diff options
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
-rw-r--r-- | arch/blackfin/kernel/time-ts.c | 205 |
1 files changed, 113 insertions, 92 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 17c38c5b5b22..cb7a01d4f009 100644 --- a/arch/blackfin/kernel/time-ts.c +++ b/arch/blackfin/kernel/time-ts.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <asm/blackfin.h> | 21 | #include <asm/blackfin.h> |
22 | #include <asm/time.h> | 22 | #include <asm/time.h> |
23 | #include <asm/gptimers.h> | 23 | #include <asm/gptimers.h> |
24 | #include <asm/nmi.h> | ||
24 | 25 | ||
25 | /* Accelerators for sched_clock() | 26 | /* Accelerators for sched_clock() |
26 | * convert from cycles(64bits) => nanoseconds (64bits) | 27 | * convert from cycles(64bits) => nanoseconds (64bits) |
@@ -50,7 +51,11 @@ | |||
50 | 51 | ||
51 | static notrace cycle_t bfin_read_cycles(struct clocksource *cs) | 52 | static notrace cycle_t bfin_read_cycles(struct clocksource *cs) |
52 | { | 53 | { |
54 | #ifdef CONFIG_CPU_FREQ | ||
53 | return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod); | 55 | return __bfin_cycles_off + (get_cycles() << __bfin_cycles_mod); |
56 | #else | ||
57 | return get_cycles(); | ||
58 | #endif | ||
54 | } | 59 | } |
55 | 60 | ||
56 | static struct clocksource bfin_cs_cycles = { | 61 | static struct clocksource bfin_cs_cycles = { |
@@ -132,7 +137,6 @@ static int __init bfin_cs_gptimer0_init(void) | |||
132 | # define bfin_cs_gptimer0_init() | 137 | # define bfin_cs_gptimer0_init() |
133 | #endif | 138 | #endif |
134 | 139 | ||
135 | |||
136 | #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE) | 140 | #if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE) |
137 | /* prefer to use cycles since it has higher rating */ | 141 | /* prefer to use cycles since it has higher rating */ |
138 | notrace unsigned long long sched_clock(void) | 142 | notrace unsigned long long sched_clock(void) |
@@ -145,47 +149,8 @@ notrace unsigned long long sched_clock(void) | |||
145 | } | 149 | } |
146 | #endif | 150 | #endif |
147 | 151 | ||
148 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 | ||
149 | __attribute__((l1_text)) | ||
150 | #endif | ||
151 | irqreturn_t timer_interrupt(int irq, void *dev_id); | ||
152 | |||
153 | static int bfin_timer_set_next_event(unsigned long, \ | ||
154 | struct clock_event_device *); | ||
155 | |||
156 | static void bfin_timer_set_mode(enum clock_event_mode, \ | ||
157 | struct clock_event_device *); | ||
158 | |||
159 | static struct clock_event_device clockevent_bfin = { | ||
160 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
161 | .name = "bfin_gptimer0", | ||
162 | .rating = 300, | ||
163 | .irq = IRQ_TIMER0, | ||
164 | #else | ||
165 | .name = "bfin_core_timer", | ||
166 | .rating = 350, | ||
167 | .irq = IRQ_CORETMR, | ||
168 | #endif | ||
169 | .shift = 32, | ||
170 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
171 | .set_next_event = bfin_timer_set_next_event, | ||
172 | .set_mode = bfin_timer_set_mode, | ||
173 | }; | ||
174 | |||
175 | static struct irqaction bfin_timer_irq = { | ||
176 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
177 | .name = "Blackfin GPTimer0", | ||
178 | #else | ||
179 | .name = "Blackfin CoreTimer", | ||
180 | #endif | ||
181 | .flags = IRQF_DISABLED | IRQF_TIMER | \ | ||
182 | IRQF_IRQPOLL | IRQF_PERCPU, | ||
183 | .handler = timer_interrupt, | ||
184 | .dev_id = &clockevent_bfin, | ||
185 | }; | ||
186 | |||
187 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | 152 | #if defined(CONFIG_TICKSOURCE_GPTMR0) |
188 | static int bfin_timer_set_next_event(unsigned long cycles, | 153 | static int bfin_gptmr0_set_next_event(unsigned long cycles, |
189 | struct clock_event_device *evt) | 154 | struct clock_event_device *evt) |
190 | { | 155 | { |
191 | disable_gptimers(TIMER0bit); | 156 | disable_gptimers(TIMER0bit); |
@@ -196,7 +161,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, | |||
196 | return 0; | 161 | return 0; |
197 | } | 162 | } |
198 | 163 | ||
199 | static void bfin_timer_set_mode(enum clock_event_mode mode, | 164 | static void bfin_gptmr0_set_mode(enum clock_event_mode mode, |
200 | struct clock_event_device *evt) | 165 | struct clock_event_device *evt) |
201 | { | 166 | { |
202 | switch (mode) { | 167 | switch (mode) { |
@@ -224,25 +189,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, | |||
224 | } | 189 | } |
225 | } | 190 | } |
226 | 191 | ||
227 | static void bfin_timer_ack(void) | 192 | static void bfin_gptmr0_ack(void) |
228 | { | 193 | { |
229 | set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); | 194 | set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); |
230 | } | 195 | } |
231 | 196 | ||
232 | static void __init bfin_timer_init(void) | 197 | static void __init bfin_gptmr0_init(void) |
233 | { | 198 | { |
234 | disable_gptimers(TIMER0bit); | 199 | disable_gptimers(TIMER0bit); |
235 | } | 200 | } |
236 | 201 | ||
237 | static unsigned long __init bfin_clockevent_check(void) | 202 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 |
203 | __attribute__((l1_text)) | ||
204 | #endif | ||
205 | irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id) | ||
238 | { | 206 | { |
239 | setup_irq(IRQ_TIMER0, &bfin_timer_irq); | 207 | struct clock_event_device *evt = dev_id; |
240 | return get_sclk(); | 208 | smp_mb(); |
209 | evt->event_handler(evt); | ||
210 | bfin_gptmr0_ack(); | ||
211 | return IRQ_HANDLED; | ||
241 | } | 212 | } |
242 | 213 | ||
243 | #else /* CONFIG_TICKSOURCE_CORETMR */ | 214 | static struct irqaction gptmr0_irq = { |
215 | .name = "Blackfin GPTimer0", | ||
216 | .flags = IRQF_DISABLED | IRQF_TIMER | \ | ||
217 | IRQF_IRQPOLL | IRQF_PERCPU, | ||
218 | .handler = bfin_gptmr0_interrupt, | ||
219 | }; | ||
244 | 220 | ||
245 | static int bfin_timer_set_next_event(unsigned long cycles, | 221 | static struct clock_event_device clockevent_gptmr0 = { |
222 | .name = "bfin_gptimer0", | ||
223 | .rating = 300, | ||
224 | .irq = IRQ_TIMER0, | ||
225 | .shift = 32, | ||
226 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, | ||
227 | .set_next_event = bfin_gptmr0_set_next_event, | ||
228 | .set_mode = bfin_gptmr0_set_mode, | ||
229 | }; | ||
230 | |||
231 | static void __init bfin_gptmr0_clockevent_init(struct clock_event_device *evt) | ||
232 | { | ||
233 | unsigned long clock_tick; | ||
234 | |||
235 | clock_tick = get_sclk(); | ||
236 | evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); | ||
237 | evt->max_delta_ns = clockevent_delta2ns(-1, evt); | ||
238 | evt->min_delta_ns = clockevent_delta2ns(100, evt); | ||
239 | |||
240 | evt->cpumask = cpumask_of(0); | ||
241 | |||
242 | clockevents_register_device(evt); | ||
243 | } | ||
244 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
245 | |||
246 | #if defined(CONFIG_TICKSOURCE_CORETMR) | ||
247 | /* per-cpu local core timer */ | ||
248 | static DEFINE_PER_CPU(struct clock_event_device, coretmr_events); | ||
249 | |||
250 | static int bfin_coretmr_set_next_event(unsigned long cycles, | ||
246 | struct clock_event_device *evt) | 251 | struct clock_event_device *evt) |
247 | { | 252 | { |
248 | bfin_write_TCNTL(TMPWR); | 253 | bfin_write_TCNTL(TMPWR); |
@@ -253,7 +258,7 @@ static int bfin_timer_set_next_event(unsigned long cycles, | |||
253 | return 0; | 258 | return 0; |
254 | } | 259 | } |
255 | 260 | ||
256 | static void bfin_timer_set_mode(enum clock_event_mode mode, | 261 | static void bfin_coretmr_set_mode(enum clock_event_mode mode, |
257 | struct clock_event_device *evt) | 262 | struct clock_event_device *evt) |
258 | { | 263 | { |
259 | switch (mode) { | 264 | switch (mode) { |
@@ -285,19 +290,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode, | |||
285 | } | 290 | } |
286 | } | 291 | } |
287 | 292 | ||
288 | static void bfin_timer_ack(void) | 293 | void bfin_coretmr_init(void) |
289 | { | ||
290 | } | ||
291 | |||
292 | static void __init bfin_timer_init(void) | ||
293 | { | 294 | { |
294 | /* power up the timer, but don't enable it just yet */ | 295 | /* power up the timer, but don't enable it just yet */ |
295 | bfin_write_TCNTL(TMPWR); | 296 | bfin_write_TCNTL(TMPWR); |
296 | CSYNC(); | 297 | CSYNC(); |
297 | 298 | ||
298 | /* | 299 | /* the TSCALE prescaler counter. */ |
299 | * the TSCALE prescaler counter. | ||
300 | */ | ||
301 | bfin_write_TSCALE(TIME_SCALE - 1); | 300 | bfin_write_TSCALE(TIME_SCALE - 1); |
302 | bfin_write_TPERIOD(0); | 301 | bfin_write_TPERIOD(0); |
303 | bfin_write_TCOUNT(0); | 302 | bfin_write_TCOUNT(0); |
@@ -305,48 +304,54 @@ static void __init bfin_timer_init(void) | |||
305 | CSYNC(); | 304 | CSYNC(); |
306 | } | 305 | } |
307 | 306 | ||
308 | static unsigned long __init bfin_clockevent_check(void) | 307 | #ifdef CONFIG_CORE_TIMER_IRQ_L1 |
309 | { | 308 | __attribute__((l1_text)) |
310 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | 309 | #endif |
311 | return get_cclk() / TIME_SCALE; | 310 | irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id) |
312 | } | ||
313 | |||
314 | void __init setup_core_timer(void) | ||
315 | { | 311 | { |
316 | bfin_timer_init(); | 312 | int cpu = smp_processor_id(); |
317 | bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); | 313 | struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); |
318 | } | ||
319 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
320 | 314 | ||
321 | /* | ||
322 | * timer_interrupt() needs to keep up the real-time clock, | ||
323 | * as well as call the "do_timer()" routine every clocktick | ||
324 | */ | ||
325 | irqreturn_t timer_interrupt(int irq, void *dev_id) | ||
326 | { | ||
327 | struct clock_event_device *evt = dev_id; | ||
328 | smp_mb(); | 315 | smp_mb(); |
329 | evt->event_handler(evt); | 316 | evt->event_handler(evt); |
330 | bfin_timer_ack(); | ||
331 | return IRQ_HANDLED; | ||
332 | } | ||
333 | |||
334 | static int __init bfin_clockevent_init(void) | ||
335 | { | ||
336 | unsigned long timer_clk; | ||
337 | 317 | ||
338 | timer_clk = bfin_clockevent_check(); | 318 | touch_nmi_watchdog(); |
339 | 319 | ||
340 | bfin_timer_init(); | 320 | return IRQ_HANDLED; |
321 | } | ||
341 | 322 | ||
342 | clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); | 323 | static struct irqaction coretmr_irq = { |
343 | clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin); | 324 | .name = "Blackfin CoreTimer", |
344 | clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin); | 325 | .flags = IRQF_DISABLED | IRQF_TIMER | \ |
345 | clockevent_bfin.cpumask = cpumask_of(0); | 326 | IRQF_IRQPOLL | IRQF_PERCPU, |
346 | clockevents_register_device(&clockevent_bfin); | 327 | .handler = bfin_coretmr_interrupt, |
328 | }; | ||
347 | 329 | ||
348 | return 0; | 330 | void bfin_coretmr_clockevent_init(void) |
331 | { | ||
332 | unsigned long clock_tick; | ||
333 | unsigned int cpu = smp_processor_id(); | ||
334 | struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); | ||
335 | |||
336 | evt->name = "bfin_core_timer"; | ||
337 | evt->rating = 350; | ||
338 | evt->irq = -1; | ||
339 | evt->shift = 32; | ||
340 | evt->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT; | ||
341 | evt->set_next_event = bfin_coretmr_set_next_event; | ||
342 | evt->set_mode = bfin_coretmr_set_mode; | ||
343 | |||
344 | clock_tick = get_cclk() / TIME_SCALE; | ||
345 | evt->mult = div_sc(clock_tick, NSEC_PER_SEC, evt->shift); | ||
346 | evt->max_delta_ns = clockevent_delta2ns(-1, evt); | ||
347 | evt->min_delta_ns = clockevent_delta2ns(100, evt); | ||
348 | |||
349 | evt->cpumask = cpumask_of(cpu); | ||
350 | |||
351 | clockevents_register_device(evt); | ||
349 | } | 352 | } |
353 | #endif /* CONFIG_TICKSOURCE_CORETMR */ | ||
354 | |||
350 | 355 | ||
351 | void __init time_init(void) | 356 | void __init time_init(void) |
352 | { | 357 | { |
@@ -370,5 +375,21 @@ void __init time_init(void) | |||
370 | 375 | ||
371 | bfin_cs_cycles_init(); | 376 | bfin_cs_cycles_init(); |
372 | bfin_cs_gptimer0_init(); | 377 | bfin_cs_gptimer0_init(); |
373 | bfin_clockevent_init(); | 378 | |
379 | #if defined(CONFIG_TICKSOURCE_CORETMR) | ||
380 | bfin_coretmr_init(); | ||
381 | setup_irq(IRQ_CORETMR, &coretmr_irq); | ||
382 | bfin_coretmr_clockevent_init(); | ||
383 | #endif | ||
384 | |||
385 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
386 | bfin_gptmr0_init(); | ||
387 | setup_irq(IRQ_TIMER0, &gptmr0_irq); | ||
388 | gptmr0_irq.dev_id = &clockevent_gptmr0; | ||
389 | bfin_gptmr0_clockevent_init(&clockevent_gptmr0); | ||
390 | #endif | ||
391 | |||
392 | #if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0) | ||
393 | # error at least one clock event device is required | ||
394 | #endif | ||
374 | } | 395 | } |