aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/time-armada-370-xp.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/clocksource/time-armada-370-xp.c')
-rw-r--r--drivers/clocksource/time-armada-370-xp.c89
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 */
71static u32 ticks_per_jiffy; 71static u32 ticks_per_jiffy;
72 72
73static struct clock_event_device __percpu **percpu_armada_370_xp_evt; 73static struct clock_event_device __percpu *armada_370_xp_evt;
74 74
75static u32 notrace armada_370_xp_read_sched_clock(void) 75static 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
146static struct clock_event_device armada_370_xp_clkevt = { 146static 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
155static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id) 148static 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
203static void armada_370_xp_timer_stop(struct clock_event_device *evt) 191static 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
209static struct local_timer_ops armada_370_xp_local_timer_ops __cpuinitdata = { 197static 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
216static struct notifier_block armada_370_xp_timer_cpu_nb __cpuinitdata = {
217 .notifier_call = armada_370_xp_timer_cpu_notify,
212}; 218};
213 219
214void __init armada_370_xp_timer_init(void) 220void __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}