aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/time.c
diff options
context:
space:
mode:
authorMark A. Greer <mgreer@mvista.com>2009-04-15 15:41:54 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2009-05-28 18:17:48 -0400
commit3abd5acfff0111809463bcfd7236a1bdf09e4e2d (patch)
tree19d2577a3b8dac0b15103baf32a5e2a7b9dc8c1b /arch/arm/mach-davinci/time.c
parent0b0c4c2a6974eae7b96066cb0da35b526fe58468 (diff)
davinci: Add compare register support to timer code
The Timer64p timer has 8 compare registers that can be used to generate interrupts when the timer value matches the compare reg's value. They do not disturb the timer itself. This can be useful when there is only one timer available for both clock events and clocksource. When enabled, the clocksource remains a continuous 32-bit counter but the clock event will no longer support periodic interrupts. Instead only oneshot timers will be supported and implemented by setting the compare register to the current timer value plus the period that the clock event subsystem is requesting. Compare registers support is enabled automatically when the following conditions are met: 1) The same timer is being used for clock events and clocksource. 2) The timer is the bottom half (32 bits) of the 64-bit timer (hardware limitation). 3) The the compare register offset and irq are not zero. Since the timer is always running, there is a hardware race in timer32_config() between reading the current timer value, and adding the period to the current timer value and writing the compare register. Testing on a da830 evm board with the timer clocked at 24 MHz and the processor clocked at 300 MHz, showed the number of counter ticks to do this ranged from 20-53 (~1-2.2 usecs) but usually around 41 ticks. This includes some artifacts from collecting the information. So, the minimum period should be at least 5 usecs to be safe. There is also an non-critical lower limit that the period should be since there is no point in setting an event that is much shorter than the time it takes to set the event, and get & handle the timer interrupt for that event. There can also be all sorts of delays from activities occuring elsewhere in the system (including hardware activitis like cache & TLB management). These are virtually impossible to quantify so a minimum period of 50 usecs was chosen. That will certianly be enough to avoid the actual hardware race but hopefully not large enough to cause unreasonably course-grained timers. Signed-off-by: Mark A. Greer <mgreer@mvista.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch/arm/mach-davinci/time.c')
-rw-r--r--arch/arm/mach-davinci/time.c141
1 files changed, 103 insertions, 38 deletions
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index f80ae25a52e4..fc90d3ee0eba 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -46,14 +46,24 @@ enum {
46}; 46};
47 47
48/* Timer register offsets */ 48/* Timer register offsets */
49#define PID12 0x0 49#define PID12 0x0
50#define TIM12 0x10 50#define TIM12 0x10
51#define TIM34 0x14 51#define TIM34 0x14
52#define PRD12 0x18 52#define PRD12 0x18
53#define PRD34 0x1c 53#define PRD34 0x1c
54#define TCR 0x20 54#define TCR 0x20
55#define TGCR 0x24 55#define TGCR 0x24
56#define WDTCR 0x28 56#define WDTCR 0x28
57
58/* Offsets of the 8 compare registers */
59#define CMP12_0 0x60
60#define CMP12_1 0x64
61#define CMP12_2 0x68
62#define CMP12_3 0x6c
63#define CMP12_4 0x70
64#define CMP12_5 0x74
65#define CMP12_6 0x78
66#define CMP12_7 0x7c
57 67
58/* Timer register bitfields */ 68/* Timer register bitfields */
59#define TCR_ENAMODE_DISABLE 0x0 69#define TCR_ENAMODE_DISABLE 0x0
@@ -85,6 +95,7 @@ struct timer_s {
85 unsigned int id; 95 unsigned int id;
86 unsigned long period; 96 unsigned long period;
87 unsigned long opts; 97 unsigned long opts;
98 unsigned long flags;
88 void __iomem *base; 99 void __iomem *base;
89 unsigned long tim_off; 100 unsigned long tim_off;
90 unsigned long prd_off; 101 unsigned long prd_off;
@@ -94,9 +105,13 @@ struct timer_s {
94static struct timer_s timers[]; 105static struct timer_s timers[];
95 106
96/* values for 'opts' field of struct timer_s */ 107/* values for 'opts' field of struct timer_s */
97#define TIMER_OPTS_DISABLED 0x00 108#define TIMER_OPTS_DISABLED 0x01
98#define TIMER_OPTS_ONESHOT 0x01 109#define TIMER_OPTS_ONESHOT 0x02
99#define TIMER_OPTS_PERIODIC 0x02 110#define TIMER_OPTS_PERIODIC 0x04
111#define TIMER_OPTS_STATE_MASK 0x07
112
113#define TIMER_OPTS_USE_COMPARE 0x80000000
114#define USING_COMPARE(t) ((t)->opts & TIMER_OPTS_USE_COMPARE)
100 115
101static char *id_to_name[] = { 116static char *id_to_name[] = {
102 [T0_BOT] = "timer0_0", 117 [T0_BOT] = "timer0_0",
@@ -107,24 +122,41 @@ static char *id_to_name[] = {
107 122
108static int timer32_config(struct timer_s *t) 123static int timer32_config(struct timer_s *t)
109{ 124{
110 u32 tcr = __raw_readl(t->base + TCR); 125 u32 tcr;
111 126 struct davinci_soc_info *soc_info = davinci_get_soc_info();
112 /* disable timer */ 127
113 tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); 128 if (USING_COMPARE(t)) {
114 __raw_writel(tcr, t->base + TCR); 129 struct davinci_timer_instance *dtip =
115 130 soc_info->timer_info->timers;
116 /* reset counter to zero, set new period */ 131 int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id);
117 __raw_writel(0, t->base + t->tim_off); 132
118 __raw_writel(t->period, t->base + t->prd_off); 133 /*
119 134 * Next interrupt should be the current time reg value plus
120 /* Set enable mode */ 135 * the new period (using 32-bit unsigned addition/wrapping
121 if (t->opts & TIMER_OPTS_ONESHOT) { 136 * to 0 on overflow). This assumes that the clocksource
122 tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift; 137 * is setup to count to 2^32-1 before wrapping around to 0.
123 } else if (t->opts & TIMER_OPTS_PERIODIC) { 138 */
124 tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; 139 __raw_writel(__raw_readl(t->base + t->tim_off) + t->period,
140 t->base + dtip[event_timer].cmp_off);
141 } else {
142 tcr = __raw_readl(t->base + TCR);
143
144 /* disable timer */
145 tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
146 __raw_writel(tcr, t->base + TCR);
147
148 /* reset counter to zero, set new period */
149 __raw_writel(0, t->base + t->tim_off);
150 __raw_writel(t->period, t->base + t->prd_off);
151
152 /* Set enable mode */
153 if (t->opts & TIMER_OPTS_ONESHOT)
154 tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
155 else if (t->opts & TIMER_OPTS_PERIODIC)
156 tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
157
158 __raw_writel(tcr, t->base + TCR);
125 } 159 }
126
127 __raw_writel(tcr, t->base + TCR);
128 return 0; 160 return 0;
129} 161}
130 162
@@ -222,8 +254,11 @@ static void __init timer_init(void)
222 /* Register interrupt */ 254 /* Register interrupt */
223 t->irqaction.name = t->name; 255 t->irqaction.name = t->name;
224 t->irqaction.dev_id = (void *)t; 256 t->irqaction.dev_id = (void *)t;
225 if (t->irqaction.handler != NULL) 257
258 if (t->irqaction.handler != NULL) {
259 irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq;
226 setup_irq(irq, &t->irqaction); 260 setup_irq(irq, &t->irqaction);
261 }
227 262
228 timer32_config(&timers[i]); 263 timer32_config(&timers[i]);
229 } 264 }
@@ -268,15 +303,18 @@ static void davinci_set_mode(enum clock_event_mode mode,
268 switch (mode) { 303 switch (mode) {
269 case CLOCK_EVT_MODE_PERIODIC: 304 case CLOCK_EVT_MODE_PERIODIC:
270 t->period = davinci_clock_tick_rate / (HZ); 305 t->period = davinci_clock_tick_rate / (HZ);
271 t->opts = TIMER_OPTS_PERIODIC; 306 t->opts &= ~TIMER_OPTS_STATE_MASK;
307 t->opts |= TIMER_OPTS_PERIODIC;
272 timer32_config(t); 308 timer32_config(t);
273 break; 309 break;
274 case CLOCK_EVT_MODE_ONESHOT: 310 case CLOCK_EVT_MODE_ONESHOT:
275 t->opts = TIMER_OPTS_ONESHOT; 311 t->opts &= ~TIMER_OPTS_STATE_MASK;
312 t->opts |= TIMER_OPTS_ONESHOT;
276 break; 313 break;
277 case CLOCK_EVT_MODE_UNUSED: 314 case CLOCK_EVT_MODE_UNUSED:
278 case CLOCK_EVT_MODE_SHUTDOWN: 315 case CLOCK_EVT_MODE_SHUTDOWN:
279 t->opts = TIMER_OPTS_DISABLED; 316 t->opts &= ~TIMER_OPTS_STATE_MASK;
317 t->opts |= TIMER_OPTS_DISABLED;
280 break; 318 break;
281 case CLOCK_EVT_MODE_RESUME: 319 case CLOCK_EVT_MODE_RESUME:
282 break; 320 break;
@@ -295,12 +333,40 @@ static void __init davinci_timer_init(void)
295{ 333{
296 struct clk *timer_clk; 334 struct clk *timer_clk;
297 struct davinci_soc_info *soc_info = &davinci_soc_info; 335 struct davinci_soc_info *soc_info = &davinci_soc_info;
298 336 unsigned int clockevent_id;
337 unsigned int clocksource_id;
299 static char err[] __initdata = KERN_ERR 338 static char err[] __initdata = KERN_ERR
300 "%s: can't register clocksource!\n"; 339 "%s: can't register clocksource!\n";
301 340
302 timers[TID_CLOCKEVENT].id = soc_info->timer_info->clockevent_id; 341 clockevent_id = soc_info->timer_info->clockevent_id;
303 timers[TID_CLOCKSOURCE].id = soc_info->timer_info->clocksource_id; 342 clocksource_id = soc_info->timer_info->clocksource_id;
343
344 timers[TID_CLOCKEVENT].id = clockevent_id;
345 timers[TID_CLOCKSOURCE].id = clocksource_id;
346
347 /*
348 * If using same timer for both clock events & clocksource,
349 * a compare register must be used to generate an event interrupt.
350 * This is equivalent to a oneshot timer only (not periodic).
351 */
352 if (clockevent_id == clocksource_id) {
353 struct davinci_timer_instance *dtip =
354 soc_info->timer_info->timers;
355 int event_timer = ID_TO_TIMER(clockevent_id);
356
357 /* Only bottom timers can use compare regs */
358 if (IS_TIMER_TOP(clockevent_id))
359 pr_warning("davinci_timer_init: Invalid use"
360 " of system timers. Results unpredictable.\n");
361 else if ((dtip[event_timer].cmp_off == 0)
362 || (dtip[event_timer].cmp_irq == 0))
363 pr_warning("davinci_timer_init: Invalid timer instance"
364 " setup. Results unpredictable.\n");
365 else {
366 timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
367 clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
368 }
369 }
304 370
305 /* init timer hw */ 371 /* init timer hw */
306 timer_init(); 372 timer_init();
@@ -312,7 +378,7 @@ static void __init davinci_timer_init(void)
312 davinci_clock_tick_rate = clk_get_rate(timer_clk); 378 davinci_clock_tick_rate = clk_get_rate(timer_clk);
313 379
314 /* setup clocksource */ 380 /* setup clocksource */
315 clocksource_davinci.name = id_to_name[timers[TID_CLOCKSOURCE].id]; 381 clocksource_davinci.name = id_to_name[clocksource_id];
316 clocksource_davinci.mult = 382 clocksource_davinci.mult =
317 clocksource_khz2mult(davinci_clock_tick_rate/1000, 383 clocksource_khz2mult(davinci_clock_tick_rate/1000,
318 clocksource_davinci.shift); 384 clocksource_davinci.shift);
@@ -325,8 +391,7 @@ static void __init davinci_timer_init(void)
325 clockevent_davinci.shift); 391 clockevent_davinci.shift);
326 clockevent_davinci.max_delta_ns = 392 clockevent_davinci.max_delta_ns =
327 clockevent_delta2ns(0xfffffffe, &clockevent_davinci); 393 clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
328 clockevent_davinci.min_delta_ns = 394 clockevent_davinci.min_delta_ns = 50000; /* 50 usec */
329 clockevent_delta2ns(1, &clockevent_davinci);
330 395
331 clockevent_davinci.cpumask = cpumask_of(0); 396 clockevent_davinci.cpumask = cpumask_of(0);
332 clockevents_register_device(&clockevent_davinci); 397 clockevents_register_device(&clockevent_davinci);