2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / mach - versatile / core . c
*
* Copyright ( C ) 1999 - 2003 ARM Limited
* Copyright ( C ) 2000 Deep Blue Solutions Ltd
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/init.h>
# include <linux/device.h>
# include <linux/dma-mapping.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <linux/sysdev.h>
# include <linux/interrupt.h>
2006-01-07 13:52:45 +00:00
# include <linux/amba/bus.h>
# include <linux/amba/clcd.h>
2009-07-05 22:43:01 +01:00
# include <linux/amba/pl061.h>
2009-09-22 14:29:36 +01:00
# include <linux/amba/mmci.h>
2007-03-08 20:25:13 +01:00
# include <linux/clocksource.h>
2007-03-08 20:30:38 +01:00
# include <linux/clockchips.h>
2008-09-24 17:48:26 +01:00
# include <linux/cnt32_to_63.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
2008-11-08 20:13:53 +00:00
# include <asm/clkdev.h>
2005-04-16 15:20:36 -07:00
# include <asm/system.h>
# include <asm/irq.h>
# include <asm/leds.h>
2005-06-29 15:15:54 +01:00
# include <asm/hardware/arm_timer.h>
2010-01-16 20:16:10 +00:00
# include <asm/hardware/icst.h>
2006-01-13 21:30:48 +00:00
# include <asm/hardware/vic.h>
2006-07-10 16:33:54 +01:00
# include <asm/mach-types.h>
2005-04-16 15:20:36 -07:00
# include <asm/mach/arch.h>
# include <asm/mach/flash.h>
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
# include <asm/mach/map.h>
2010-01-14 19:59:37 +00:00
# include <mach/hardware.h>
# include <mach/platform.h>
2005-04-16 15:20:36 -07:00
# include "core.h"
# include "clock.h"
/*
* All IO addresses are mapped onto VA 0xFFF x . xxxx , where x . xxxx
* is the ( PA > > 12 ) .
*
* Setup a VA for the Versatile Vectored Interrupt Controller .
*/
2005-09-29 00:09:02 +01:00
# define VA_VIC_BASE __io_address(VERSATILE_VIC_BASE)
# define VA_SIC_BASE __io_address(VERSATILE_SIC_BASE)
2005-04-16 15:20:36 -07:00
static void sic_mask_irq ( unsigned int irq )
{
irq - = IRQ_SIC_START ;
writel ( 1 < < irq , VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR ) ;
}
static void sic_unmask_irq ( unsigned int irq )
{
irq - = IRQ_SIC_START ;
writel ( 1 < < irq , VA_SIC_BASE + SIC_IRQ_ENABLE_SET ) ;
}
2006-08-01 22:26:25 +01:00
static struct irq_chip sic_chip = {
. name = " SIC " ,
2005-04-16 15:20:36 -07:00
. ack = sic_mask_irq ,
. mask = sic_mask_irq ,
. unmask = sic_unmask_irq ,
} ;
static void
2006-11-23 11:41:32 +00:00
sic_handle_irq ( unsigned int irq , struct irq_desc * desc )
2005-04-16 15:20:36 -07:00
{
unsigned long status = readl ( VA_SIC_BASE + SIC_IRQ_STATUS ) ;
if ( status = = 0 ) {
2006-10-06 10:53:39 -07:00
do_bad_IRQ ( irq , desc ) ;
2005-04-16 15:20:36 -07:00
return ;
}
do {
irq = ffs ( status ) - 1 ;
status & = ~ ( 1 < < irq ) ;
irq + = IRQ_SIC_START ;
2008-10-09 13:36:24 +01:00
generic_handle_irq ( irq ) ;
2005-04-16 15:20:36 -07:00
} while ( status ) ;
}
# if 1
# define IRQ_MMCI0A IRQ_VICSOURCE22
# define IRQ_AACI IRQ_VICSOURCE24
# define IRQ_ETH IRQ_VICSOURCE25
# define PIC_MASK 0xFFD00000
# else
# define IRQ_MMCI0A IRQ_SIC_MMCI0A
# define IRQ_AACI IRQ_SIC_AACI
# define IRQ_ETH IRQ_SIC_ETH
# define PIC_MASK 0
# endif
void __init versatile_init_irq ( void )
{
2006-01-13 21:30:48 +00:00
unsigned int i ;
2005-04-16 15:20:36 -07:00
2009-03-24 15:30:07 +00:00
vic_init ( VA_VIC_BASE , IRQ_VIC_START , ~ 0 , 0 ) ;
2005-04-16 15:20:36 -07:00
2006-06-10 12:42:12 +01:00
set_irq_chained_handler ( IRQ_VICSOURCE31 , sic_handle_irq ) ;
2005-04-16 15:20:36 -07:00
/* Do second interrupt controller */
writel ( ~ 0 , VA_SIC_BASE + SIC_IRQ_ENABLE_CLEAR ) ;
for ( i = IRQ_SIC_START ; i < = IRQ_SIC_END ; i + + ) {
if ( ( PIC_MASK & ( 1 < < ( i - IRQ_SIC_START ) ) ) = = 0 ) {
set_irq_chip ( i , & sic_chip ) ;
2006-11-23 11:41:32 +00:00
set_irq_handler ( i , handle_level_irq ) ;
2005-04-16 15:20:36 -07:00
set_irq_flags ( i , IRQF_VALID | IRQF_PROBE ) ;
}
}
/*
* Interrupts on secondary controller from 0 to 8 are routed to
* source 31 on PIC .
* Interrupts from 21 to 31 are routed directly to the VIC on
* the corresponding number on primary controller . This is controlled
* by setting PIC_ENABLEx .
*/
writel ( PIC_MASK , VA_SIC_BASE + SIC_INT_PIC_ENABLE ) ;
}
static struct map_desc versatile_io_desc [ ] __initdata = {
2005-10-28 15:19:06 +01:00
{
. virtual = IO_ADDRESS ( VERSATILE_SYS_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_SYS_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( VERSATILE_SIC_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_SIC_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( VERSATILE_VIC_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_VIC_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( VERSATILE_SCTL_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_SCTL_BASE ) ,
. length = SZ_4K * 9 ,
. type = MT_DEVICE
} ,
2005-04-16 15:20:36 -07:00
# ifdef CONFIG_MACH_VERSATILE_AB
2005-10-28 15:19:06 +01:00
{
. virtual = IO_ADDRESS ( VERSATILE_GPIO0_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_GPIO0_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( VERSATILE_IB2_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_IB2_BASE ) ,
. length = SZ_64M ,
. type = MT_DEVICE
} ,
2005-04-16 15:20:36 -07:00
# endif
# ifdef CONFIG_DEBUG_LL
2005-10-28 15:19:06 +01:00
{
. virtual = IO_ADDRESS ( VERSATILE_UART0_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_UART0_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} ,
2005-04-16 15:20:36 -07:00
# endif
2005-06-20 18:51:06 +01:00
# ifdef CONFIG_PCI
2005-10-28 15:19:06 +01:00
{
. virtual = IO_ADDRESS ( VERSATILE_PCI_CORE_BASE ) ,
. pfn = __phys_to_pfn ( VERSATILE_PCI_CORE_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
2006-10-11 17:22:34 +01:00
. virtual = ( unsigned long ) VERSATILE_PCI_VIRT_BASE ,
2005-10-28 15:19:06 +01:00
. pfn = __phys_to_pfn ( VERSATILE_PCI_BASE ) ,
. length = VERSATILE_PCI_BASE_SIZE ,
. type = MT_DEVICE
} , {
2006-10-11 17:22:34 +01:00
. virtual = ( unsigned long ) VERSATILE_PCI_CFG_VIRT_BASE ,
2005-10-28 15:19:06 +01:00
. pfn = __phys_to_pfn ( VERSATILE_PCI_CFG_BASE ) ,
. length = VERSATILE_PCI_CFG_BASE_SIZE ,
. type = MT_DEVICE
} ,
2005-06-20 18:51:06 +01:00
#if 0
2005-10-28 15:19:06 +01:00
{
. virtual = VERSATILE_PCI_VIRT_MEM_BASE0 ,
. pfn = __phys_to_pfn ( VERSATILE_PCI_MEM_BASE0 ) ,
. length = SZ_16M ,
. type = MT_DEVICE
} , {
. virtual = VERSATILE_PCI_VIRT_MEM_BASE1 ,
. pfn = __phys_to_pfn ( VERSATILE_PCI_MEM_BASE1 ) ,
. length = SZ_16M ,
. type = MT_DEVICE
} , {
. virtual = VERSATILE_PCI_VIRT_MEM_BASE2 ,
. pfn = __phys_to_pfn ( VERSATILE_PCI_MEM_BASE2 ) ,
. length = SZ_16M ,
. type = MT_DEVICE
} ,
2005-06-20 18:51:06 +01:00
# endif
2005-04-16 15:20:36 -07:00
# endif
} ;
void __init versatile_map_io ( void )
{
iotable_init ( versatile_io_desc , ARRAY_SIZE ( versatile_io_desc ) ) ;
}
2005-09-29 00:09:02 +01:00
# define VERSATILE_REFCOUNTER (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_24MHz_OFFSET)
2005-04-16 15:20:36 -07:00
/*
* This is the Versatile sched_clock implementation . This has
2006-12-04 20:29:21 +01:00
* a resolution of 41.7 ns , and a maximum value of about 35583 days .
*
* The return value is guaranteed to be monotonic in that range as
* long as there is always less than 89 seconds between successive
* calls to this function .
2005-04-16 15:20:36 -07:00
*/
unsigned long long sched_clock ( void )
{
2006-12-04 20:29:21 +01:00
unsigned long long v = cnt32_to_63 ( readl ( VERSATILE_REFCOUNTER ) ) ;
2005-04-16 15:20:36 -07:00
2006-12-04 20:29:21 +01:00
/* the <<1 gets rid of the cnt_32_to_63 top bit saving on a bic insn */
v * = 125 < < 1 ;
do_div ( v , 3 < < 1 ) ;
2005-04-16 15:20:36 -07:00
return v ;
}
2005-09-29 00:09:02 +01:00
# define VERSATILE_FLASHCTRL (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_FLASH_OFFSET)
2005-04-16 15:20:36 -07:00
static int versatile_flash_init ( void )
{
u32 val ;
val = __raw_readl ( VERSATILE_FLASHCTRL ) ;
val & = ~ VERSATILE_FLASHPROG_FLVPPEN ;
__raw_writel ( val , VERSATILE_FLASHCTRL ) ;
return 0 ;
}
static void versatile_flash_exit ( void )
{
u32 val ;
val = __raw_readl ( VERSATILE_FLASHCTRL ) ;
val & = ~ VERSATILE_FLASHPROG_FLVPPEN ;
__raw_writel ( val , VERSATILE_FLASHCTRL ) ;
}
static void versatile_flash_set_vpp ( int on )
{
u32 val ;
val = __raw_readl ( VERSATILE_FLASHCTRL ) ;
if ( on )
val | = VERSATILE_FLASHPROG_FLVPPEN ;
else
val & = ~ VERSATILE_FLASHPROG_FLVPPEN ;
__raw_writel ( val , VERSATILE_FLASHCTRL ) ;
}
static struct flash_platform_data versatile_flash_data = {
. map_name = " cfi_probe " ,
. width = 4 ,
. init = versatile_flash_init ,
. exit = versatile_flash_exit ,
. set_vpp = versatile_flash_set_vpp ,
} ;
static struct resource versatile_flash_resource = {
. start = VERSATILE_FLASH_BASE ,
2006-08-13 14:17:12 +01:00
. end = VERSATILE_FLASH_BASE + VERSATILE_FLASH_SIZE - 1 ,
2005-04-16 15:20:36 -07:00
. flags = IORESOURCE_MEM ,
} ;
static struct platform_device versatile_flash_device = {
. name = " armflash " ,
. id = 0 ,
. dev = {
. platform_data = & versatile_flash_data ,
} ,
. num_resources = 1 ,
. resource = & versatile_flash_resource ,
} ;
static struct resource smc91x_resources [ ] = {
[ 0 ] = {
. start = VERSATILE_ETH_BASE ,
. end = VERSATILE_ETH_BASE + SZ_64K - 1 ,
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = IRQ_ETH ,
. end = IRQ_ETH ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct platform_device smc91x_device = {
. name = " smc91x " ,
. id = 0 ,
. num_resources = ARRAY_SIZE ( smc91x_resources ) ,
. resource = smc91x_resources ,
} ;
2006-12-10 21:21:32 +01:00
static struct resource versatile_i2c_resource = {
. start = VERSATILE_I2C_BASE ,
. end = VERSATILE_I2C_BASE + SZ_4K - 1 ,
. flags = IORESOURCE_MEM ,
} ;
static struct platform_device versatile_i2c_device = {
. name = " versatile-i2c " ,
2009-02-12 15:58:20 +01:00
. id = 0 ,
2006-12-10 21:21:32 +01:00
. num_resources = 1 ,
. resource = & versatile_i2c_resource ,
} ;
2009-02-12 15:58:20 +01:00
static struct i2c_board_info versatile_i2c_board_info [ ] = {
{
2009-07-18 15:51:55 +01:00
I2C_BOARD_INFO ( " ds1338 " , 0xd0 > > 1 ) ,
2009-02-12 15:58:20 +01:00
} ,
} ;
static int __init versatile_i2c_init ( void )
{
return i2c_register_board_info ( 0 , versatile_i2c_board_info ,
ARRAY_SIZE ( versatile_i2c_board_info ) ) ;
}
arch_initcall ( versatile_i2c_init ) ;
2005-09-29 00:09:02 +01:00
# define VERSATILE_SYSMCI (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_MCI_OFFSET)
2005-04-16 15:20:36 -07:00
unsigned int mmc_status ( struct device * dev )
{
struct amba_device * adev = container_of ( dev , struct amba_device , dev ) ;
u32 mask ;
if ( adev - > res . start = = VERSATILE_MMCI0_BASE )
mask = 1 ;
else
mask = 2 ;
return readl ( VERSATILE_SYSMCI ) & mask ;
}
2009-09-22 14:29:36 +01:00
static struct mmci_platform_data mmc0_plat_data = {
2005-04-16 15:20:36 -07:00
. ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34 ,
. status = mmc_status ,
2009-07-09 15:15:12 +01:00
. gpio_wp = - 1 ,
. gpio_cd = - 1 ,
2005-04-16 15:20:36 -07:00
} ;
/*
* Clock handling
*/
2010-01-16 16:27:28 +00:00
static const struct icst_params versatile_oscvco_params = {
2010-01-16 17:28:44 +00:00
. ref = 24000000 ,
2010-01-16 18:08:47 +00:00
. vco_max = ICST307_VCO_MAX ,
2010-01-16 19:49:39 +00:00
. vco_min = ICST307_VCO_MIN ,
2005-04-16 15:20:36 -07:00
. vd_min = 4 + 8 ,
. vd_max = 511 + 8 ,
. rd_min = 1 + 2 ,
. rd_max = 127 + 2 ,
2010-01-16 19:46:19 +00:00
. s2div = icst307_s2div ,
. idx2s = icst307_idx2s ,
2005-04-16 15:20:36 -07:00
} ;
2010-01-16 16:27:28 +00:00
static void versatile_oscvco_set ( struct clk * clk , struct icst_vco vco )
2005-04-16 15:20:36 -07:00
{
2008-11-08 20:13:53 +00:00
void __iomem * sys = __io_address ( VERSATILE_SYS_BASE ) ;
void __iomem * sys_lock = sys + VERSATILE_SYS_LOCK_OFFSET ;
2005-04-16 15:20:36 -07:00
u32 val ;
2008-11-08 20:13:53 +00:00
val = readl ( sys + clk - > oscoff ) & ~ 0x7ffff ;
2005-04-16 15:20:36 -07:00
val | = vco . v | ( vco . r < < 9 ) | ( vco . s < < 16 ) ;
writel ( 0xa05f , sys_lock ) ;
2008-11-08 20:13:53 +00:00
writel ( val , sys + clk - > oscoff ) ;
2005-04-16 15:20:36 -07:00
writel ( 0 , sys_lock ) ;
}
2008-11-08 20:13:53 +00:00
static struct clk osc4_clk = {
2005-04-16 15:20:36 -07:00
. params = & versatile_oscvco_params ,
2008-11-08 20:13:53 +00:00
. oscoff = VERSATILE_SYS_OSCCLCD_OFFSET ,
. setvco = versatile_oscvco_set ,
} ;
/*
* These are fixed clocks .
*/
static struct clk ref24_clk = {
. rate = 24000000 ,
} ;
2009-05-18 17:29:30 +01:00
static struct clk_lookup lookups [ ] = {
2008-11-08 20:13:53 +00:00
{ /* UART0 */
. dev_id = " dev:f1 " ,
. clk = & ref24_clk ,
} , { /* UART1 */
. dev_id = " dev:f2 " ,
. clk = & ref24_clk ,
} , { /* UART2 */
. dev_id = " dev:f3 " ,
. clk = & ref24_clk ,
} , { /* UART3 */
. dev_id = " fpga:09 " ,
. clk = & ref24_clk ,
} , { /* KMI0 */
. dev_id = " fpga:06 " ,
. clk = & ref24_clk ,
} , { /* KMI1 */
. dev_id = " fpga:07 " ,
. clk = & ref24_clk ,
} , { /* MMC0 */
. dev_id = " fpga:05 " ,
. clk = & ref24_clk ,
} , { /* MMC1 */
. dev_id = " fpga:0b " ,
. clk = & ref24_clk ,
} , { /* CLCD */
. dev_id = " dev:20 " ,
. clk = & osc4_clk ,
}
2005-04-16 15:20:36 -07:00
} ;
/*
* CLCD support .
*/
# define SYS_CLCD_MODE_MASK (3 << 0)
# define SYS_CLCD_MODE_888 (0 << 0)
# define SYS_CLCD_MODE_5551 (1 << 0)
# define SYS_CLCD_MODE_565_RLSB (2 << 0)
# define SYS_CLCD_MODE_565_BLSB (3 << 0)
# define SYS_CLCD_NLCDIOON (1 << 2)
# define SYS_CLCD_VDDPOSSWITCH (1 << 3)
# define SYS_CLCD_PWR3V5SWITCH (1 << 4)
# define SYS_CLCD_ID_MASK (0x1f << 8)
# define SYS_CLCD_ID_SANYO_3_8 (0x00 << 8)
# define SYS_CLCD_ID_UNKNOWN_8_4 (0x01 << 8)
# define SYS_CLCD_ID_EPSON_2_2 (0x02 << 8)
# define SYS_CLCD_ID_SANYO_2_5 (0x07 << 8)
# define SYS_CLCD_ID_VGA (0x1f << 8)
static struct clcd_panel vga = {
. mode = {
. name = " VGA " ,
. refresh = 60 ,
. xres = 640 ,
. yres = 480 ,
. pixclock = 39721 ,
. left_margin = 40 ,
. right_margin = 24 ,
. upper_margin = 32 ,
. lower_margin = 11 ,
. hsync_len = 96 ,
. vsync_len = 2 ,
. sync = 0 ,
. vmode = FB_VMODE_NONINTERLACED ,
} ,
. width = - 1 ,
. height = - 1 ,
. tim2 = TIM2_BCD | TIM2_IPC ,
. cntl = CNTL_LCDTFT | CNTL_LCDVCOMP ( 1 ) ,
. bpp = 16 ,
} ;
static struct clcd_panel sanyo_3_8_in = {
. mode = {
. name = " Sanyo QVGA " ,
. refresh = 116 ,
. xres = 320 ,
. yres = 240 ,
. pixclock = 100000 ,
. left_margin = 6 ,
. right_margin = 6 ,
. upper_margin = 5 ,
. lower_margin = 5 ,
. hsync_len = 6 ,
. vsync_len = 6 ,
. sync = 0 ,
. vmode = FB_VMODE_NONINTERLACED ,
} ,
. width = - 1 ,
. height = - 1 ,
. tim2 = TIM2_BCD ,
. cntl = CNTL_LCDTFT | CNTL_LCDVCOMP ( 1 ) ,
. bpp = 16 ,
} ;
static struct clcd_panel sanyo_2_5_in = {
. mode = {
. name = " Sanyo QVGA Portrait " ,
. refresh = 116 ,
. xres = 240 ,
. yres = 320 ,
. pixclock = 100000 ,
. left_margin = 20 ,
. right_margin = 10 ,
. upper_margin = 2 ,
. lower_margin = 2 ,
. hsync_len = 10 ,
. vsync_len = 2 ,
. sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT ,
. vmode = FB_VMODE_NONINTERLACED ,
} ,
. width = - 1 ,
. height = - 1 ,
. tim2 = TIM2_IVS | TIM2_IHS | TIM2_IPC ,
. cntl = CNTL_LCDTFT | CNTL_LCDVCOMP ( 1 ) ,
. bpp = 16 ,
} ;
static struct clcd_panel epson_2_2_in = {
. mode = {
. name = " Epson QCIF " ,
. refresh = 390 ,
. xres = 176 ,
. yres = 220 ,
. pixclock = 62500 ,
. left_margin = 3 ,
. right_margin = 2 ,
. upper_margin = 1 ,
. lower_margin = 0 ,
. hsync_len = 3 ,
. vsync_len = 2 ,
. sync = 0 ,
. vmode = FB_VMODE_NONINTERLACED ,
} ,
. width = - 1 ,
. height = - 1 ,
. tim2 = TIM2_BCD | TIM2_IPC ,
. cntl = CNTL_LCDTFT | CNTL_LCDVCOMP ( 1 ) ,
. bpp = 16 ,
} ;
/*
* Detect which LCD panel is connected , and return the appropriate
* clcd_panel structure . Note : we do not have any information on
* the required timings for the 8.4 in panel , so we presently assume
* VGA timings .
*/
static struct clcd_panel * versatile_clcd_panel ( void )
{
2005-09-29 00:09:02 +01:00
void __iomem * sys_clcd = __io_address ( VERSATILE_SYS_BASE ) + VERSATILE_SYS_CLCD_OFFSET ;
2005-04-16 15:20:36 -07:00
struct clcd_panel * panel = & vga ;
u32 val ;
val = readl ( sys_clcd ) & SYS_CLCD_ID_MASK ;
if ( val = = SYS_CLCD_ID_SANYO_3_8 )
panel = & sanyo_3_8_in ;
else if ( val = = SYS_CLCD_ID_SANYO_2_5 )
panel = & sanyo_2_5_in ;
else if ( val = = SYS_CLCD_ID_EPSON_2_2 )
panel = & epson_2_2_in ;
else if ( val = = SYS_CLCD_ID_VGA )
panel = & vga ;
else {
printk ( KERN_ERR " CLCD: unknown LCD panel ID 0x%08x, using VGA \n " ,
val ) ;
panel = & vga ;
}
return panel ;
}
/*
* Disable all display connectors on the interface module .
*/
static void versatile_clcd_disable ( struct clcd_fb * fb )
{
2005-09-29 00:09:02 +01:00
void __iomem * sys_clcd = __io_address ( VERSATILE_SYS_BASE ) + VERSATILE_SYS_CLCD_OFFSET ;
2005-04-16 15:20:36 -07:00
u32 val ;
val = readl ( sys_clcd ) ;
val & = ~ SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH ;
writel ( val , sys_clcd ) ;
# ifdef CONFIG_MACH_VERSATILE_AB
/*
* If the LCD is Sanyo 2 x5 in on the IB2 board , turn the back - light off
*/
2006-07-10 16:33:54 +01:00
if ( machine_is_versatile_ab ( ) & & fb - > panel = = & sanyo_2_5_in ) {
2005-09-29 00:09:02 +01:00
void __iomem * versatile_ib2_ctrl = __io_address ( VERSATILE_IB2_CTRL ) ;
2005-04-16 15:20:36 -07:00
unsigned long ctrl ;
ctrl = readl ( versatile_ib2_ctrl ) ;
ctrl & = ~ 0x01 ;
writel ( ctrl , versatile_ib2_ctrl ) ;
}
# endif
}
/*
* Enable the relevant connector on the interface module .
*/
static void versatile_clcd_enable ( struct clcd_fb * fb )
{
2005-09-29 00:09:02 +01:00
void __iomem * sys_clcd = __io_address ( VERSATILE_SYS_BASE ) + VERSATILE_SYS_CLCD_OFFSET ;
2005-04-16 15:20:36 -07:00
u32 val ;
val = readl ( sys_clcd ) ;
val & = ~ SYS_CLCD_MODE_MASK ;
switch ( fb - > fb . var . green . length ) {
case 5 :
val | = SYS_CLCD_MODE_5551 ;
break ;
case 6 :
2005-06-16 18:01:11 +01:00
val | = SYS_CLCD_MODE_565_RLSB ;
2005-04-16 15:20:36 -07:00
break ;
case 8 :
val | = SYS_CLCD_MODE_888 ;
break ;
}
/*
* Set the MUX
*/
writel ( val , sys_clcd ) ;
/*
* And now enable the PSUs
*/
val | = SYS_CLCD_NLCDIOON | SYS_CLCD_PWR3V5SWITCH ;
writel ( val , sys_clcd ) ;
# ifdef CONFIG_MACH_VERSATILE_AB
/*
* If the LCD is Sanyo 2 x5 in on the IB2 board , turn the back - light on
*/
2006-07-10 16:33:54 +01:00
if ( machine_is_versatile_ab ( ) & & fb - > panel = = & sanyo_2_5_in ) {
2005-09-29 00:09:02 +01:00
void __iomem * versatile_ib2_ctrl = __io_address ( VERSATILE_IB2_CTRL ) ;
2005-04-16 15:20:36 -07:00
unsigned long ctrl ;
ctrl = readl ( versatile_ib2_ctrl ) ;
ctrl | = 0x01 ;
writel ( ctrl , versatile_ib2_ctrl ) ;
}
# endif
}
static unsigned long framesize = SZ_1M ;
static int versatile_clcd_setup ( struct clcd_fb * fb )
{
dma_addr_t dma ;
fb - > panel = versatile_clcd_panel ( ) ;
fb - > fb . screen_base = dma_alloc_writecombine ( & fb - > dev - > dev , framesize ,
& dma , GFP_KERNEL ) ;
if ( ! fb - > fb . screen_base ) {
printk ( KERN_ERR " CLCD: unable to map framebuffer \n " ) ;
return - ENOMEM ;
}
fb - > fb . fix . smem_start = dma ;
fb - > fb . fix . smem_len = framesize ;
return 0 ;
}
static int versatile_clcd_mmap ( struct clcd_fb * fb , struct vm_area_struct * vma )
{
return dma_mmap_writecombine ( & fb - > dev - > dev , vma ,
fb - > fb . screen_base ,
fb - > fb . fix . smem_start ,
fb - > fb . fix . smem_len ) ;
}
static void versatile_clcd_remove ( struct clcd_fb * fb )
{
dma_free_writecombine ( & fb - > dev - > dev , fb - > fb . fix . smem_len ,
fb - > fb . screen_base , fb - > fb . fix . smem_start ) ;
}
static struct clcd_board clcd_plat_data = {
. name = " Versatile " ,
. check = clcdfb_check ,
. decode = clcdfb_decode ,
. disable = versatile_clcd_disable ,
. enable = versatile_clcd_enable ,
. setup = versatile_clcd_setup ,
. mmap = versatile_clcd_mmap ,
. remove = versatile_clcd_remove ,
} ;
2009-07-05 22:43:01 +01:00
static struct pl061_platform_data gpio0_plat_data = {
. gpio_base = 0 ,
. irq_base = IRQ_GPIO0_START ,
} ;
static struct pl061_platform_data gpio1_plat_data = {
. gpio_base = 8 ,
. irq_base = IRQ_GPIO1_START ,
} ;
2005-04-16 15:20:36 -07:00
# define AACI_IRQ { IRQ_AACI, NO_IRQ }
# define AACI_DMA { 0x80, 0x81 }
# define MMCI0_IRQ { IRQ_MMCI0A,IRQ_SIC_MMCI0B }
# define MMCI0_DMA { 0x84, 0 }
# define KMI0_IRQ { IRQ_SIC_KMI0, NO_IRQ }
# define KMI0_DMA { 0, 0 }
# define KMI1_IRQ { IRQ_SIC_KMI1, NO_IRQ }
# define KMI1_DMA { 0, 0 }
/*
* These devices are connected directly to the multi - layer AHB switch
*/
# define SMC_IRQ { NO_IRQ, NO_IRQ }
# define SMC_DMA { 0, 0 }
# define MPMC_IRQ { NO_IRQ, NO_IRQ }
# define MPMC_DMA { 0, 0 }
# define CLCD_IRQ { IRQ_CLCDINT, NO_IRQ }
# define CLCD_DMA { 0, 0 }
# define DMAC_IRQ { IRQ_DMAINT, NO_IRQ }
# define DMAC_DMA { 0, 0 }
/*
* These devices are connected via the core APB bridge
*/
# define SCTL_IRQ { NO_IRQ, NO_IRQ }
# define SCTL_DMA { 0, 0 }
# define WATCHDOG_IRQ { IRQ_WDOGINT, NO_IRQ }
# define WATCHDOG_DMA { 0, 0 }
# define GPIO0_IRQ { IRQ_GPIOINT0, NO_IRQ }
# define GPIO0_DMA { 0, 0 }
# define GPIO1_IRQ { IRQ_GPIOINT1, NO_IRQ }
# define GPIO1_DMA { 0, 0 }
# define RTC_IRQ { IRQ_RTCINT, NO_IRQ }
# define RTC_DMA { 0, 0 }
/*
* These devices are connected via the DMA APB bridge
*/
# define SCI_IRQ { IRQ_SCIINT, NO_IRQ }
# define SCI_DMA { 7, 6 }
# define UART0_IRQ { IRQ_UARTINT0, NO_IRQ }
# define UART0_DMA { 15, 14 }
# define UART1_IRQ { IRQ_UARTINT1, NO_IRQ }
# define UART1_DMA { 13, 12 }
# define UART2_IRQ { IRQ_UARTINT2, NO_IRQ }
# define UART2_DMA { 11, 10 }
# define SSP_IRQ { IRQ_SSPINT, NO_IRQ }
# define SSP_DMA { 9, 8 }
/* FPGA Primecells */
AMBA_DEVICE ( aaci , " fpga:04 " , AACI , NULL ) ;
AMBA_DEVICE ( mmc0 , " fpga:05 " , MMCI0 , & mmc0_plat_data ) ;
AMBA_DEVICE ( kmi0 , " fpga:06 " , KMI0 , NULL ) ;
AMBA_DEVICE ( kmi1 , " fpga:07 " , KMI1 , NULL ) ;
/* DevChip Primecells */
AMBA_DEVICE ( smc , " dev:00 " , SMC , NULL ) ;
AMBA_DEVICE ( mpmc , " dev:10 " , MPMC , NULL ) ;
AMBA_DEVICE ( clcd , " dev:20 " , CLCD , & clcd_plat_data ) ;
AMBA_DEVICE ( dmac , " dev:30 " , DMAC , NULL ) ;
AMBA_DEVICE ( sctl , " dev:e0 " , SCTL , NULL ) ;
AMBA_DEVICE ( wdog , " dev:e1 " , WATCHDOG , NULL ) ;
2009-07-05 22:43:01 +01:00
AMBA_DEVICE ( gpio0 , " dev:e4 " , GPIO0 , & gpio0_plat_data ) ;
AMBA_DEVICE ( gpio1 , " dev:e5 " , GPIO1 , & gpio1_plat_data ) ;
2005-04-16 15:20:36 -07:00
AMBA_DEVICE ( rtc , " dev:e8 " , RTC , NULL ) ;
AMBA_DEVICE ( sci0 , " dev:f0 " , SCI , NULL ) ;
AMBA_DEVICE ( uart0 , " dev:f1 " , UART0 , NULL ) ;
AMBA_DEVICE ( uart1 , " dev:f2 " , UART1 , NULL ) ;
AMBA_DEVICE ( uart2 , " dev:f3 " , UART2 , NULL ) ;
AMBA_DEVICE ( ssp0 , " dev:f4 " , SSP , NULL ) ;
static struct amba_device * amba_devs [ ] __initdata = {
& dmac_device ,
& uart0_device ,
& uart1_device ,
& uart2_device ,
& smc_device ,
& mpmc_device ,
& clcd_device ,
& sctl_device ,
& wdog_device ,
& gpio0_device ,
& gpio1_device ,
& rtc_device ,
& sci0_device ,
& ssp0_device ,
& aaci_device ,
& mmc0_device ,
& kmi0_device ,
& kmi1_device ,
} ;
# ifdef CONFIG_LEDS
2005-09-29 00:09:02 +01:00
# define VA_LEDS_BASE (__io_address(VERSATILE_SYS_BASE) + VERSATILE_SYS_LED_OFFSET)
2005-04-16 15:20:36 -07:00
static void versatile_leds_event ( led_event_t ledevt )
{
unsigned long flags ;
u32 val ;
local_irq_save ( flags ) ;
val = readl ( VA_LEDS_BASE ) ;
switch ( ledevt ) {
case led_idle_start :
val = val & ~ VERSATILE_SYS_LED0 ;
break ;
case led_idle_end :
val = val | VERSATILE_SYS_LED0 ;
break ;
case led_timer :
val = val ^ VERSATILE_SYS_LED1 ;
break ;
case led_halted :
val = 0 ;
break ;
default :
break ;
}
writel ( val , VA_LEDS_BASE ) ;
local_irq_restore ( flags ) ;
}
# endif /* CONFIG_LEDS */
void __init versatile_init ( void )
{
int i ;
2010-01-12 12:28:00 +00:00
clkdev_add_table ( lookups , ARRAY_SIZE ( lookups ) ) ;
2005-04-16 15:20:36 -07:00
platform_device_register ( & versatile_flash_device ) ;
2006-12-10 21:21:32 +01:00
platform_device_register ( & versatile_i2c_device ) ;
2005-04-16 15:20:36 -07:00
platform_device_register ( & smc91x_device ) ;
for ( i = 0 ; i < ARRAY_SIZE ( amba_devs ) ; i + + ) {
struct amba_device * d = amba_devs [ i ] ;
amba_device_register ( d , & iomem_resource ) ;
}
# ifdef CONFIG_LEDS
leds_event = versatile_leds_event ;
# endif
}
/*
* Where is the timer ( VA ) ?
*/
2005-09-29 00:09:02 +01:00
# define TIMER0_VA_BASE __io_address(VERSATILE_TIMER0_1_BASE)
# define TIMER1_VA_BASE (__io_address(VERSATILE_TIMER0_1_BASE) + 0x20)
# define TIMER2_VA_BASE __io_address(VERSATILE_TIMER2_3_BASE)
# define TIMER3_VA_BASE (__io_address(VERSATILE_TIMER2_3_BASE) + 0x20)
# define VA_IC_BASE __io_address(VERSATILE_VIC_BASE)
2005-04-16 15:20:36 -07:00
/*
* How long is the timer interval ?
*/
# define TIMER_INTERVAL (TICKS_PER_uSEC * mSEC_10)
# if TIMER_INTERVAL >= 0x100000
2005-06-29 15:15:54 +01:00
# define TIMER_RELOAD (TIMER_INTERVAL >> 8)
# define TIMER_DIVISOR (TIMER_CTRL_DIV256)
2005-04-16 15:20:36 -07:00
# define TICKS2USECS(x) (256 * (x) / TICKS_PER_uSEC)
# elif TIMER_INTERVAL >= 0x10000
# define TIMER_RELOAD (TIMER_INTERVAL >> 4) /* Divide by 16 */
2005-06-29 15:15:54 +01:00
# define TIMER_DIVISOR (TIMER_CTRL_DIV16)
2005-04-16 15:20:36 -07:00
# define TICKS2USECS(x) (16 * (x) / TICKS_PER_uSEC)
# else
# define TIMER_RELOAD (TIMER_INTERVAL)
2005-06-29 15:15:54 +01:00
# define TIMER_DIVISOR (TIMER_CTRL_DIV1)
2005-04-16 15:20:36 -07:00
# define TICKS2USECS(x) ((x) / TICKS_PER_uSEC)
# endif
2007-03-08 20:30:38 +01:00
static void timer_set_mode ( enum clock_event_mode mode ,
struct clock_event_device * clk )
{
unsigned long ctrl ;
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
writel ( TIMER_RELOAD , TIMER0_VA_BASE + TIMER_LOAD ) ;
ctrl = TIMER_CTRL_PERIODIC ;
ctrl | = TIMER_CTRL_32BIT | TIMER_CTRL_IE | TIMER_CTRL_ENABLE ;
break ;
case CLOCK_EVT_MODE_ONESHOT :
/* period set, and timer enabled in 'next_event' hook */
ctrl = TIMER_CTRL_ONESHOT ;
ctrl | = TIMER_CTRL_32BIT | TIMER_CTRL_IE ;
break ;
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_SHUTDOWN :
default :
ctrl = 0 ;
}
writel ( ctrl , TIMER0_VA_BASE + TIMER_CTRL ) ;
}
static int timer_set_next_event ( unsigned long evt ,
struct clock_event_device * unused )
{
unsigned long ctrl = readl ( TIMER0_VA_BASE + TIMER_CTRL ) ;
writel ( evt , TIMER0_VA_BASE + TIMER_LOAD ) ;
writel ( ctrl | TIMER_CTRL_ENABLE , TIMER0_VA_BASE + TIMER_CTRL ) ;
return 0 ;
}
static struct clock_event_device timer0_clockevent = {
. name = " timer0 " ,
. shift = 32 ,
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
. set_mode = timer_set_mode ,
. set_next_event = timer_set_next_event ,
} ;
2005-04-16 15:20:36 -07:00
/*
* IRQ handler for the timer
*/
2006-10-06 10:53:39 -07:00
static irqreturn_t versatile_timer_interrupt ( int irq , void * dev_id )
2005-04-16 15:20:36 -07:00
{
2007-03-08 20:30:38 +01:00
struct clock_event_device * evt = & timer0_clockevent ;
2005-04-16 15:20:36 -07:00
2005-06-29 15:15:54 +01:00
writel ( 1 , TIMER0_VA_BASE + TIMER_INTCLR ) ;
2005-04-16 15:20:36 -07:00
2007-03-08 20:30:38 +01:00
evt - > event_handler ( evt ) ;
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}
static struct irqaction versatile_timer_irq = {
. name = " Versatile Timer Tick " ,
2007-05-08 00:35:39 -07:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2005-06-26 17:06:36 +01:00
. handler = versatile_timer_interrupt ,
2005-04-16 15:20:36 -07:00
} ;
2009-04-21 12:24:00 -07:00
static cycle_t versatile_get_cycles ( struct clocksource * cs )
2007-03-08 20:25:13 +01:00
{
return ~ readl ( TIMER3_VA_BASE + TIMER_VALUE ) ;
}
static struct clocksource clocksource_versatile = {
. name = " timer3 " ,
. rating = 200 ,
. read = versatile_get_cycles ,
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. shift = 20 ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
static int __init versatile_clocksource_init ( void )
{
/* setup timer3 as free-running clocksource */
writel ( 0 , TIMER3_VA_BASE + TIMER_CTRL ) ;
writel ( 0xffffffff , TIMER3_VA_BASE + TIMER_LOAD ) ;
writel ( 0xffffffff , TIMER3_VA_BASE + TIMER_VALUE ) ;
writel ( TIMER_CTRL_32BIT | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC ,
TIMER3_VA_BASE + TIMER_CTRL ) ;
clocksource_versatile . mult =
clocksource_khz2mult ( 1000 , clocksource_versatile . shift ) ;
clocksource_register ( & clocksource_versatile ) ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
/*
* Set up timer interrupt , and return the current time in seconds .
*/
static void __init versatile_timer_init ( void )
{
2005-06-29 15:15:54 +01:00
u32 val ;
2005-04-16 15:20:36 -07:00
/*
* set clock frequency :
* VERSATILE_REFCLK is 32 KHz
* VERSATILE_TIMCLK is 1 MHz
*/
2005-09-29 00:09:02 +01:00
val = readl ( __io_address ( VERSATILE_SCTL_BASE ) ) ;
2005-06-29 15:15:54 +01:00
writel ( ( VERSATILE_TIMCLK < < VERSATILE_TIMER1_EnSel ) |
( VERSATILE_TIMCLK < < VERSATILE_TIMER2_EnSel ) |
( VERSATILE_TIMCLK < < VERSATILE_TIMER3_EnSel ) |
( VERSATILE_TIMCLK < < VERSATILE_TIMER4_EnSel ) | val ,
2005-09-29 00:09:02 +01:00
__io_address ( VERSATILE_SCTL_BASE ) ) ;
2005-04-16 15:20:36 -07:00
/*
* Initialise to a known state ( all timers off )
*/
2005-06-29 15:15:54 +01:00
writel ( 0 , TIMER0_VA_BASE + TIMER_CTRL ) ;
writel ( 0 , TIMER1_VA_BASE + TIMER_CTRL ) ;
writel ( 0 , TIMER2_VA_BASE + TIMER_CTRL ) ;
writel ( 0 , TIMER3_VA_BASE + TIMER_CTRL ) ;
2005-04-16 15:20:36 -07:00
/*
* Make irqs happen for the system timer
*/
setup_irq ( IRQ_TIMERINT0_1 , & versatile_timer_irq ) ;
2007-03-08 20:25:13 +01:00
versatile_clocksource_init ( ) ;
2007-03-08 20:30:38 +01:00
timer0_clockevent . mult =
div_sc ( 1000000 , NSEC_PER_SEC , timer0_clockevent . shift ) ;
timer0_clockevent . max_delta_ns =
clockevent_delta2ns ( 0xffffffff , & timer0_clockevent ) ;
timer0_clockevent . min_delta_ns =
clockevent_delta2ns ( 0xf , & timer0_clockevent ) ;
2008-12-13 21:20:26 +10:30
timer0_clockevent . cpumask = cpumask_of ( 0 ) ;
2007-03-08 20:30:38 +01:00
clockevents_register_device ( & timer0_clockevent ) ;
2005-04-16 15:20:36 -07:00
}
struct sys_timer versatile_timer = {
. init = versatile_timer_init ,
} ;
2007-03-08 20:25:13 +01:00