diff options
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
-rw-r--r-- | arch/blackfin/kernel/time-ts.c | 214 |
1 files changed, 118 insertions, 96 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c index 17c38c5b5b22..8c9a43daf80f 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) | 152 | #if defined(CONFIG_TICKSOURCE_GPTMR0) |
177 | .name = "Blackfin GPTimer0", | 153 | static int bfin_gptmr0_set_next_event(unsigned long cycles, |
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) | ||
188 | static int bfin_timer_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 | }; | ||
220 | |||
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 | }; | ||
244 | 230 | ||
245 | static int bfin_timer_set_next_event(unsigned long cycles, | 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,52 +304,64 @@ 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 |
308 | __attribute__((l1_text)) | ||
309 | #endif | ||
310 | irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id) | ||
309 | { | 311 | { |
310 | setup_irq(IRQ_CORETMR, &bfin_timer_irq); | 312 | int cpu = smp_processor_id(); |
311 | return get_cclk() / TIME_SCALE; | 313 | struct clock_event_device *evt = &per_cpu(coretmr_events, cpu); |
312 | } | ||
313 | 314 | ||
314 | void __init setup_core_timer(void) | ||
315 | { | ||
316 | bfin_timer_init(); | ||
317 | bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); | ||
318 | } | ||
319 | #endif /* CONFIG_TICKSOURCE_GPTMR0 */ | ||
320 | |||
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(); | 317 | |
318 | touch_nmi_watchdog(); | ||
319 | |||
331 | return IRQ_HANDLED; | 320 | return IRQ_HANDLED; |
332 | } | 321 | } |
333 | 322 | ||
334 | static int __init bfin_clockevent_init(void) | 323 | static struct irqaction coretmr_irq = { |
335 | { | 324 | .name = "Blackfin CoreTimer", |
336 | unsigned long timer_clk; | 325 | .flags = IRQF_DISABLED | IRQF_TIMER | \ |
337 | 326 | IRQF_IRQPOLL | IRQF_PERCPU, | |
338 | timer_clk = bfin_clockevent_check(); | 327 | .handler = bfin_coretmr_interrupt, |
328 | }; | ||
339 | 329 | ||
340 | bfin_timer_init(); | 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); | ||
352 | } | ||
353 | #endif /* CONFIG_TICKSOURCE_CORETMR */ | ||
341 | 354 | ||
342 | clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); | ||
343 | clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin); | ||
344 | clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin); | ||
345 | clockevent_bfin.cpumask = cpumask_of(0); | ||
346 | clockevents_register_device(&clockevent_bfin); | ||
347 | 355 | ||
348 | return 0; | 356 | void read_persistent_clock(struct timespec *ts) |
357 | { | ||
358 | time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */ | ||
359 | ts->tv_sec = secs_since_1970; | ||
360 | ts->tv_nsec = 0; | ||
349 | } | 361 | } |
350 | 362 | ||
351 | void __init time_init(void) | 363 | void __init time_init(void) |
352 | { | 364 | { |
353 | time_t secs_since_1970 = (365 * 37 + 9) * 24 * 60 * 60; /* 1 Jan 2007 */ | ||
354 | 365 | ||
355 | #ifdef CONFIG_RTC_DRV_BFIN | 366 | #ifdef CONFIG_RTC_DRV_BFIN |
356 | /* [#2663] hack to filter junk RTC values that would cause | 367 | /* [#2663] hack to filter junk RTC values that would cause |
@@ -363,12 +374,23 @@ void __init time_init(void) | |||
363 | } | 374 | } |
364 | #endif | 375 | #endif |
365 | 376 | ||
366 | /* Initialize xtime. From now on, xtime is updated with timer interrupts */ | ||
367 | xtime.tv_sec = secs_since_1970; | ||
368 | xtime.tv_nsec = 0; | ||
369 | set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec); | ||
370 | |||
371 | bfin_cs_cycles_init(); | 377 | bfin_cs_cycles_init(); |
372 | bfin_cs_gptimer0_init(); | 378 | bfin_cs_gptimer0_init(); |
373 | bfin_clockevent_init(); | 379 | |
380 | #if defined(CONFIG_TICKSOURCE_CORETMR) | ||
381 | bfin_coretmr_init(); | ||
382 | setup_irq(IRQ_CORETMR, &coretmr_irq); | ||
383 | bfin_coretmr_clockevent_init(); | ||
384 | #endif | ||
385 | |||
386 | #if defined(CONFIG_TICKSOURCE_GPTMR0) | ||
387 | bfin_gptmr0_init(); | ||
388 | setup_irq(IRQ_TIMER0, &gptmr0_irq); | ||
389 | gptmr0_irq.dev_id = &clockevent_gptmr0; | ||
390 | bfin_gptmr0_clockevent_init(&clockevent_gptmr0); | ||
391 | #endif | ||
392 | |||
393 | #if !defined(CONFIG_TICKSOURCE_CORETMR) && !defined(CONFIG_TICKSOURCE_GPTMR0) | ||
394 | # error at least one clock event device is required | ||
395 | #endif | ||
374 | } | 396 | } |