2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - integrator / integrator_ap . c
*
* Copyright ( C ) 2000 - 2003 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/types.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/list.h>
2005-10-29 22:07:23 +04:00
# include <linux/platform_device.h>
2005-04-17 02:20:36 +04:00
# include <linux/slab.h>
# include <linux/string.h>
2011-04-23 00:02:55 +04:00
# include <linux/syscore_ops.h>
2006-01-07 16:52:45 +03:00
# include <linux/amba/bus.h>
# include <linux/amba/kmi.h>
2010-01-17 19:20:56 +03:00
# include <linux/clocksource.h>
# include <linux/clockchips.h>
# include <linux/interrupt.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2011-05-18 13:51:52 +04:00
# include <linux/mtd/physmap.h>
2011-09-09 00:23:15 +04:00
# include <linux/clk.h>
2011-09-05 01:40:08 +04:00
# include <video/vga.h>
2005-04-17 02:20:36 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2010-01-14 22:59:37 +03:00
# include <mach/platform.h>
2010-01-17 19:20:56 +03:00
# include <asm/hardware/arm_timer.h>
2005-04-17 02:20:36 +04:00
# include <asm/setup.h>
2005-10-31 02:03:48 +03:00
# include <asm/param.h> /* HZ */
2005-04-17 02:20:36 +04:00
# include <asm/mach-types.h>
2012-02-01 02:38:23 +04:00
# include <asm/sched_clock.h>
2005-04-17 02:20:36 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/lm.h>
2012-02-26 13:46:48 +04:00
# include <mach/irqs.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
# include <asm/mach/time.h>
2011-01-19 18:32:15 +03:00
# include <plat/fpga-irq.h>
2010-05-22 21:18:57 +04:00
# include "common.h"
2005-04-17 02:20:36 +04:00
/*
* All IO addresses are mapped onto VA 0xFFF x . xxxx , where x . xxxx
* is the ( PA > > 12 ) .
*
* Setup a VA for the Integrator interrupt controller ( for header # 0 ,
* just for now ) .
*/
2011-01-19 18:32:15 +03:00
# define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE)
# define VA_SC_BASE __io_address(INTEGRATOR_SC_BASE)
# define VA_EBI_BASE __io_address(INTEGRATOR_EBI_BASE)
# define VA_CMIC_BASE __io_address(INTEGRATOR_HDR_IC)
2005-04-17 02:20:36 +04:00
/*
* Logical Physical
* e8000000 40000000 PCI memory PHYS_PCI_MEM_BASE ( max 512 M )
* ec000000 61000000 PCI config space PHYS_PCI_CONFIG_BASE ( max 16 M )
* ed000000 62000000 PCI V3 regs PHYS_PCI_V3_BASE ( max 64 k )
* ee000000 60000000 PCI IO PHYS_PCI_IO_BASE ( max 16 M )
* ef000000 Cache flush
* f1000000 10000000 Core module registers
* f1100000 11000000 System controller registers
* f1200000 12000000 EBI registers
* f1300000 13000000 Counter / Timer
* f1400000 14000000 Interrupt controller
* f1600000 16000000 UART 0
* f1700000 17000000 UART 1
* f1a00000 1 a000000 Debug LEDs
* f1b00000 1 b000000 GPIO
*/
static struct map_desc ap_io_desc [ ] __initdata = {
2005-10-28 18:19:10 +04:00
{
. virtual = IO_ADDRESS ( INTEGRATOR_HDR_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_HDR_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_SC_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_SC_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_EBI_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_EBI_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_CT_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_CT_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_IC_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_IC_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_UART0_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_UART0_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_UART1_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_UART1_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_DBG_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_DBG_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
2010-01-17 22:59:58 +03:00
. virtual = IO_ADDRESS ( INTEGRATOR_AP_GPIO_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_AP_GPIO_BASE ) ,
2005-10-28 18:19:10 +04:00
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = PCI_MEMORY_VADDR ,
. pfn = __phys_to_pfn ( PHYS_PCI_MEM_BASE ) ,
. length = SZ_16M ,
. type = MT_DEVICE
} , {
. virtual = PCI_CONFIG_VADDR ,
. pfn = __phys_to_pfn ( PHYS_PCI_CONFIG_BASE ) ,
. length = SZ_16M ,
. type = MT_DEVICE
} , {
. virtual = PCI_V3_VADDR ,
. pfn = __phys_to_pfn ( PHYS_PCI_V3_BASE ) ,
. length = SZ_64K ,
. type = MT_DEVICE
} , {
. virtual = PCI_IO_VADDR ,
. pfn = __phys_to_pfn ( PHYS_PCI_IO_BASE ) ,
. length = SZ_64K ,
. type = MT_DEVICE
}
2005-04-17 02:20:36 +04:00
} ;
static void __init ap_map_io ( void )
{
iotable_init ( ap_io_desc , ARRAY_SIZE ( ap_io_desc ) ) ;
2011-09-05 01:40:08 +04:00
vga_base = PCI_MEMORY_VADDR ;
2005-04-17 02:20:36 +04:00
}
# define INTEGRATOR_SC_VALID_INT 0x003fffff
2011-01-19 18:32:15 +03:00
static struct fpga_irq_data sc_irq_data = {
. base = VA_IC_BASE ,
. irq_start = 0 ,
. chip . name = " SC " ,
2005-04-17 02:20:36 +04:00
} ;
static void __init ap_init_irq ( void )
{
/* Disable all interrupts initially. */
/* Do the core module ones */
writel ( - 1 , VA_CMIC_BASE + IRQ_ENABLE_CLEAR ) ;
/* do the header card stuff next */
writel ( - 1 , VA_IC_BASE + IRQ_ENABLE_CLEAR ) ;
writel ( - 1 , VA_IC_BASE + FIQ_ENABLE_CLEAR ) ;
2011-01-19 18:32:15 +03:00
fpga_irq_init ( - 1 , INTEGRATOR_SC_VALID_INT , & sc_irq_data ) ;
2005-04-17 02:20:36 +04:00
}
# ifdef CONFIG_PM
static unsigned long ic_irq_enable ;
2011-04-23 00:02:55 +04:00
static int irq_suspend ( void )
2005-04-17 02:20:36 +04:00
{
ic_irq_enable = readl ( VA_IC_BASE + IRQ_ENABLE ) ;
return 0 ;
}
2011-04-23 00:02:55 +04:00
static void irq_resume ( void )
2005-04-17 02:20:36 +04:00
{
/* disable all irq sources */
writel ( - 1 , VA_CMIC_BASE + IRQ_ENABLE_CLEAR ) ;
writel ( - 1 , VA_IC_BASE + IRQ_ENABLE_CLEAR ) ;
writel ( - 1 , VA_IC_BASE + FIQ_ENABLE_CLEAR ) ;
writel ( ic_irq_enable , VA_IC_BASE + IRQ_ENABLE_SET ) ;
}
# else
# define irq_suspend NULL
# define irq_resume NULL
# endif
2011-04-23 00:02:55 +04:00
static struct syscore_ops irq_syscore_ops = {
2005-04-17 02:20:36 +04:00
. suspend = irq_suspend ,
. resume = irq_resume ,
} ;
2011-04-23 00:02:55 +04:00
static int __init irq_syscore_init ( void )
2005-04-17 02:20:36 +04:00
{
2011-04-23 00:02:55 +04:00
register_syscore_ops ( & irq_syscore_ops ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
}
2011-04-23 00:02:55 +04:00
device_initcall ( irq_syscore_init ) ;
2005-04-17 02:20:36 +04:00
/*
* Flash handling .
*/
# define SC_CTRLC (VA_SC_BASE + INTEGRATOR_SC_CTRLC_OFFSET)
# define SC_CTRLS (VA_SC_BASE + INTEGRATOR_SC_CTRLS_OFFSET)
# define EBI_CSR1 (VA_EBI_BASE + INTEGRATOR_EBI_CSR1_OFFSET)
# define EBI_LOCK (VA_EBI_BASE + INTEGRATOR_EBI_LOCK_OFFSET)
2011-05-18 13:51:52 +04:00
static int ap_flash_init ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
u32 tmp ;
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP , SC_CTRLC ) ;
tmp = readl ( EBI_CSR1 ) | INTEGRATOR_EBI_WRITE_ENABLE ;
writel ( tmp , EBI_CSR1 ) ;
if ( ! ( readl ( EBI_CSR1 ) & INTEGRATOR_EBI_WRITE_ENABLE ) ) {
writel ( 0xa05f , EBI_LOCK ) ;
writel ( tmp , EBI_CSR1 ) ;
writel ( 0 , EBI_LOCK ) ;
}
return 0 ;
}
2011-05-18 13:51:52 +04:00
static void ap_flash_exit ( struct platform_device * dev )
2005-04-17 02:20:36 +04:00
{
u32 tmp ;
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP , SC_CTRLC ) ;
tmp = readl ( EBI_CSR1 ) & ~ INTEGRATOR_EBI_WRITE_ENABLE ;
writel ( tmp , EBI_CSR1 ) ;
if ( readl ( EBI_CSR1 ) & INTEGRATOR_EBI_WRITE_ENABLE ) {
writel ( 0xa05f , EBI_LOCK ) ;
writel ( tmp , EBI_CSR1 ) ;
writel ( 0 , EBI_LOCK ) ;
}
}
2011-05-18 13:51:55 +04:00
static void ap_flash_set_vpp ( struct platform_device * pdev , int on )
2005-04-17 02:20:36 +04:00
{
2011-01-19 18:32:15 +03:00
void __iomem * reg = on ? SC_CTRLS : SC_CTRLC ;
2005-04-17 02:20:36 +04:00
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN , reg ) ;
}
2011-05-18 13:51:52 +04:00
static struct physmap_flash_data ap_flash_data = {
2005-04-17 02:20:36 +04:00
. width = 4 ,
. init = ap_flash_init ,
. exit = ap_flash_exit ,
. set_vpp = ap_flash_set_vpp ,
} ;
static struct resource cfi_flash_resource = {
. start = INTEGRATOR_FLASH_BASE ,
. end = INTEGRATOR_FLASH_BASE + INTEGRATOR_FLASH_SIZE - 1 ,
. flags = IORESOURCE_MEM ,
} ;
static struct platform_device cfi_flash_device = {
2011-05-18 13:51:52 +04:00
. name = " physmap-flash " ,
2005-04-17 02:20:36 +04:00
. id = 0 ,
. dev = {
. platform_data = & ap_flash_data ,
} ,
. num_resources = 1 ,
. resource = & cfi_flash_resource ,
} ;
static void __init ap_init ( void )
{
unsigned long sc_dec ;
int i ;
platform_device_register ( & cfi_flash_device ) ;
sc_dec = readl ( VA_SC_BASE + INTEGRATOR_SC_DEC_OFFSET ) ;
for ( i = 0 ; i < 4 ; i + + ) {
struct lm_device * lmdev ;
if ( ( sc_dec & ( 16 < < i ) ) = = 0 )
continue ;
2006-03-20 22:46:41 +03:00
lmdev = kzalloc ( sizeof ( struct lm_device ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! lmdev )
continue ;
lmdev - > resource . start = 0xc0000000 + 0x10000000 * i ;
lmdev - > resource . end = lmdev - > resource . start + 0x0fffffff ;
lmdev - > resource . flags = IORESOURCE_MEM ;
lmdev - > irq = IRQ_AP_EXPINT0 + i ;
lmdev - > id = i ;
lm_device_register ( lmdev ) ;
}
}
2010-01-17 19:20:56 +03:00
/*
* Where is the timer ( VA ) ?
*/
# define TIMER0_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER0_BASE)
# define TIMER1_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER1_BASE)
# define TIMER2_VA_BASE IO_ADDRESS(INTEGRATOR_TIMER2_BASE)
static unsigned long timer_reload ;
2012-02-01 02:38:23 +04:00
static u32 notrace integrator_read_sched_clock ( void )
{
return - readl ( ( void __iomem * ) TIMER2_VA_BASE + TIMER_VALUE ) ;
}
2011-09-09 00:23:15 +04:00
static void integrator_clocksource_init ( unsigned long inrate )
2010-01-17 19:20:56 +03:00
{
2011-05-08 18:35:22 +04:00
void __iomem * base = ( void __iomem * ) TIMER2_VA_BASE ;
2011-09-06 11:08:13 +04:00
u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC ;
2011-09-09 00:23:15 +04:00
unsigned long rate = inrate ;
2010-01-17 19:20:56 +03:00
2011-09-09 00:23:15 +04:00
if ( rate > = 1500000 ) {
rate / = 16 ;
2011-09-06 11:08:13 +04:00
ctrl | = TIMER_CTRL_DIV16 ;
2010-01-17 19:20:56 +03:00
}
writel ( 0xffff , base + TIMER_LOAD ) ;
2011-09-06 11:08:13 +04:00
writel ( ctrl , base + TIMER_CTRL ) ;
2010-01-17 19:20:56 +03:00
2011-05-08 18:35:22 +04:00
clocksource_mmio_init ( base + TIMER_VALUE , " timer2 " ,
2011-09-09 00:23:15 +04:00
rate , 200 , 16 , clocksource_mmio_readl_down ) ;
2012-02-01 02:38:23 +04:00
setup_sched_clock ( integrator_read_sched_clock , 16 , rate ) ;
2010-01-17 19:20:56 +03:00
}
static void __iomem * const clkevt_base = ( void __iomem * ) TIMER1_VA_BASE ;
/*
* IRQ handler for the timer
*/
static irqreturn_t integrator_timer_interrupt ( int irq , void * dev_id )
{
struct clock_event_device * evt = dev_id ;
/* clear the interrupt */
writel ( 1 , clkevt_base + TIMER_INTCLR ) ;
evt - > event_handler ( evt ) ;
return IRQ_HANDLED ;
}
static void clkevt_set_mode ( enum clock_event_mode mode , struct clock_event_device * evt )
{
u32 ctrl = readl ( clkevt_base + TIMER_CTRL ) & ~ TIMER_CTRL_ENABLE ;
2011-09-09 00:21:42 +04:00
/* Disable timer */
writel ( ctrl , clkevt_base + TIMER_CTRL ) ;
2010-01-17 19:20:56 +03:00
2011-09-09 00:21:42 +04:00
switch ( mode ) {
case CLOCK_EVT_MODE_PERIODIC :
/* Enable the timer and start the periodic tick */
2010-01-17 19:20:56 +03:00
writel ( timer_reload , clkevt_base + TIMER_LOAD ) ;
ctrl | = TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE ;
2011-09-09 00:21:42 +04:00
writel ( ctrl , clkevt_base + TIMER_CTRL ) ;
break ;
case CLOCK_EVT_MODE_ONESHOT :
/* Leave the timer disabled, .set_next_event will enable it */
ctrl & = ~ TIMER_CTRL_PERIODIC ;
writel ( ctrl , clkevt_base + TIMER_CTRL ) ;
break ;
case CLOCK_EVT_MODE_UNUSED :
case CLOCK_EVT_MODE_SHUTDOWN :
case CLOCK_EVT_MODE_RESUME :
default :
/* Just leave in disabled state */
break ;
2010-01-17 19:20:56 +03:00
}
}
static int clkevt_set_next_event ( unsigned long next , struct clock_event_device * evt )
{
unsigned long ctrl = readl ( clkevt_base + TIMER_CTRL ) ;
writel ( ctrl & ~ TIMER_CTRL_ENABLE , clkevt_base + TIMER_CTRL ) ;
writel ( next , clkevt_base + TIMER_LOAD ) ;
writel ( ctrl | TIMER_CTRL_ENABLE , clkevt_base + TIMER_CTRL ) ;
return 0 ;
}
static struct clock_event_device integrator_clockevent = {
. name = " timer1 " ,
2011-09-09 00:21:42 +04:00
. features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT ,
2010-01-17 19:20:56 +03:00
. set_mode = clkevt_set_mode ,
. set_next_event = clkevt_set_next_event ,
. rating = 300 ,
} ;
static struct irqaction integrator_timer_irq = {
. name = " timer " ,
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
. handler = integrator_timer_interrupt ,
. dev_id = & integrator_clockevent ,
} ;
2011-09-09 00:23:15 +04:00
static void integrator_clockevent_init ( unsigned long inrate )
2010-01-17 19:20:56 +03:00
{
2011-09-09 00:23:15 +04:00
unsigned long rate = inrate ;
2010-01-17 19:20:56 +03:00
unsigned int ctrl = 0 ;
2011-09-09 00:22:32 +04:00
/* Calculate and program a divisor */
2011-09-09 00:23:15 +04:00
if ( rate > 0x100000 * HZ ) {
rate / = 256 ;
2010-01-17 19:20:56 +03:00
ctrl | = TIMER_CTRL_DIV256 ;
2011-09-09 00:23:15 +04:00
} else if ( rate > 0x10000 * HZ ) {
rate / = 16 ;
2010-01-17 19:20:56 +03:00
ctrl | = TIMER_CTRL_DIV16 ;
}
2011-09-09 00:23:15 +04:00
timer_reload = rate / HZ ;
2010-01-17 19:20:56 +03:00
writel ( ctrl , clkevt_base + TIMER_CTRL ) ;
setup_irq ( IRQ_TIMERINT1 , & integrator_timer_irq ) ;
2011-09-09 00:22:32 +04:00
clockevents_config_and_register ( & integrator_clockevent ,
2011-09-09 00:23:15 +04:00
rate ,
2011-09-09 00:22:32 +04:00
1 ,
0xffffU ) ;
2010-01-17 19:20:56 +03:00
}
/*
* Set up timer ( s ) .
*/
2005-04-17 02:20:36 +04:00
static void __init ap_init_timer ( void )
{
2011-09-09 00:23:15 +04:00
struct clk * clk ;
unsigned long rate ;
clk = clk_get_sys ( " ap_timer " , NULL ) ;
BUG_ON ( IS_ERR ( clk ) ) ;
clk_enable ( clk ) ;
rate = clk_get_rate ( clk ) ;
2010-01-17 19:20:56 +03:00
writel ( 0 , TIMER0_VA_BASE + TIMER_CTRL ) ;
writel ( 0 , TIMER1_VA_BASE + TIMER_CTRL ) ;
writel ( 0 , TIMER2_VA_BASE + TIMER_CTRL ) ;
2011-09-09 00:23:15 +04:00
integrator_clocksource_init ( rate ) ;
integrator_clockevent_init ( rate ) ;
2005-04-17 02:20:36 +04:00
}
static struct sys_timer ap_timer = {
. init = ap_init_timer ,
} ;
MACHINE_START ( INTEGRATOR , " ARM-Integrator " )
2005-07-03 20:38:58 +04:00
/* Maintainer: ARM Ltd/Deep Blue Solutions Ltd */
2011-07-06 06:38:12 +04:00
. atag_offset = 0x100 ,
2010-05-22 21:18:57 +04:00
. reserve = integrator_reserve ,
2011-01-11 16:00:04 +03:00
. map_io = ap_map_io ,
2012-02-26 13:46:48 +04:00
. nr_irqs = NR_IRQS_INTEGRATOR_AP ,
2011-01-11 16:00:04 +03:00
. init_early = integrator_init_early ,
2005-07-03 20:38:58 +04:00
. init_irq = ap_init_irq ,
2005-04-17 02:20:36 +04:00
. timer = & ap_timer ,
2005-07-03 20:38:58 +04:00
. init_machine = ap_init ,
2011-11-03 23:54:37 +04:00
. restart = integrator_restart ,
2005-04-17 02:20:36 +04:00
MACHINE_END