aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-realview
diff options
context:
space:
mode:
authorRussell King <rmk@dyn-67.arm.linux.org.uk>2009-06-01 13:35:26 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2009-06-01 13:35:26 -0400
commitc7f7ff179cb9f2f1e0244ef2c80afbb93c74ce2a (patch)
tree717656ebdba1fea6c763b2c57076c4c6996dfba3 /arch/arm/mach-realview
parenta22f277bba321474a01691ae66d5952926459f44 (diff)
parente03cdade0ca945a04e982525e50fef275190b77b (diff)
Merge branch 'smp' into devel
Diffstat (limited to 'arch/arm/mach-realview')
-rw-r--r--arch/arm/mach-realview/Makefile3
-rw-r--r--arch/arm/mach-realview/core.h3
-rw-r--r--arch/arm/mach-realview/include/mach/scu.h13
-rw-r--r--arch/arm/mach-realview/localtimer.c188
-rw-r--r--arch/arm/mach-realview/platsmp.c49
-rw-r--r--arch/arm/mach-realview/realview_eb.c1
-rw-r--r--arch/arm/mach-realview/realview_pb11mp.c1
7 files changed, 24 insertions, 234 deletions
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 7bea8ffc4b59..e13d0947ad0b 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
7obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o 7obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
8obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o 8obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
9obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o 9obj-$(CONFIG_MACH_REALVIEW_PBA8) += realview_pba8.o
10obj-$(CONFIG_SMP) += platsmp.o headsmp.o localtimer.o 10obj-$(CONFIG_SMP) += platsmp.o headsmp.o
11obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o 11obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
12obj-$(CONFIG_LOCAL_TIMERS) += localtimer.o
diff --git a/arch/arm/mach-realview/core.h b/arch/arm/mach-realview/core.h
index 21c08637683b..59a337ba4be7 100644
--- a/arch/arm/mach-realview/core.h
+++ b/arch/arm/mach-realview/core.h
@@ -51,9 +51,6 @@ extern struct mmc_platform_data realview_mmc0_plat_data;
51extern struct mmc_platform_data realview_mmc1_plat_data; 51extern struct mmc_platform_data realview_mmc1_plat_data;
52extern struct clcd_board clcd_plat_data; 52extern struct clcd_board clcd_plat_data;
53extern void __iomem *gic_cpu_base_addr; 53extern void __iomem *gic_cpu_base_addr;
54#ifdef CONFIG_LOCAL_TIMERS
55extern void __iomem *twd_base;
56#endif
57extern void __iomem *timer0_va_base; 54extern void __iomem *timer0_va_base;
58extern void __iomem *timer1_va_base; 55extern void __iomem *timer1_va_base;
59extern void __iomem *timer2_va_base; 56extern void __iomem *timer2_va_base;
diff --git a/arch/arm/mach-realview/include/mach/scu.h b/arch/arm/mach-realview/include/mach/scu.h
deleted file mode 100644
index d55802d645af..000000000000
--- a/arch/arm/mach-realview/include/mach/scu.h
+++ /dev/null
@@ -1,13 +0,0 @@
1#ifndef __ASMARM_ARCH_SCU_H
2#define __ASMARM_ARCH_SCU_H
3
4/*
5 * SCU registers
6 */
7#define SCU_CTRL 0x00
8#define SCU_CONFIG 0x04
9#define SCU_CPU_STATUS 0x08
10#define SCU_INVALIDATE 0x0c
11#define SCU_FPGA_REVISION 0x10
12
13#endif
diff --git a/arch/arm/mach-realview/localtimer.c b/arch/arm/mach-realview/localtimer.c
index 1c01d13460f0..60b4e111f459 100644
--- a/arch/arm/mach-realview/localtimer.c
+++ b/arch/arm/mach-realview/localtimer.c
@@ -9,196 +9,18 @@
9 * published by the Free Software Foundation. 9 * published by the Free Software Foundation.
10 */ 10 */
11#include <linux/init.h> 11#include <linux/init.h>
12#include <linux/kernel.h>
13#include <linux/delay.h>
14#include <linux/device.h>
15#include <linux/smp.h> 12#include <linux/smp.h>
16#include <linux/jiffies.h>
17#include <linux/percpu.h>
18#include <linux/clockchips.h> 13#include <linux/clockchips.h>
19#include <linux/irq.h>
20#include <linux/io.h>
21 14
22#include <asm/hardware/arm_twd.h>
23#include <asm/hardware/gic.h>
24#include <mach/hardware.h>
25#include <asm/irq.h> 15#include <asm/irq.h>
26 16#include <asm/smp_twd.h>
27static DEFINE_PER_CPU(struct clock_event_device, local_clockevent); 17#include <asm/localtimer.h>
28
29/*
30 * Used on SMP for either the local timer or IPI_TIMER
31 */
32void local_timer_interrupt(void)
33{
34 struct clock_event_device *clk = &__get_cpu_var(local_clockevent);
35
36 clk->event_handler(clk);
37}
38
39#ifdef CONFIG_LOCAL_TIMERS
40
41/* set up by the platform code */
42void __iomem *twd_base;
43
44static unsigned long mpcore_timer_rate;
45
46static void local_timer_set_mode(enum clock_event_mode mode,
47 struct clock_event_device *clk)
48{
49 unsigned long ctrl;
50
51 switch(mode) {
52 case CLOCK_EVT_MODE_PERIODIC:
53 /* timer load already set up */
54 ctrl = TWD_TIMER_CONTROL_ENABLE | TWD_TIMER_CONTROL_IT_ENABLE
55 | TWD_TIMER_CONTROL_PERIODIC;
56 break;
57 case CLOCK_EVT_MODE_ONESHOT:
58 /* period set, and timer enabled in 'next_event' hook */
59 ctrl = TWD_TIMER_CONTROL_IT_ENABLE | TWD_TIMER_CONTROL_ONESHOT;
60 break;
61 case CLOCK_EVT_MODE_UNUSED:
62 case CLOCK_EVT_MODE_SHUTDOWN:
63 default:
64 ctrl = 0;
65 }
66
67 __raw_writel(ctrl, twd_base + TWD_TIMER_CONTROL);
68}
69
70static int local_timer_set_next_event(unsigned long evt,
71 struct clock_event_device *unused)
72{
73 unsigned long ctrl = __raw_readl(twd_base + TWD_TIMER_CONTROL);
74
75 __raw_writel(evt, twd_base + TWD_TIMER_COUNTER);
76 __raw_writel(ctrl | TWD_TIMER_CONTROL_ENABLE, twd_base + TWD_TIMER_CONTROL);
77
78 return 0;
79}
80
81/*
82 * local_timer_ack: checks for a local timer interrupt.
83 *
84 * If a local timer interrupt has occurred, acknowledge and return 1.
85 * Otherwise, return 0.
86 */
87int local_timer_ack(void)
88{
89 if (__raw_readl(twd_base + TWD_TIMER_INTSTAT)) {
90 __raw_writel(1, twd_base + TWD_TIMER_INTSTAT);
91 return 1;
92 }
93
94 return 0;
95}
96
97static void __cpuinit twd_calibrate_rate(void)
98{
99 unsigned long load, count;
100 u64 waitjiffies;
101
102 /*
103 * If this is the first time round, we need to work out how fast
104 * the timer ticks
105 */
106 if (mpcore_timer_rate == 0) {
107 printk("Calibrating local timer... ");
108
109 /* Wait for a tick to start */
110 waitjiffies = get_jiffies_64() + 1;
111
112 while (get_jiffies_64() < waitjiffies)
113 udelay(10);
114
115 /* OK, now the tick has started, let's get the timer going */
116 waitjiffies += 5;
117
118 /* enable, no interrupt or reload */
119 __raw_writel(0x1, twd_base + TWD_TIMER_CONTROL);
120
121 /* maximum value */
122 __raw_writel(0xFFFFFFFFU, twd_base + TWD_TIMER_COUNTER);
123
124 while (get_jiffies_64() < waitjiffies)
125 udelay(10);
126
127 count = __raw_readl(twd_base + TWD_TIMER_COUNTER);
128
129 mpcore_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5);
130
131 printk("%lu.%02luMHz.\n", mpcore_timer_rate / 1000000,
132 (mpcore_timer_rate / 100000) % 100);
133 }
134
135 load = mpcore_timer_rate / HZ;
136
137 __raw_writel(load, twd_base + TWD_TIMER_LOAD);
138}
139 18
140/* 19/*
141 * Setup the local clock events for a CPU. 20 * Setup the local clock events for a CPU.
142 */ 21 */
143void __cpuinit local_timer_setup(void) 22void __cpuinit local_timer_setup(struct clock_event_device *evt)
144{
145 unsigned int cpu = smp_processor_id();
146 struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
147 unsigned long flags;
148
149 twd_calibrate_rate();
150
151 clk->name = "local_timer";
152 clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
153 clk->rating = 350;
154 clk->set_mode = local_timer_set_mode;
155 clk->set_next_event = local_timer_set_next_event;
156 clk->irq = IRQ_LOCALTIMER;
157 clk->cpumask = cpumask_of(cpu);
158 clk->shift = 20;
159 clk->mult = div_sc(mpcore_timer_rate, NSEC_PER_SEC, clk->shift);
160 clk->max_delta_ns = clockevent_delta2ns(0xffffffff, clk);
161 clk->min_delta_ns = clockevent_delta2ns(0xf, clk);
162
163 /* Make sure our local interrupt controller has this enabled */
164 local_irq_save(flags);
165 get_irq_chip(IRQ_LOCALTIMER)->unmask(IRQ_LOCALTIMER);
166 local_irq_restore(flags);
167
168 clockevents_register_device(clk);
169}
170
171/*
172 * take a local timer down
173 */
174void __cpuexit local_timer_stop(void)
175{ 23{
176 __raw_writel(0, twd_base + TWD_TIMER_CONTROL); 24 evt->irq = IRQ_LOCALTIMER;
25 twd_timer_setup(evt);
177} 26}
178
179#else /* CONFIG_LOCAL_TIMERS */
180
181static void dummy_timer_set_mode(enum clock_event_mode mode,
182 struct clock_event_device *clk)
183{
184}
185
186void __cpuinit local_timer_setup(void)
187{
188 unsigned int cpu = smp_processor_id();
189 struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
190
191 clk->name = "dummy_timer";
192 clk->features = CLOCK_EVT_FEAT_ONESHOT |
193 CLOCK_EVT_FEAT_PERIODIC |
194 CLOCK_EVT_FEAT_DUMMY;
195 clk->rating = 400;
196 clk->mult = 1;
197 clk->set_mode = dummy_timer_set_mode;
198 clk->broadcast = smp_timer_broadcast;
199 clk->cpumask = cpumask_of(cpu);
200
201 clockevents_register_device(clk);
202}
203
204#endif /* !CONFIG_LOCAL_TIMERS */
diff --git a/arch/arm/mach-realview/platsmp.c b/arch/arm/mach-realview/platsmp.c
index 30a9c68591f6..ca742172ea78 100644
--- a/arch/arm/mach-realview/platsmp.c
+++ b/arch/arm/mach-realview/platsmp.c
@@ -19,10 +19,11 @@
19#include <asm/cacheflush.h> 19#include <asm/cacheflush.h>
20#include <mach/hardware.h> 20#include <mach/hardware.h>
21#include <asm/mach-types.h> 21#include <asm/mach-types.h>
22#include <asm/localtimer.h>
22 23
23#include <mach/board-eb.h> 24#include <mach/board-eb.h>
24#include <mach/board-pb11mp.h> 25#include <mach/board-pb11mp.h>
25#include <mach/scu.h> 26#include <asm/smp_scu.h>
26 27
27#include "core.h" 28#include "core.h"
28 29
@@ -44,31 +45,12 @@ static void __iomem *scu_base_addr(void)
44 return (void __iomem *)0; 45 return (void __iomem *)0;
45} 46}
46 47
47static unsigned int __init get_core_count(void) 48static inline unsigned int get_core_count(void)
48{ 49{
49 unsigned int ncores;
50 void __iomem *scu_base = scu_base_addr(); 50 void __iomem *scu_base = scu_base_addr();
51 51 if (scu_base)
52 if (scu_base) { 52 return scu_get_core_count(scu_base);
53 ncores = __raw_readl(scu_base + SCU_CONFIG); 53 return 1;
54 ncores = (ncores & 0x03) + 1;
55 } else
56 ncores = 1;
57
58 return ncores;
59}
60
61/*
62 * Setup the SCU
63 */
64static void scu_enable(void)
65{
66 u32 scu_ctrl;
67 void __iomem *scu_base = scu_base_addr();
68
69 scu_ctrl = __raw_readl(scu_base + SCU_CTRL);
70 scu_ctrl |= 1;
71 __raw_writel(scu_ctrl, scu_base + SCU_CTRL);
72} 54}
73 55
74static DEFINE_SPINLOCK(boot_lock); 56static DEFINE_SPINLOCK(boot_lock);
@@ -184,7 +166,7 @@ void __init smp_init_cpus(void)
184 unsigned int i, ncores = get_core_count(); 166 unsigned int i, ncores = get_core_count();
185 167
186 for (i = 0; i < ncores; i++) 168 for (i = 0; i < ncores; i++)
187 cpu_set(i, cpu_possible_map); 169 set_cpu_possible(i, true);
188} 170}
189 171
190void __init smp_prepare_cpus(unsigned int max_cpus) 172void __init smp_prepare_cpus(unsigned int max_cpus)
@@ -217,19 +199,12 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
217 if (max_cpus > ncores) 199 if (max_cpus > ncores)
218 max_cpus = ncores; 200 max_cpus = ncores;
219 201
220#if defined(CONFIG_LOCAL_TIMERS) || defined(CONFIG_GENERIC_CLOCKEVENTS_BROADCAST)
221 /*
222 * Enable the local timer or broadcast device for the boot CPU.
223 */
224 local_timer_setup();
225#endif
226
227 /* 202 /*
228 * Initialise the present map, which describes the set of CPUs 203 * Initialise the present map, which describes the set of CPUs
229 * actually populated at the present time. 204 * actually populated at the present time.
230 */ 205 */
231 for (i = 0; i < max_cpus; i++) 206 for (i = 0; i < max_cpus; i++)
232 cpu_set(i, cpu_present_map); 207 set_cpu_present(i, true);
233 208
234 /* 209 /*
235 * Initialise the SCU if there are more than one CPU and let 210 * Initialise the SCU if there are more than one CPU and let
@@ -239,7 +214,13 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
239 * WFI 214 * WFI
240 */ 215 */
241 if (max_cpus > 1) { 216 if (max_cpus > 1) {
242 scu_enable(); 217 /*
218 * Enable the local timer or broadcast device for the
219 * boot CPU, but only if we have more than one CPU.
220 */
221 percpu_timer_setup();
222
223 scu_enable(scu_base_addr());
243 poke_milo(); 224 poke_milo();
244 } 225 }
245} 226}
diff --git a/arch/arm/mach-realview/realview_eb.c b/arch/arm/mach-realview/realview_eb.c
index c20fbef122b3..8dfa44e08a94 100644
--- a/arch/arm/mach-realview/realview_eb.c
+++ b/arch/arm/mach-realview/realview_eb.c
@@ -32,6 +32,7 @@
32#include <asm/hardware/gic.h> 32#include <asm/hardware/gic.h>
33#include <asm/hardware/icst307.h> 33#include <asm/hardware/icst307.h>
34#include <asm/hardware/cache-l2x0.h> 34#include <asm/hardware/cache-l2x0.h>
35#include <asm/localtimer.h>
35 36
36#include <asm/mach/arch.h> 37#include <asm/mach/arch.h>
37#include <asm/mach/map.h> 38#include <asm/mach/map.h>
diff --git a/arch/arm/mach-realview/realview_pb11mp.c b/arch/arm/mach-realview/realview_pb11mp.c
index ea1e60eca359..dc4b16943907 100644
--- a/arch/arm/mach-realview/realview_pb11mp.c
+++ b/arch/arm/mach-realview/realview_pb11mp.c
@@ -32,6 +32,7 @@
32#include <asm/hardware/gic.h> 32#include <asm/hardware/gic.h>
33#include <asm/hardware/icst307.h> 33#include <asm/hardware/icst307.h>
34#include <asm/hardware/cache-l2x0.h> 34#include <asm/hardware/cache-l2x0.h>
35#include <asm/localtimer.h>
35 36
36#include <asm/mach/arch.h> 37#include <asm/mach/arch.h>
37#include <asm/mach/flash.h> 38#include <asm/mach/flash.h>