diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-02-04 15:29:53 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-02-04 15:29:53 -0800 |
commit | 9ef9dc69d4167276c04590d67ee55de8380bc1ad (patch) | |
tree | f0afd03cd9184eda2fe14c41f09daec79a62682e /arch/arm/mach-realview | |
parent | 2c8296f8cf0ec40867965dddef3dfe92f73b38f4 (diff) | |
parent | 0d899e1b0000ddf78a75d7dcf9a9029d6f7f8091 (diff) |
Merge branch 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm
* 'for-linus' of master.kernel.org:/home/rmk/linux-2.6-arm: (44 commits)
[ARM] 4822/1: RealView: Change the REALVIEW_MPCORE configuration option
[ARM] 4821/1: RealView: Remove the platform dependencies from localtimer.c
[ARM] 4820/1: RealView: Select the timer IRQ at run-time
[ARM] 4819/1: RealView: Fix entry-macro.S to work with multiple platforms
[ARM] 4818/1: RealView: Add core-tile detection
[ARM] 4817/1: RealView: Move the AMBA resource definitions to realview_eb.c
[ARM] 4816/1: RealView: Move the platform-specific definitions into board-eb.h
[ARM] 4815/1: RealView: Add clockevents suport for the local timers
[ARM] 4814/1: RealView: Add broadcasting clockevents support for ARM11MPCore
[ARM] 4813/1: Add SMP helper functions for clockevents support
[ARM] 4812/1: RealView: clockevents support for the RealView platforms
[ARM] 4811/1: RealView: clocksource support for the RealView platforms
[ARM] 4736/1: Export atags to userspace and allow kexec to use customised atags
[ARM] 4798/1: pcm027: fix missing header file
[ARM] 4803/1: pxa: fix building issue of poodle.c caused by patch 4737/1
[ARM] 4801/1: pxa: fix building issues of missing pxa2xx-regs.h
[ARM] pxa: introduce sysdev for pxa3xx static memory controller
[ARM] pxa: add preliminary suspend/resume code for pxa3xx
[ARM] pxa: introduce sysdev for GPIO register saving/restoring
[ARM] pxa: introduce sysdev for IRQ register saving/restoring
...
Diffstat (limited to 'arch/arm/mach-realview')
-rw-r--r-- | arch/arm/mach-realview/Kconfig | 21 | ||||
-rw-r--r-- | arch/arm/mach-realview/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/mach-realview/core.c | 179 | ||||
-rw-r--r-- | arch/arm/mach-realview/core.h | 71 | ||||
-rw-r--r-- | arch/arm/mach-realview/localtimer.c | 144 | ||||
-rw-r--r-- | arch/arm/mach-realview/platsmp.c | 20 | ||||
-rw-r--r-- | arch/arm/mach-realview/realview_eb.c | 234 |
7 files changed, 442 insertions, 230 deletions
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig index 35156ca39df..39b3bb7f102 100644 --- a/arch/arm/mach-realview/Kconfig +++ b/arch/arm/mach-realview/Kconfig @@ -7,24 +7,21 @@ config MACH_REALVIEW_EB help Include support for the ARM(R) RealView Emulation Baseboard platform. -config REALVIEW_MPCORE - bool "Support MPcore tile" +config REALVIEW_EB_ARM11MP + bool "Support ARM11MPCore tile" depends on MACH_REALVIEW_EB select CACHE_L2X0 help - Enable support for the MPCore tile on the Realview platform. - Since there are device address and interrupt differences, a - kernel built with this option enabled is not compatible with - other tiles. + Enable support for the ARM11MPCore tile on the Realview platform. -config REALVIEW_MPCORE_REVB - bool "Support MPcore RevB tile" - depends on REALVIEW_MPCORE +config REALVIEW_EB_ARM11MP_REVB + bool "Support ARM11MPCore RevB tile" + depends on REALVIEW_EB_ARM11MP default n help - Enable support for the MPCore RevB tile on the Realview platform. - Since there are device address differences, a + Enable support for the ARM11MPCore RevB tile on the Realview + platform. Since there are device address differences, a kernel built with this option enabled is not compatible with - other tiles. + other revisions of the ARM11MPCore tile. endmenu diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile index 36e76ba937f..ca1e390c3c2 100644 --- a/arch/arm/mach-realview/Makefile +++ b/arch/arm/mach-realview/Makefile @@ -4,6 +4,5 @@ obj-y := core.o clock.o obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o -obj-$(CONFIG_SMP) += platsmp.o headsmp.o +obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o -obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o diff --git a/arch/arm/mach-realview/core.c b/arch/arm/mach-realview/core.c index 61d70218f1e..98aefc9f4df 100644 --- a/arch/arm/mach-realview/core.c +++ b/arch/arm/mach-realview/core.c @@ -25,6 +25,8 @@ #include <linux/interrupt.h> #include <linux/amba/bus.h> #include <linux/amba/clcd.h> +#include <linux/clocksource.h> +#include <linux/clockchips.h> #include <asm/system.h> #include <asm/hardware.h> @@ -37,7 +39,6 @@ #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> #include <asm/mach/mmc.h> @@ -48,6 +49,9 @@ #define REALVIEW_REFCOUNTER (__io_address(REALVIEW_SYS_BASE) + REALVIEW_SYS_24MHz_OFFSET) +/* used by entry-macro.S */ +void __iomem *gic_cpu_base_addr; + /* * This is the RealView sched_clock implementation. This has * a resolution of 41.7ns, and a maximum value of about 179s. @@ -121,26 +125,6 @@ struct platform_device realview_flash_device = { .resource = &realview_flash_resource, }; -static struct resource realview_smc91x_resources[] = { - [0] = { - .start = REALVIEW_ETH_BASE, - .end = REALVIEW_ETH_BASE + SZ_64K - 1, - .flags = IORESOURCE_MEM, - }, - [1] = { - .start = IRQ_ETH, - .end = IRQ_ETH, - .flags = IORESOURCE_IRQ, - }, -}; - -struct platform_device realview_smc91x_device = { - .name = "smc91x", - .id = 0, - .num_resources = ARRAY_SIZE(realview_smc91x_resources), - .resource = realview_smc91x_resources, -}; - static struct resource realview_i2c_resource = { .start = REALVIEW_I2C_BASE, .end = REALVIEW_I2C_BASE + SZ_4K - 1, @@ -484,45 +468,64 @@ void realview_leds_event(led_event_t ledevt) #define TICKS2USECS(x) ((x) / TICKS_PER_uSEC) #endif -/* - * Returns number of ms since last clock interrupt. Note that interrupts - * will have been disabled by do_gettimeoffset() - */ -static unsigned long realview_gettimeoffset(void) +static void timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) { - unsigned long ticks1, ticks2, status; + unsigned long ctrl; - /* - * Get the current number of ticks. Note that there is a race - * condition between us reading the timer and checking for - * an interrupt. We get around this by ensuring that the - * counter has not reloaded between our two reads. - */ - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - do { - ticks1 = ticks2; - status = __raw_readl(__io_address(REALVIEW_GIC_DIST_BASE + GIC_DIST_PENDING_SET) - + ((IRQ_TIMERINT0_1 >> 5) << 2)); - ticks2 = readl(TIMER0_VA_BASE + TIMER_VALUE) & 0xffff; - } while (ticks2 > ticks1); + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - /* - * Number of ticks since last interrupt. - */ - ticks1 = TIMER_RELOAD - ticks2; + 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; + } - /* - * Interrupt pending? If so, we've reloaded once already. - * - * FIXME: Need to check this is effectively timer 0 that expires - */ - if (status & IRQMASK_TIMERINT0_1) - ticks1 += TIMER_RELOAD; + writel(ctrl, TIMER0_VA_BASE + TIMER_CTRL); +} - /* - * Convert the ticks to usecs - */ - return TICKS2USECS(ticks1); +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, + .rating = 300, + .cpumask = CPU_MASK_ALL, +}; + +static void __init realview_clockevents_init(unsigned int timer_irq) +{ + timer0_clockevent.irq = timer_irq; + 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); + + clockevents_register_device(&timer0_clockevent); } /* @@ -530,15 +533,12 @@ static unsigned long realview_gettimeoffset(void) */ static irqreturn_t realview_timer_interrupt(int irq, void *dev_id) { - // ...clear the interrupt + struct clock_event_device *evt = &timer0_clockevent; + + /* clear the interrupt */ writel(1, TIMER0_VA_BASE + TIMER_INTCLR); - timer_tick(); - -#if defined(CONFIG_SMP) && !defined(CONFIG_LOCAL_TIMERS) - smp_send_timer(); - update_process_times(user_mode(get_irq_regs())); -#endif + evt->event_handler(evt); return IRQ_HANDLED; } @@ -549,13 +549,49 @@ static struct irqaction realview_timer_irq = { .handler = realview_timer_interrupt, }; +static cycle_t realview_get_cycles(void) +{ + return ~readl(TIMER3_VA_BASE + TIMER_VALUE); +} + +static struct clocksource clocksource_realview = { + .name = "timer3", + .rating = 200, + .read = realview_get_cycles, + .mask = CLOCKSOURCE_MASK(32), + .shift = 20, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void __init realview_clocksource_init(void) +{ + /* setup timer 0 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_realview.mult = + clocksource_khz2mult(1000, clocksource_realview.shift); + clocksource_register(&clocksource_realview); +} + /* - * Set up timer interrupt, and return the current time in seconds. + * Set up the clock source and clock events devices */ -static void __init realview_timer_init(void) +void __init realview_timer_init(unsigned int timer_irq) { u32 val; +#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST + /* + * The dummy clock device has to be registered before the main device + * so that the latter will broadcast the clock events + */ + local_timer_setup(smp_processor_id()); +#endif + /* * set clock frequency: * REALVIEW_REFCLK is 32KHz @@ -576,18 +612,11 @@ static void __init realview_timer_init(void) writel(0, TIMER2_VA_BASE + TIMER_CTRL); writel(0, TIMER3_VA_BASE + TIMER_CTRL); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_LOAD); - writel(TIMER_RELOAD, TIMER0_VA_BASE + TIMER_VALUE); - writel(TIMER_DIVISOR | TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC | - TIMER_CTRL_IE, TIMER0_VA_BASE + TIMER_CTRL); - /* * Make irqs happen for the system timer */ - setup_irq(IRQ_TIMERINT0_1, &realview_timer_irq); -} + setup_irq(timer_irq, &realview_timer_irq); -struct sys_timer realview_timer = { - .init = realview_timer_init, - .offset = realview_gettimeoffset, -}; + realview_clocksource_init(); + realview_clockevents_init(timer_irq); +} diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h index 2b53420f9c1..492a14c0d60 100644 --- a/arch/arm/mach-realview/core.h +++ b/arch/arm/mach-realview/core.h @@ -27,8 +27,6 @@ #include <asm/leds.h> #include <asm/io.h> -extern struct sys_timer realview_timer; - #define AMBA_DEVICE(name,busid,base,plat) \ static struct amba_device name##_device = { \ .dev = { \ @@ -38,7 +36,7 @@ static struct amba_device name##_device = { \ }, \ .res = { \ .start = REALVIEW_##base##_BASE, \ - .end = (REALVIEW_##base##_BASE) + SZ_4K - 1,\ + .end = (REALVIEW_##base##_BASE) + SZ_4K - 1, \ .flags = IORESOURCE_MEM, \ }, \ .dma_mask = ~0, \ @@ -46,74 +44,19 @@ static struct amba_device name##_device = { \ /* .dma = base##_DMA,*/ \ } -/* - * These devices are connected via the core APB bridge - */ -#define GPIO2_IRQ { IRQ_GPIOINT2, NO_IRQ } -#define GPIO2_DMA { 0, 0 } -#define GPIO3_IRQ { IRQ_GPIOINT3, NO_IRQ } -#define GPIO3_DMA { 0, 0 } - -#define AACI_IRQ { IRQ_AACI, NO_IRQ } -#define AACI_DMA { 0x80, 0x81 } -#define MMCI0_IRQ { IRQ_MMCI0A,IRQ_MMCI0B } -#define MMCI0_DMA { 0x84, 0 } -#define KMI0_IRQ { IRQ_KMI0, NO_IRQ } -#define KMI0_DMA { 0, 0 } -#define KMI1_IRQ { IRQ_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 UART3_IRQ { IRQ_UART3, NO_IRQ } -#define UART3_DMA { 0x86, 0x87 } -#define SSP_IRQ { IRQ_SSPINT, NO_IRQ } -#define SSP_DMA { 9, 8 } - - extern struct platform_device realview_flash_device; -extern struct platform_device realview_smc91x_device; extern struct platform_device realview_i2c_device; extern struct mmc_platform_data realview_mmc0_plat_data; extern struct mmc_platform_data realview_mmc1_plat_data; extern struct clk realview_clcd_clk; extern struct clcd_board clcd_plat_data; +extern void __iomem *gic_cpu_base_addr; +#ifdef CONFIG_LOCAL_TIMERS +extern void __iomem *twd_base_addr; +extern unsigned int twd_size; +#endif extern void realview_leds_event(led_event_t ledevt); +extern void realview_timer_init(unsigned int timer_irq); #endif diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c index c7bdf04ab09..50604360479 100644 --- a/arch/arm/mach-realview/localtimer.c +++ b/arch/arm/mach-realview/localtimer.c @@ -14,19 +14,75 @@ #include <linux/device.h> #include <linux/smp.h> #include <linux/jiffies.h> +#include <linux/percpu.h> +#include <linux/clockchips.h> +#include <linux/irq.h> -#include <asm/mach/time.h> #include <asm/hardware/arm_twd.h> #include <asm/hardware/gic.h> #include <asm/hardware.h> #include <asm/io.h> #include <asm/irq.h> -#define TWD_BASE(cpu) (__io_address(REALVIEW_TWD_BASE) + \ - ((cpu) * REALVIEW_TWD_SIZE)) +static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); + +/* + * Used on SMP for either the local timer or IPI_TIMER + */ +void local_timer_interrupt(void) +{ + struct clock_event_device *clk = &__get_cpu_var(local_clockevent); + + clk->event_handler(clk); +} + +#ifdef CONFIG_LOCAL_TIMERS + +#define TWD_BASE(cpu) (twd_base_addr + (cpu) * twd_size) + +/* set up by the platform code */ +void __iomem *twd_base_addr; +unsigned int twd_size; static unsigned long mpcore_timer_rate; +static void local_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ + void __iomem *base = TWD_BASE(smp_processor_id()); + unsigned long ctrl; + + switch(mode) { + case CLOCK_EVT_MODE_PERIODIC: + /* timer load already set up */ + ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE + | TWD_TIMER_CONTROL_PERIODIC; + break; + case CLOCK_EVT_MODE_ONESHOT: + /* period set, and timer enabled in 'next_event' hook */ + ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT; + break; + case CLOCK_EVT_MODE_UNUSED: + case CLOCK_EVT_MODE_SHUTDOWN: + default: + ctrl = 0; + } + + __raw_writel(ctrl, base + TWD_TIMER_CONTROL); +} + +static int local_timer_set_next_event(unsigned long evt, + struct clock_event_device *unused) +{ + void __iomem *base = TWD_BASE(smp_processor_id()); + unsigned long ctrl = __raw_readl(base + TWD_TIMER_CONTROL); + + __raw_writel(evt, base + TWD_TIMER_COUNTER); + __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, base + TWD_TIMER_CONTROL); + + return 0; +} + /* * local_timer_ack: checks for a local timer interrupt. * @@ -45,12 +101,11 @@ int local_timer_ack(void) return 0; } -void __cpuinit local_timer_setup(unsigned int cpu) +static void __cpuinit twd_calibrate_rate(unsigned int cpu) { void __iomem *base = TWD_BASE(cpu); - unsigned int load, offset; + unsigned long load, count; u64 waitjiffies; - unsigned int count; /* * If this is the first time round, we need to work out how fast @@ -88,36 +143,36 @@ void __cpuinit local_timer_setup(unsigned int cpu) load = mpcore_timer_rate / HZ; __raw_writel(load, base + TWD_TIMER_LOAD); - __raw_writel(0x7, base + TWD_TIMER_CONTROL); - - /* - * Now maneuver our local tick into the right part of the jiffy. - * Start by working out where within the tick our local timer - * interrupt should go. - */ - offset = ((mpcore_timer_rate / HZ) / (NR_CPUS + 1)) * (cpu + 1); - - /* - * gettimeoffset() will return a number of us since the last tick. - * Convert this number of us to a local timer tick count. - * Be careful of integer overflow whilst keeping maximum precision. - * - * with HZ=100 and 1MHz (fpga) ~ 1GHz processor: - * load = 1 ~ 10,000 - * mpcore_timer_rate/10000 = 100 ~ 100,000 - * - * so the multiply value will be less than 10^9 always. - */ - load = (system_timer->offset() * (mpcore_timer_rate / 10000)) / 100; - - /* Add on our offset to get the load value */ - load = (load + offset) % (mpcore_timer_rate / HZ); +} - __raw_writel(load, base + TWD_TIMER_COUNTER); +/* + * Setup the local clock events for a CPU. + */ +void __cpuinit local_timer_setup(unsigned int cpu) +{ + struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); + unsigned long flags; + + twd_calibrate_rate(cpu); + + clk->name = "local_timer"; + clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; + clk->rating = 350; + clk->set_mode = local_timer_set_mode; + clk->set_next_event = local_timer_set_next_event; + clk->irq = IRQ_LOCALTIMER; + clk->cpumask = cpumask_of_cpu(cpu); + clk->shift = 20; + clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift); + clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk); + clk->min_delta_ns = clockevent_delta2ns(0xf, clk); /* Make sure our local interrupt controller has this enabled */ - __raw_writel(1 << IRQ_LOCALTIMER, - __io_address(REALVIEW_GIC_DIST_BASE) + GIC_DIST_ENABLE_SET); + local_irq_save(flags); + get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER); + local_irq_restore(flags); + + clockevents_register_device(clk); } /* @@ -127,3 +182,26 @@ void __cpuexit local_timer_stop(unsigned int cpu) { __raw_writel(0, TWD_BASE(cpu) + TWD_TIMER_CONTROL); } + +#else /* CONFIG_LOCAL_TIMERS */ + +static void dummy_timer_set_mode(enum clock_event_mode mode, + struct clock_event_device *clk) +{ +} + +void __cpuinit local_timer_setup(unsigned int cpu) +{ + struct clock_event_device *clk = &per_cpu(local_clockevent, cpu); + + clk->name = "dummy_timer"; + clk->features = CLOCK_EVT_FEAT_DUMMY; + clk->rating = 200; + clk->set_mode = dummy_timer_set_mode; + clk->broadcast = smp_timer_broadcast; + clk->cpumask = cpumask_of_cpu(cpu); + + clockevents_register_device(clk); +} + +#endif /* !CONFIG_LOCAL_TIMERS */ diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c index fce3596f995..de2b7159557 100644 --- a/arch/arm/mach-realview/platsmp.c +++ b/arch/arm/mach-realview/platsmp.c @@ -18,6 +18,7 @@ #include <asm/hardware/arm_scu.h> #include <asm/hardware.h> #include <asm/io.h> +#include <asm/mach-types.h> extern void realview_secondary_startup(void); @@ -31,9 +32,13 @@ static unsigned int __init get_core_count(void) { unsigned int ncores; - ncores = __raw_readl(__io_address(REALVIEW_MPCORE_SCU_BASE) + SCU_CONFIG); + if (machine_is_realview_eb() && core_tile_eb11mp()) { + ncores = __raw_readl(__io_address(REALVIEW_EB11MP_SCU_BASE) + SCU_CONFIG); + ncores = (ncores & 0x03) + 1; + } else + ncores = 1; - return (ncores & 0x03) + 1; + return ncores; } static DEFINE_SPINLOCK(boot_lock); @@ -52,7 +57,7 @@ void __cpuinit platform_secondary_init(unsigned int cpu) * core (e.g. timer irq), then they will not have been enabled * for us: do so */ - gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); + gic_cpu_init(0, __io_address(REALVIEW_EB11MP_GIC_CPU_BASE)); /* * let the primary processor know we're out of the @@ -187,10 +192,15 @@ void __init smp_prepare_cpus(unsigned int max_cpus) if (max_cpus > ncores) max_cpus = ncores; +#ifdef CONFIG_LOCAL_TIMERS /* - * Enable the local timer for primary CPU + * Enable the local timer for primary CPU. If the device is + * dummy (!CONFIG_LOCAL_TIMERS), it was already registers in + * realview_timer_init */ - local_timer_setup(cpu); + if (machine_is_realview_eb() && core_tile_eb11mp()) + local_timer_setup(cpu); +#endif /* * Initialise the present map, which describes the set of CPUs diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c index ecec2f85c4c..60d9eb81024 100644 --- a/arch/arm/mach-realview/realview_eb.c +++ b/arch/arm/mach-realview/realview_eb.c @@ -36,7 +36,9 @@ #include <asm/mach/arch.h> #include <asm/mach/map.h> #include <asm/mach/mmc.h> +#include <asm/mach/time.h> +#include <asm/arch/board-eb.h> #include <asm/arch/irqs.h> #include "core.h" @@ -58,26 +60,7 @@ static struct map_desc realview_eb_io_desc[] __initdata = { .pfn = __phys_to_pfn(REALVIEW_GIC_DIST_BASE), .length = SZ_4K, .type = MT_DEVICE, - }, -#ifdef CONFIG_REALVIEW_MPCORE - { - .virtual = IO_ADDRESS(REALVIEW_GIC1_CPU_BASE), - .pfn = __phys_to_pfn(REALVIEW_GIC1_CPU_BASE), - .length = SZ_4K, - .type = MT_DEVICE, }, { - .virtual = IO_ADDRESS(REALVIEW_GIC1_DIST_BASE), - .pfn = __phys_to_pfn(REALVIEW_GIC1_DIST_BASE), - .length = SZ_4K, - .type = MT_DEVICE, - }, { - .virtual = IO_ADDRESS(REALVIEW_MPCORE_L220_BASE), - .pfn = __phys_to_pfn(REALVIEW_MPCORE_L220_BASE), - .length = SZ_8K, - .type = MT_DEVICE, - }, -#endif - { .virtual = IO_ADDRESS(REALVIEW_SCTL_BASE), .pfn = __phys_to_pfn(REALVIEW_SCTL_BASE), .length = SZ_4K, @@ -103,11 +86,95 @@ static struct map_desc realview_eb_io_desc[] __initdata = { #endif }; +static struct map_desc realview_eb11mp_io_desc[] __initdata = { + { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_CPU_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_CPU_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_GIC_DIST_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_GIC_DIST_BASE), + .length = SZ_4K, + .type = MT_DEVICE, + }, { + .virtual = IO_ADDRESS(REALVIEW_EB11MP_L220_BASE), + .pfn = __phys_to_pfn(REALVIEW_EB11MP_L220_BASE), + .length = SZ_8K, + .type = MT_DEVICE, + } +}; + static void __init realview_eb_map_io(void) { iotable_init(realview_eb_io_desc, ARRAY_SIZE(realview_eb_io_desc)); + if (core_tile_eb11mp()) + iotable_init(realview_eb11mp_io_desc, ARRAY_SIZE(realview_eb11mp_io_desc)); } +/* + * RealView EB AMBA devices + */ + +/* + * These devices are connected via the core APB bridge + */ +#define GPIO2_IRQ { IRQ_EB_GPIO2, NO_IRQ } +#define GPIO2_DMA { 0, 0 } +#define GPIO3_IRQ { IRQ_EB_GPIO3, NO_IRQ } +#define GPIO3_DMA { 0, 0 } + +#define AACI_IRQ { IRQ_EB_AACI, NO_IRQ } +#define AACI_DMA { 0x80, 0x81 } +#define MMCI0_IRQ { IRQ_EB_MMCI0A, IRQ_EB_MMCI0B } +#define MMCI0_DMA { 0x84, 0 } +#define KMI0_IRQ { IRQ_EB_KMI0, NO_IRQ } +#define KMI0_DMA { 0, 0 } +#define KMI1_IRQ { IRQ_EB_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_EB_CLCD, NO_IRQ } +#define CLCD_DMA { 0, 0 } +#define DMAC_IRQ { IRQ_EB_DMA, 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_EB_WDOG, NO_IRQ } +#define WATCHDOG_DMA { 0, 0 } +#define GPIO0_IRQ { IRQ_EB_GPIO0, NO_IRQ } +#define GPIO0_DMA { 0, 0 } +#define GPIO1_IRQ { IRQ_EB_GPIO1, NO_IRQ } +#define GPIO1_DMA { 0, 0 } +#define RTC_IRQ { IRQ_EB_RTC, NO_IRQ } +#define RTC_DMA { 0, 0 } + +/* + * These devices are connected via the DMA APB bridge + */ +#define SCI_IRQ { IRQ_EB_SCI, NO_IRQ } +#define SCI_DMA { 7, 6 } +#define UART0_IRQ { IRQ_EB_UART0, NO_IRQ } +#define UART0_DMA { 15, 14 } +#define UART1_IRQ { IRQ_EB_UART1, NO_IRQ } +#define UART1_DMA { 13, 12 } +#define UART2_IRQ { IRQ_EB_UART2, NO_IRQ } +#define UART2_DMA { 11, 10 } +#define UART3_IRQ { IRQ_EB_UART3, NO_IRQ } +#define UART3_DMA { 0x86, 0x87 } +#define SSP_IRQ { IRQ_EB_SSP, NO_IRQ } +#define SSP_DMA { 9, 8 } + /* FPGA Primecells */ AMBA_DEVICE(aaci, "fpga:04", AACI, NULL); AMBA_DEVICE(mmc0, "fpga:05", MMCI0, &realview_mmc0_plat_data); @@ -153,38 +220,127 @@ static struct amba_device *amba_devs[] __initdata = { &kmi1_device, }; +/* + * RealView EB platform devices + */ + +static struct resource realview_eb_smc91x_resources[] = { + [0] = { + .start = REALVIEW_ETH_BASE, + .end = REALVIEW_ETH_BASE + SZ_64K - 1, + .flags = IORESOURCE_MEM, + }, + [1] = { + .start = IRQ_EB_ETH, + .end = IRQ_EB_ETH, + .flags = IORESOURCE_IRQ, + }, +}; + +static struct platform_device realview_eb_smc91x_device = { + .name = "smc91x", + .id = 0, + .num_resources = ARRAY_SIZE(realview_eb_smc91x_resources), + .resource = realview_eb_smc91x_resources, +}; + static void __init gic_init_irq(void) { -#ifdef CONFIG_REALVIEW_MPCORE - unsigned int pldctrl; - writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); - pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); - pldctrl |= 0x00800000; /* New irq mode */ - writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_MPCORE_SYS_PLD_CTRL1); - writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); + if (core_tile_eb11mp()) { + unsigned int pldctrl; + + /* new irq mode */ + writel(0x0000a05f, __io_address(REALVIEW_SYS_LOCK)); + pldctrl = readl(__io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1); + pldctrl |= 0x00800000; + writel(pldctrl, __io_address(REALVIEW_SYS_BASE) + REALVIEW_EB11MP_SYS_PLD_CTRL1); + writel(0x00000000, __io_address(REALVIEW_SYS_LOCK)); + + /* core tile GIC, primary */ + gic_cpu_base_addr = __io_address(REALVIEW_EB11MP_GIC_CPU_BASE); + gic_dist_init(0, __io_address(REALVIEW_EB11MP_GIC_DIST_BASE), 29); + gic_cpu_init(0, gic_cpu_base_addr); + +#ifndef CONFIG_REALVIEW_EB_ARM11MP_REVB + /* board GIC, secondary */ + gic_dist_init(1, __io_address(REALVIEW_GIC_DIST_BASE), 64); + gic_cpu_init(1, __io_address(REALVIEW_GIC_CPU_BASE)); + gic_cascade_irq(1, IRQ_EB11MP_EB_IRQ1); #endif - gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29); - gic_cpu_init(0, __io_address(REALVIEW_GIC_CPU_BASE)); -#if defined(CONFIG_REALVIEW_MPCORE) && !defined(CONFIG_REALVIEW_MPCORE_REVB) - gic_dist_init(1, __io_address(REALVIEW_GIC1_DIST_BASE), 64); - gic_cpu_init(1, __io_address(REALVIEW_GIC1_CPU_BASE)); - gic_cascade_irq(1, IRQ_EB_IRQ1); + } else { + /* board GIC, primary */ + gic_cpu_base_addr = __io_address(REALVIEW_GIC_CPU_BASE); + gic_dist_init(0, __io_address(REALVIEW_GIC_DIST_BASE), 29); + gic_cpu_init(0, gic_cpu_base_addr); + } +} + +/* + * Fix up the IRQ numbers for the RealView EB/ARM11MPCore tile + */ +static void realview_eb11mp_fixup(void) +{ + /* AMBA devices */ + dmac_device.irq[0] = IRQ_EB11MP_DMA; + uart0_device.irq[0] = IRQ_EB11MP_UART0; + uart1_device.irq[0] = IRQ_EB11MP_UART1; + uart2_device.irq[0] = IRQ_EB11MP_UART2; + uart3_device.irq[0] = IRQ_EB11MP_UART3; + clcd_device.irq[0] = IRQ_EB11MP_CLCD; + wdog_device.irq[0] = IRQ_EB11MP_WDOG; + gpio0_device.irq[0] = IRQ_EB11MP_GPIO0; + gpio1_device.irq[0] = IRQ_EB11MP_GPIO1; + gpio2_device.irq[0] = IRQ_EB11MP_GPIO2; + rtc_device.irq[0] = IRQ_EB11MP_RTC; + sci0_device.irq[0] = IRQ_EB11MP_SCI; + ssp0_device.irq[0] = IRQ_EB11MP_SSP; + aaci_device.irq[0] = IRQ_EB11MP_AACI; + mmc0_device.irq[0] = IRQ_EB11MP_MMCI0A; + mmc0_device.irq[1] = IRQ_EB11MP_MMCI0B; + kmi0_device.irq[0] = IRQ_EB11MP_KMI0; + kmi1_device.irq[0] = IRQ_EB11MP_KMI1; + + /* platform devices */ + realview_eb_smc91x_resources[1].start = IRQ_EB11MP_ETH; + realview_eb_smc91x_resources[1].end = IRQ_EB11MP_ETH; +} + +static void __init realview_eb_timer_init(void) +{ + unsigned int timer_irq; + + if (core_tile_eb11mp()) { +#ifdef CONFIG_LOCAL_TIMERS + twd_base_addr = __io_address(REALVIEW_EB11MP_TWD_BASE); + twd_size = REALVIEW_EB11MP_TWD_SIZE; #endif + timer_irq = IRQ_EB11MP_TIMER0_1; + } else + timer_irq = IRQ_EB_TIMER0_1; + + realview_timer_init(timer_irq); } +static struct sys_timer realview_eb_timer = { + .init = realview_eb_timer_init, +}; + static void __init realview_eb_init(void) { int i; -#ifdef CONFIG_REALVIEW_MPCORE - /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled - * Bits: .... ...0 0111 1001 0000 .... .... .... */ - l2x0_init(__io_address(REALVIEW_MPCORE_L220_BASE), 0x00790000, 0xfe000fff); -#endif + if (core_tile_eb11mp()) { + realview_eb11mp_fixup(); + + /* 1MB (128KB/way), 8-way associativity, evmon/parity/share enabled + * Bits: .... ...0 0111 1001 0000 .... .... .... */ + l2x0_init(__io_address(REALVIEW_EB11MP_L220_BASE), 0x00790000, 0xfe000fff); + } + clk_register(&realview_clcd_clk); platform_device_register(&realview_flash_device); - platform_device_register(&realview_smc91x_device); + platform_device_register(&realview_eb_smc91x_device); platform_device_register(&realview_i2c_device); for (i = 0; i < ARRAY_SIZE(amba_devs); i++) { @@ -204,6 +360,6 @@ MACHINE_START(REALVIEW_EB, "ARM-RealView EB") .boot_params = 0x00000100, .map_io = realview_eb_map_io, .init_irq = gic_init_irq, - .timer = &realview_timer, + .timer = &realview_eb_timer, .init_machine = realview_eb_init, MACHINE_END |