aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-davinci/time.c
diff options
context:
space:
mode:
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);