aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin/kernel/time-ts.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/blackfin/kernel/time-ts.c')
-rw-r--r--arch/blackfin/kernel/time-ts.c242
1 files changed, 135 insertions, 107 deletions
diff --git a/arch/blackfin/kernel/time-ts.c b/arch/blackfin/kernel/time-ts.c
index 359cfb1815ca..cb7a01d4f009 100644
--- a/arch/blackfin/kernel/time-ts.c
+++ b/arch/blackfin/kernel/time-ts.c
@@ -21,8 +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 24#include <asm/nmi.h>
25#if defined(CONFIG_CYCLES_CLOCKSOURCE)
26 25
27/* Accelerators for sched_clock() 26/* Accelerators for sched_clock()
28 * convert from cycles(64bits) => nanoseconds (64bits) 27 * convert from cycles(64bits) => nanoseconds (64bits)
@@ -46,22 +45,17 @@
46 * -johnstul@us.ibm.com "math is hard, lets go shopping!" 45 * -johnstul@us.ibm.com "math is hard, lets go shopping!"
47 */ 46 */
48 47
49static unsigned long cyc2ns_scale;
50#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */ 48#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */
51 49
52static inline void set_cyc2ns_scale(unsigned long cpu_khz) 50#if defined(CONFIG_CYCLES_CLOCKSOURCE)
53{
54 cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR) / cpu_khz;
55}
56
57static inline unsigned long long cycles_2_ns(cycle_t cyc)
58{
59 return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;
60}
61 51
62static cycle_t bfin_read_cycles(struct clocksource *cs) 52static notrace cycle_t bfin_read_cycles(struct clocksource *cs)
63{ 53{
54#ifdef CONFIG_CPU_FREQ
64 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
65} 59}
66 60
67static struct clocksource bfin_cs_cycles = { 61static struct clocksource bfin_cs_cycles = {
@@ -69,19 +63,18 @@ static struct clocksource bfin_cs_cycles = {
69 .rating = 400, 63 .rating = 400,
70 .read = bfin_read_cycles, 64 .read = bfin_read_cycles,
71 .mask = CLOCKSOURCE_MASK(64), 65 .mask = CLOCKSOURCE_MASK(64),
72 .shift = 22, 66 .shift = CYC2NS_SCALE_FACTOR,
73 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 67 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
74}; 68};
75 69
76unsigned long long sched_clock(void) 70static inline unsigned long long bfin_cs_cycles_sched_clock(void)
77{ 71{
78 return cycles_2_ns(bfin_read_cycles(&bfin_cs_cycles)); 72 return clocksource_cyc2ns(bfin_read_cycles(&bfin_cs_cycles),
73 bfin_cs_cycles.mult, bfin_cs_cycles.shift);
79} 74}
80 75
81static int __init bfin_cs_cycles_init(void) 76static int __init bfin_cs_cycles_init(void)
82{ 77{
83 set_cyc2ns_scale(get_cclk() / 1000);
84
85 bfin_cs_cycles.mult = \ 78 bfin_cs_cycles.mult = \
86 clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift); 79 clocksource_hz2mult(get_cclk(), bfin_cs_cycles.shift);
87 80
@@ -108,7 +101,7 @@ void __init setup_gptimer0(void)
108 enable_gptimers(TIMER0bit); 101 enable_gptimers(TIMER0bit);
109} 102}
110 103
111static cycle_t bfin_read_gptimer0(void) 104static cycle_t bfin_read_gptimer0(struct clocksource *cs)
112{ 105{
113 return bfin_read_TIMER0_COUNTER(); 106 return bfin_read_TIMER0_COUNTER();
114} 107}
@@ -118,10 +111,16 @@ static struct clocksource bfin_cs_gptimer0 = {
118 .rating = 350, 111 .rating = 350,
119 .read = bfin_read_gptimer0, 112 .read = bfin_read_gptimer0,
120 .mask = CLOCKSOURCE_MASK(32), 113 .mask = CLOCKSOURCE_MASK(32),
121 .shift = 22, 114 .shift = CYC2NS_SCALE_FACTOR,
122 .flags = CLOCK_SOURCE_IS_CONTINUOUS, 115 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
123}; 116};
124 117
118static inline unsigned long long bfin_cs_gptimer0_sched_clock(void)
119{
120 return clocksource_cyc2ns(bfin_read_TIMER0_COUNTER(),
121 bfin_cs_gptimer0.mult, bfin_cs_gptimer0.shift);
122}
123
125static int __init bfin_cs_gptimer0_init(void) 124static int __init bfin_cs_gptimer0_init(void)
126{ 125{
127 setup_gptimer0(); 126 setup_gptimer0();
@@ -138,47 +137,20 @@ static int __init bfin_cs_gptimer0_init(void)
138# define bfin_cs_gptimer0_init() 137# define bfin_cs_gptimer0_init()
139#endif 138#endif
140 139
141#ifdef CONFIG_CORE_TIMER_IRQ_L1 140#if defined(CONFIG_GPTMR0_CLOCKSOURCE) || defined(CONFIG_CYCLES_CLOCKSOURCE)
142__attribute__((l1_text)) 141/* prefer to use cycles since it has higher rating */
143#endif 142notrace unsigned long long sched_clock(void)
144irqreturn_t timer_interrupt(int irq, void *dev_id); 143{
145 144#if defined(CONFIG_CYCLES_CLOCKSOURCE)
146static int bfin_timer_set_next_event(unsigned long, \ 145 return bfin_cs_cycles_sched_clock();
147 struct clock_event_device *);
148
149static void bfin_timer_set_mode(enum clock_event_mode, \
150 struct clock_event_device *);
151
152static struct clock_event_device clockevent_bfin = {
153#if defined(CONFIG_TICKSOURCE_GPTMR0)
154 .name = "bfin_gptimer0",
155 .rating = 300,
156 .irq = IRQ_TIMER0,
157#else 146#else
158 .name = "bfin_core_timer", 147 return bfin_cs_gptimer0_sched_clock();
159 .rating = 350,
160 .irq = IRQ_CORETMR,
161#endif 148#endif
162 .shift = 32, 149}
163 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
164 .set_next_event = bfin_timer_set_next_event,
165 .set_mode = bfin_timer_set_mode,
166};
167
168static struct irqaction bfin_timer_irq = {
169#if defined(CONFIG_TICKSOURCE_GPTMR0)
170 .name = "Blackfin GPTimer0",
171#else
172 .name = "Blackfin CoreTimer",
173#endif 150#endif
174 .flags = IRQF_DISABLED | IRQF_TIMER | \
175 IRQF_IRQPOLL | IRQF_PERCPU,
176 .handler = timer_interrupt,
177 .dev_id = &clockevent_bfin,
178};
179 151
180#if defined(CONFIG_TICKSOURCE_GPTMR0) 152#if defined(CONFIG_TICKSOURCE_GPTMR0)
181static int bfin_timer_set_next_event(unsigned long cycles, 153static int bfin_gptmr0_set_next_event(unsigned long cycles,
182 struct clock_event_device *evt) 154 struct clock_event_device *evt)
183{ 155{
184 disable_gptimers(TIMER0bit); 156 disable_gptimers(TIMER0bit);
@@ -189,7 +161,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
189 return 0; 161 return 0;
190} 162}
191 163
192static void bfin_timer_set_mode(enum clock_event_mode mode, 164static void bfin_gptmr0_set_mode(enum clock_event_mode mode,
193 struct clock_event_device *evt) 165 struct clock_event_device *evt)
194{ 166{
195 switch (mode) { 167 switch (mode) {
@@ -217,25 +189,65 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
217 } 189 }
218} 190}
219 191
220static void bfin_timer_ack(void) 192static void bfin_gptmr0_ack(void)
221{ 193{
222 set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0); 194 set_gptimer_status(TIMER_GROUP1, TIMER_STATUS_TIMIL0);
223} 195}
224 196
225static void __init bfin_timer_init(void) 197static void __init bfin_gptmr0_init(void)
226{ 198{
227 disable_gptimers(TIMER0bit); 199 disable_gptimers(TIMER0bit);
228} 200}
229 201
230static unsigned long __init bfin_clockevent_check(void) 202#ifdef CONFIG_CORE_TIMER_IRQ_L1
203__attribute__((l1_text))
204#endif
205irqreturn_t bfin_gptmr0_interrupt(int irq, void *dev_id)
231{ 206{
232 setup_irq(IRQ_TIMER0, &bfin_timer_irq); 207 struct clock_event_device *evt = dev_id;
233 return get_sclk(); 208 smp_mb();
209 evt->event_handler(evt);
210 bfin_gptmr0_ack();
211 return IRQ_HANDLED;
234} 212}
235 213
236#else /* CONFIG_TICKSOURCE_CORETMR */ 214static 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};
237 220
238static int bfin_timer_set_next_event(unsigned long cycles, 221static 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
231static 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 */
248static DEFINE_PER_CPU(struct clock_event_device, coretmr_events);
249
250static int bfin_coretmr_set_next_event(unsigned long cycles,
239 struct clock_event_device *evt) 251 struct clock_event_device *evt)
240{ 252{
241 bfin_write_TCNTL(TMPWR); 253 bfin_write_TCNTL(TMPWR);
@@ -246,7 +258,7 @@ static int bfin_timer_set_next_event(unsigned long cycles,
246 return 0; 258 return 0;
247} 259}
248 260
249static void bfin_timer_set_mode(enum clock_event_mode mode, 261static void bfin_coretmr_set_mode(enum clock_event_mode mode,
250 struct clock_event_device *evt) 262 struct clock_event_device *evt)
251{ 263{
252 switch (mode) { 264 switch (mode) {
@@ -278,19 +290,13 @@ static void bfin_timer_set_mode(enum clock_event_mode mode,
278 } 290 }
279} 291}
280 292
281static void bfin_timer_ack(void) 293void bfin_coretmr_init(void)
282{
283}
284
285static void __init bfin_timer_init(void)
286{ 294{
287 /* power up the timer, but don't enable it just yet */ 295 /* power up the timer, but don't enable it just yet */
288 bfin_write_TCNTL(TMPWR); 296 bfin_write_TCNTL(TMPWR);
289 CSYNC(); 297 CSYNC();
290 298
291 /* 299 /* the TSCALE prescaler counter. */
292 * the TSCALE prescaler counter.
293 */
294 bfin_write_TSCALE(TIME_SCALE - 1); 300 bfin_write_TSCALE(TIME_SCALE - 1);
295 bfin_write_TPERIOD(0); 301 bfin_write_TPERIOD(0);
296 bfin_write_TCOUNT(0); 302 bfin_write_TCOUNT(0);
@@ -298,48 +304,54 @@ static void __init bfin_timer_init(void)
298 CSYNC(); 304 CSYNC();
299} 305}
300 306
301static unsigned long __init bfin_clockevent_check(void) 307#ifdef CONFIG_CORE_TIMER_IRQ_L1
302{ 308__attribute__((l1_text))
303 setup_irq(IRQ_CORETMR, &bfin_timer_irq); 309#endif
304 return get_cclk() / TIME_SCALE; 310irqreturn_t bfin_coretmr_interrupt(int irq, void *dev_id)
305}
306
307void __init setup_core_timer(void)
308{ 311{
309 bfin_timer_init(); 312 int cpu = smp_processor_id();
310 bfin_timer_set_mode(CLOCK_EVT_MODE_PERIODIC, NULL); 313 struct clock_event_device *evt = &per_cpu(coretmr_events, cpu);
311}
312#endif /* CONFIG_TICKSOURCE_GPTMR0 */
313 314
314/*
315 * timer_interrupt() needs to keep up the real-time clock,
316 * as well as call the "do_timer()" routine every clocktick
317 */
318irqreturn_t timer_interrupt(int irq, void *dev_id)
319{
320 struct clock_event_device *evt = dev_id;
321 smp_mb(); 315 smp_mb();
322 evt->event_handler(evt); 316 evt->event_handler(evt);
323 bfin_timer_ack();
324 return IRQ_HANDLED;
325}
326 317
327static int __init bfin_clockevent_init(void) 318 touch_nmi_watchdog();
328{
329 unsigned long timer_clk;
330
331 timer_clk = bfin_clockevent_check();
332 319
333 bfin_timer_init(); 320 return IRQ_HANDLED;
321}
334 322
335 clockevent_bfin.mult = div_sc(timer_clk, NSEC_PER_SEC, clockevent_bfin.shift); 323static struct irqaction coretmr_irq = {
336 clockevent_bfin.max_delta_ns = clockevent_delta2ns(-1, &clockevent_bfin); 324 .name = "Blackfin CoreTimer",
337 clockevent_bfin.min_delta_ns = clockevent_delta2ns(100, &clockevent_bfin); 325 .flags = IRQF_DISABLED | IRQF_TIMER | \
338 clockevent_bfin.cpumask = cpumask_of(0); 326 IRQF_IRQPOLL | IRQF_PERCPU,
339 clockevents_register_device(&clockevent_bfin); 327 .handler = bfin_coretmr_interrupt,
328};
340 329
341 return 0; 330void 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);
342} 352}
353#endif /* CONFIG_TICKSOURCE_CORETMR */
354
343 355
344void __init time_init(void) 356void __init time_init(void)
345{ 357{
@@ -363,5 +375,21 @@ void __init time_init(void)
363 375
364 bfin_cs_cycles_init(); 376 bfin_cs_cycles_init();
365 bfin_cs_gptimer0_init(); 377 bfin_cs_gptimer0_init();
366 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
367} 395}