aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/clocksource/time-armada-370-xp.c
diff options
context:
space:
mode:
authorStephen Boyd <sboyd@codeaurora.org>2013-02-15 20:02:16 -0500
committerStephen Boyd <sboyd@codeaurora.org>2013-06-24 20:47:34 -0400
commit5ddb6d21c30d10ae4a740a788bb9101bd384fea5 (patch)
treea12436096fcc59ba2629f496da7b813caf6fcdc2 /drivers/clocksource/time-armada-370-xp.c
parentfaef31b482549640e2d0095afdf3dedb992cfa80 (diff)
clocksource: time-armada-370-xp: Divorce from local timer API
Separate the armada 370xp local timers from the local timer API. This will allow us to remove ARM local timer support in the near future and makes this driver multi-architecture friendly. Acked-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Tested-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Acked-by: Marc Zyngier <marc.zyngier@arm.com> Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
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}