diff options
-rw-r--r-- | drivers/clocksource/time-armada-370-xp.c | 89 |
1 files changed, 41 insertions, 48 deletions
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c index b1e1d92a8839..f86542002ee1 100644 --- a/drivers/clocksource/time-armada-370-xp.c +++ b/drivers/clocksource/time-armada-370-xp.c | |||
@@ -19,6 +19,7 @@ | |||
19 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
20 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
21 | #include <linux/clk.h> | 21 | #include <linux/clk.h> |
22 | #include <linux/cpu.h> | ||
22 | #include <linux/timer.h> | 23 | #include <linux/timer.h> |
23 | #include <linux/clockchips.h> | 24 | #include <linux/clockchips.h> |
24 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
@@ -31,7 +32,6 @@ | |||
31 | #include <linux/percpu.h> | 32 | #include <linux/percpu.h> |
32 | #include <linux/time-armada-370-xp.h> | 33 | #include <linux/time-armada-370-xp.h> |
33 | 34 | ||
34 | #include <asm/localtimer.h> | ||
35 | /* | 35 | /* |
36 | * Timer block registers. | 36 | * Timer block registers. |
37 | */ | 37 | */ |
@@ -70,7 +70,7 @@ static bool timer25Mhz = true; | |||
70 | */ | 70 | */ |
71 | static u32 ticks_per_jiffy; | 71 | static u32 ticks_per_jiffy; |
72 | 72 | ||
73 | static struct clock_event_device __percpu **percpu_armada_370_xp_evt; | 73 | static struct clock_event_device __percpu *armada_370_xp_evt; |
74 | 74 | ||
75 | static u32 notrace armada_370_xp_read_sched_clock(void) | 75 | static u32 notrace armada_370_xp_read_sched_clock(void) |
76 | { | 76 | { |
@@ -143,21 +143,14 @@ armada_370_xp_clkevt_mode(enum clock_event_mode mode, | |||
143 | } | 143 | } |
144 | } | 144 | } |
145 | 145 | ||
146 | static struct clock_event_device armada_370_xp_clkevt = { | 146 | static int armada_370_xp_clkevt_irq; |
147 | .name = "armada_370_xp_per_cpu_tick", | ||
148 | .features = CLOCK_EVT_FEAT_ONESHOT | CLOCK_EVT_FEAT_PERIODIC, | ||
149 | .shift = 32, | ||
150 | .rating = 300, | ||
151 | .set_next_event = armada_370_xp_clkevt_next_event, | ||
152 | .set_mode = armada_370_xp_clkevt_mode, | ||
153 | }; | ||
154 | 147 | ||
155 | static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) | 148 | static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) |
156 | { | 149 | { |
157 | /* | 150 | /* |
158 | * ACK timer interrupt and call event handler. | 151 | * ACK timer interrupt and call event handler. |
159 | */ | 152 | */ |
160 | struct clock_event_device *evt = *(struct clock_event_device **)dev_id; | 153 | struct clock_event_device *evt = dev_id; |
161 | 154 | ||
162 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); | 155 | writel(TIMER0_CLR_MASK, local_base + LCL_TIMER_EVENTS_STATUS); |
163 | evt->event_handler(evt); | 156 | evt->event_handler(evt); |
@@ -173,42 +166,55 @@ static int __cpuinit armada_370_xp_timer_setup(struct clock_event_device *evt) | |||
173 | u32 u; | 166 | u32 u; |
174 | int cpu = smp_processor_id(); | 167 | int cpu = smp_processor_id(); |
175 | 168 | ||
176 | /* Use existing clock_event for cpu 0 */ | ||
177 | if (!smp_processor_id()) | ||
178 | return 0; | ||
179 | |||
180 | u = readl(local_base + TIMER_CTRL_OFF); | 169 | u = readl(local_base + TIMER_CTRL_OFF); |
181 | if (timer25Mhz) | 170 | if (timer25Mhz) |
182 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 171 | writel(u | TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); |
183 | else | 172 | else |
184 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); | 173 | writel(u & ~TIMER0_25MHZ, local_base + TIMER_CTRL_OFF); |
185 | 174 | ||
186 | evt->name = armada_370_xp_clkevt.name; | 175 | evt->name = "armada_370_xp_per_cpu_tick", |
187 | evt->irq = armada_370_xp_clkevt.irq; | 176 | evt->features = CLOCK_EVT_FEAT_ONESHOT | |
188 | evt->features = armada_370_xp_clkevt.features; | 177 | CLOCK_EVT_FEAT_PERIODIC; |
189 | evt->shift = armada_370_xp_clkevt.shift; | 178 | evt->shift = 32, |
190 | evt->rating = armada_370_xp_clkevt.rating, | 179 | evt->rating = 300, |
191 | evt->set_next_event = armada_370_xp_clkevt_next_event, | 180 | evt->set_next_event = armada_370_xp_clkevt_next_event, |
192 | evt->set_mode = armada_370_xp_clkevt_mode, | 181 | evt->set_mode = armada_370_xp_clkevt_mode, |
182 | evt->irq = armada_370_xp_clkevt_irq; | ||
193 | evt->cpumask = cpumask_of(cpu); | 183 | evt->cpumask = cpumask_of(cpu); |
194 | 184 | ||
195 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = evt; | ||
196 | |||
197 | clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); | 185 | clockevents_config_and_register(evt, timer_clk, 1, 0xfffffffe); |
198 | enable_percpu_irq(evt->irq, 0); | 186 | enable_percpu_irq(evt->irq, 0); |
199 | 187 | ||
200 | return 0; | 188 | return 0; |
201 | } | 189 | } |
202 | 190 | ||
203 | static void armada_370_xp_timer_stop(struct clock_event_device *evt) | 191 | static void __cpuinit armada_370_xp_timer_stop(struct clock_event_device *evt) |
204 | { | 192 | { |
205 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); | 193 | evt->set_mode(CLOCK_EVT_MODE_UNUSED, evt); |
206 | disable_percpu_irq(evt->irq); | 194 | disable_percpu_irq(evt->irq); |
207 | } | 195 | } |
208 | 196 | ||
209 | static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { | 197 | static int __cpuinit armada_370_xp_timer_cpu_notify(struct notifier_block *self, |
210 | .setup = armada_370_xp_timer_setup, | 198 | unsigned long action, void *hcpu) |
211 | .stop = armada_370_xp_timer_stop, | 199 | { |
200 | /* | ||
201 | * Grab cpu pointer in each case to avoid spurious | ||
202 | * preemptible warnings | ||
203 | */ | ||
204 | switch (action & ~CPU_TASKS_FROZEN) { | ||
205 | case CPU_STARTING: | ||
206 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); | ||
207 | break; | ||
208 | case CPU_DYING: | ||
209 | armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt)); | ||
210 | break; | ||
211 | } | ||
212 | |||
213 | return NOTIFY_OK; | ||
214 | } | ||
215 | |||
216 | static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = { | ||
217 | .notifier_call = armada_370_xp_timer_cpu_notify, | ||
212 | }; | 218 | }; |
213 | 219 | ||
214 | void __init armada_370_xp_timer_init(void) | 220 | void __init armada_370_xp_timer_init(void) |
@@ -224,9 +230,6 @@ void __init armada_370_xp_timer_init(void) | |||
224 | 230 | ||
225 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { | 231 | if (of_find_property(np, "marvell,timer-25Mhz", NULL)) { |
226 | /* The fixed 25MHz timer is available so let's use it */ | 232 | /* The fixed 25MHz timer is available so let's use it */ |
227 | u = readl(local_base + TIMER_CTRL_OFF); | ||
228 | writel(u | TIMER0_25MHZ, | ||
229 | local_base + TIMER_CTRL_OFF); | ||
230 | u = readl(timer_base + TIMER_CTRL_OFF); | 233 | u = readl(timer_base + TIMER_CTRL_OFF); |
231 | writel(u | TIMER0_25MHZ, | 234 | writel(u | TIMER0_25MHZ, |
232 | timer_base + TIMER_CTRL_OFF); | 235 | timer_base + TIMER_CTRL_OFF); |
@@ -236,9 +239,6 @@ void __init armada_370_xp_timer_init(void) | |||
236 | struct clk *clk = of_clk_get(np, 0); | 239 | struct clk *clk = of_clk_get(np, 0); |
237 | WARN_ON(IS_ERR(clk)); | 240 | WARN_ON(IS_ERR(clk)); |
238 | rate = clk_get_rate(clk); | 241 | rate = clk_get_rate(clk); |
239 | u = readl(local_base + TIMER_CTRL_OFF); | ||
240 | writel(u & ~(TIMER0_25MHZ), | ||
241 | local_base + TIMER_CTRL_OFF); | ||
242 | 242 | ||
243 | u = readl(timer_base + TIMER_CTRL_OFF); | 243 | u = readl(timer_base + TIMER_CTRL_OFF); |
244 | writel(u & ~(TIMER0_25MHZ), | 244 | writel(u & ~(TIMER0_25MHZ), |
@@ -252,7 +252,7 @@ void __init armada_370_xp_timer_init(void) | |||
252 | * We use timer 0 as clocksource, and private(local) timer 0 | 252 | * We use timer 0 as clocksource, and private(local) timer 0 |
253 | * for clockevents | 253 | * for clockevents |
254 | */ | 254 | */ |
255 | armada_370_xp_clkevt.irq = irq_of_parse_and_map(np, 4); | 255 | armada_370_xp_clkevt_irq = irq_of_parse_and_map(np, 4); |
256 | 256 | ||
257 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; | 257 | ticks_per_jiffy = (timer_clk + HZ / 2) / HZ; |
258 | 258 | ||
@@ -277,26 +277,19 @@ void __init armada_370_xp_timer_init(void) | |||
277 | "armada_370_xp_clocksource", | 277 | "armada_370_xp_clocksource", |
278 | timer_clk, 300, 32, clocksource_mmio_readl_down); | 278 | timer_clk, 300, 32, clocksource_mmio_readl_down); |
279 | 279 | ||
280 | /* Register the clockevent on the private timer of CPU 0 */ | 280 | register_cpu_notifier(&armada_370_xp_timer_cpu_nb); |
281 | armada_370_xp_clkevt.cpumask = cpumask_of(0); | ||
282 | clockevents_config_and_register(&armada_370_xp_clkevt, | ||
283 | timer_clk, 1, 0xfffffffe); | ||
284 | 281 | ||
285 | percpu_armada_370_xp_evt = alloc_percpu(struct clock_event_device *); | 282 | armada_370_xp_evt = alloc_percpu(struct clock_event_device); |
286 | 283 | ||
287 | 284 | ||
288 | /* | 285 | /* |
289 | * Setup clockevent timer (interrupt-driven). | 286 | * Setup clockevent timer (interrupt-driven). |
290 | */ | 287 | */ |
291 | *__this_cpu_ptr(percpu_armada_370_xp_evt) = &armada_370_xp_clkevt; | 288 | res = request_percpu_irq(armada_370_xp_clkevt_irq, |
292 | res = request_percpu_irq(armada_370_xp_clkevt.irq, | ||
293 | armada_370_xp_timer_interrupt, | 289 | armada_370_xp_timer_interrupt, |
294 | armada_370_xp_clkevt.name, | 290 | "armada_370_xp_per_cpu_tick", |
295 | percpu_armada_370_xp_evt); | 291 | armada_370_xp_evt); |
296 | if (!res) { | 292 | /* Immediately configure the timer on the boot CPU */ |
297 | enable_percpu_irq(armada_370_xp_clkevt.irq, 0); | 293 | if (!res) |
298 | #ifdef CONFIG_LOCAL_TIMERS | 294 | armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt)); |
299 | local_timer_register(&armada_370_xp_local_timer_ops); | ||
300 | #endif | ||
301 | } | ||
302 | } | 295 | } |