Commit | Line | Data |
---|---|---|
7c6337e2 KH |
1 | /* |
2 | * DaVinci timer subsystem | |
3 | * | |
4 | * Author: Kevin Hilman, MontaVista Software, Inc. <source@mvista.com> | |
5 | * | |
6 | * 2007 (c) MontaVista Software, Inc. This file is licensed under | |
7 | * the terms of the GNU General Public License version 2. This program | |
8 | * is licensed "as is" without any warranty of any kind, whether express | |
9 | * or implied. | |
10 | */ | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/init.h> | |
13 | #include <linux/types.h> | |
14 | #include <linux/interrupt.h> | |
15 | #include <linux/clocksource.h> | |
16 | #include <linux/clockchips.h> | |
fced80c7 | 17 | #include <linux/io.h> |
f5c122da KH |
18 | #include <linux/clk.h> |
19 | #include <linux/err.h> | |
fb631387 | 20 | #include <linux/platform_device.h> |
7c6337e2 | 21 | |
a09e64fb | 22 | #include <mach/hardware.h> |
7c6337e2 KH |
23 | #include <asm/mach/irq.h> |
24 | #include <asm/mach/time.h> | |
f5c122da | 25 | #include <mach/cputype.h> |
f64691b3 | 26 | #include <mach/time.h> |
f5c122da | 27 | #include "clock.h" |
7c6337e2 KH |
28 | |
29 | static struct clock_event_device clockevent_davinci; | |
e6099002 | 30 | static unsigned int davinci_clock_tick_rate; |
7c6337e2 | 31 | |
7c6337e2 KH |
32 | /* |
33 | * This driver configures the 2 64-bit count-up timers as 4 independent | |
34 | * 32-bit count-up timers used as follows: | |
7c6337e2 | 35 | */ |
f64691b3 MG |
36 | |
37 | enum { | |
38 | TID_CLOCKEVENT, | |
39 | TID_CLOCKSOURCE, | |
40 | }; | |
7c6337e2 KH |
41 | |
42 | /* Timer register offsets */ | |
3abd5acf MG |
43 | #define PID12 0x0 |
44 | #define TIM12 0x10 | |
45 | #define TIM34 0x14 | |
46 | #define PRD12 0x18 | |
47 | #define PRD34 0x1c | |
48 | #define TCR 0x20 | |
49 | #define TGCR 0x24 | |
50 | #define WDTCR 0x28 | |
51 | ||
52 | /* Offsets of the 8 compare registers */ | |
53 | #define CMP12_0 0x60 | |
54 | #define CMP12_1 0x64 | |
55 | #define CMP12_2 0x68 | |
56 | #define CMP12_3 0x6c | |
57 | #define CMP12_4 0x70 | |
58 | #define CMP12_5 0x74 | |
59 | #define CMP12_6 0x78 | |
60 | #define CMP12_7 0x7c | |
7c6337e2 KH |
61 | |
62 | /* Timer register bitfields */ | |
63 | #define TCR_ENAMODE_DISABLE 0x0 | |
64 | #define TCR_ENAMODE_ONESHOT 0x1 | |
65 | #define TCR_ENAMODE_PERIODIC 0x2 | |
66 | #define TCR_ENAMODE_MASK 0x3 | |
67 | ||
68 | #define TGCR_TIMMODE_SHIFT 2 | |
69 | #define TGCR_TIMMODE_64BIT_GP 0x0 | |
70 | #define TGCR_TIMMODE_32BIT_UNCHAINED 0x1 | |
71 | #define TGCR_TIMMODE_64BIT_WDOG 0x2 | |
72 | #define TGCR_TIMMODE_32BIT_CHAINED 0x3 | |
73 | ||
74 | #define TGCR_TIM12RS_SHIFT 0 | |
75 | #define TGCR_TIM34RS_SHIFT 1 | |
76 | #define TGCR_RESET 0x0 | |
77 | #define TGCR_UNRESET 0x1 | |
78 | #define TGCR_RESET_MASK 0x3 | |
79 | ||
80 | #define WDTCR_WDEN_SHIFT 14 | |
81 | #define WDTCR_WDEN_DISABLE 0x0 | |
82 | #define WDTCR_WDEN_ENABLE 0x1 | |
83 | #define WDTCR_WDKEY_SHIFT 16 | |
84 | #define WDTCR_WDKEY_SEQ0 0xa5c6 | |
85 | #define WDTCR_WDKEY_SEQ1 0xda7e | |
86 | ||
87 | struct timer_s { | |
88 | char *name; | |
89 | unsigned int id; | |
90 | unsigned long period; | |
91 | unsigned long opts; | |
3abd5acf | 92 | unsigned long flags; |
f5c122da KH |
93 | void __iomem *base; |
94 | unsigned long tim_off; | |
95 | unsigned long prd_off; | |
7c6337e2 KH |
96 | unsigned long enamode_shift; |
97 | struct irqaction irqaction; | |
98 | }; | |
99 | static struct timer_s timers[]; | |
100 | ||
101 | /* values for 'opts' field of struct timer_s */ | |
3abd5acf MG |
102 | #define TIMER_OPTS_DISABLED 0x01 |
103 | #define TIMER_OPTS_ONESHOT 0x02 | |
104 | #define TIMER_OPTS_PERIODIC 0x04 | |
105 | #define TIMER_OPTS_STATE_MASK 0x07 | |
106 | ||
107 | #define TIMER_OPTS_USE_COMPARE 0x80000000 | |
108 | #define USING_COMPARE(t) ((t)->opts & TIMER_OPTS_USE_COMPARE) | |
7c6337e2 | 109 | |
f64691b3 MG |
110 | static char *id_to_name[] = { |
111 | [T0_BOT] = "timer0_0", | |
112 | [T0_TOP] = "timer0_1", | |
113 | [T1_BOT] = "timer1_0", | |
114 | [T1_TOP] = "timer1_1", | |
115 | }; | |
116 | ||
7c6337e2 KH |
117 | static int timer32_config(struct timer_s *t) |
118 | { | |
3abd5acf | 119 | u32 tcr; |
5570078c | 120 | struct davinci_soc_info *soc_info = &davinci_soc_info; |
3abd5acf MG |
121 | |
122 | if (USING_COMPARE(t)) { | |
123 | struct davinci_timer_instance *dtip = | |
124 | soc_info->timer_info->timers; | |
125 | int event_timer = ID_TO_TIMER(timers[TID_CLOCKEVENT].id); | |
126 | ||
127 | /* | |
128 | * Next interrupt should be the current time reg value plus | |
129 | * the new period (using 32-bit unsigned addition/wrapping | |
130 | * to 0 on overflow). This assumes that the clocksource | |
131 | * is setup to count to 2^32-1 before wrapping around to 0. | |
132 | */ | |
133 | __raw_writel(__raw_readl(t->base + t->tim_off) + t->period, | |
134 | t->base + dtip[event_timer].cmp_off); | |
135 | } else { | |
136 | tcr = __raw_readl(t->base + TCR); | |
137 | ||
138 | /* disable timer */ | |
139 | tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift); | |
140 | __raw_writel(tcr, t->base + TCR); | |
141 | ||
142 | /* reset counter to zero, set new period */ | |
143 | __raw_writel(0, t->base + t->tim_off); | |
144 | __raw_writel(t->period, t->base + t->prd_off); | |
145 | ||
146 | /* Set enable mode */ | |
147 | if (t->opts & TIMER_OPTS_ONESHOT) | |
148 | tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift; | |
149 | else if (t->opts & TIMER_OPTS_PERIODIC) | |
150 | tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift; | |
151 | ||
152 | __raw_writel(tcr, t->base + TCR); | |
7c6337e2 | 153 | } |
7c6337e2 KH |
154 | return 0; |
155 | } | |
156 | ||
157 | static inline u32 timer32_read(struct timer_s *t) | |
158 | { | |
f5c122da | 159 | return __raw_readl(t->base + t->tim_off); |
7c6337e2 KH |
160 | } |
161 | ||
162 | static irqreturn_t timer_interrupt(int irq, void *dev_id) | |
163 | { | |
164 | struct clock_event_device *evt = &clockevent_davinci; | |
165 | ||
166 | evt->event_handler(evt); | |
167 | return IRQ_HANDLED; | |
168 | } | |
169 | ||
170 | /* called when 32-bit counter wraps */ | |
171 | static irqreturn_t freerun_interrupt(int irq, void *dev_id) | |
172 | { | |
173 | return IRQ_HANDLED; | |
174 | } | |
175 | ||
176 | static struct timer_s timers[] = { | |
177 | [TID_CLOCKEVENT] = { | |
178 | .name = "clockevent", | |
179 | .opts = TIMER_OPTS_DISABLED, | |
180 | .irqaction = { | |
181 | .flags = IRQF_DISABLED | IRQF_TIMER, | |
182 | .handler = timer_interrupt, | |
183 | } | |
184 | }, | |
185 | [TID_CLOCKSOURCE] = { | |
186 | .name = "free-run counter", | |
187 | .period = ~0, | |
188 | .opts = TIMER_OPTS_PERIODIC, | |
189 | .irqaction = { | |
190 | .flags = IRQF_DISABLED | IRQF_TIMER, | |
191 | .handler = freerun_interrupt, | |
192 | } | |
193 | }, | |
194 | }; | |
195 | ||
196 | static void __init timer_init(void) | |
197 | { | |
f64691b3 MG |
198 | struct davinci_soc_info *soc_info = &davinci_soc_info; |
199 | struct davinci_timer_instance *dtip = soc_info->timer_info->timers; | |
1bcd38ad | 200 | void __iomem *base[2]; |
7c6337e2 KH |
201 | int i; |
202 | ||
203 | /* Global init of each 64-bit timer as a whole */ | |
204 | for(i=0; i<2; i++) { | |
f5c122da | 205 | u32 tgcr; |
1bcd38ad CC |
206 | |
207 | base[i] = ioremap(dtip[i].base, SZ_4K); | |
208 | if (WARN_ON(!base[i])) | |
209 | continue; | |
7c6337e2 KH |
210 | |
211 | /* Disabled, Internal clock source */ | |
1bcd38ad | 212 | __raw_writel(0, base[i] + TCR); |
7c6337e2 KH |
213 | |
214 | /* reset both timers, no pre-scaler for timer34 */ | |
215 | tgcr = 0; | |
1bcd38ad | 216 | __raw_writel(tgcr, base[i] + TGCR); |
7c6337e2 KH |
217 | |
218 | /* Set both timers to unchained 32-bit */ | |
219 | tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT; | |
1bcd38ad | 220 | __raw_writel(tgcr, base[i] + TGCR); |
7c6337e2 KH |
221 | |
222 | /* Unreset timers */ | |
223 | tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | | |
224 | (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); | |
1bcd38ad | 225 | __raw_writel(tgcr, base[i] + TGCR); |
7c6337e2 KH |
226 | |
227 | /* Init both counters to zero */ | |
1bcd38ad CC |
228 | __raw_writel(0, base[i] + TIM12); |
229 | __raw_writel(0, base[i] + TIM34); | |
7c6337e2 KH |
230 | } |
231 | ||
232 | /* Init of each timer as a 32-bit timer */ | |
233 | for (i=0; i< ARRAY_SIZE(timers); i++) { | |
234 | struct timer_s *t = &timers[i]; | |
f64691b3 MG |
235 | int timer = ID_TO_TIMER(t->id); |
236 | u32 irq; | |
237 | ||
1bcd38ad CC |
238 | t->base = base[timer]; |
239 | if (!t->base) | |
240 | continue; | |
f64691b3 MG |
241 | |
242 | if (IS_TIMER_BOT(t->id)) { | |
243 | t->enamode_shift = 6; | |
244 | t->tim_off = TIM12; | |
245 | t->prd_off = PRD12; | |
246 | irq = dtip[timer].bottom_irq; | |
247 | } else { | |
248 | t->enamode_shift = 22; | |
249 | t->tim_off = TIM34; | |
250 | t->prd_off = PRD34; | |
251 | irq = dtip[timer].top_irq; | |
7c6337e2 | 252 | } |
f64691b3 MG |
253 | |
254 | /* Register interrupt */ | |
255 | t->irqaction.name = t->name; | |
256 | t->irqaction.dev_id = (void *)t; | |
3abd5acf MG |
257 | |
258 | if (t->irqaction.handler != NULL) { | |
259 | irq = USING_COMPARE(t) ? dtip[i].cmp_irq : irq; | |
f64691b3 | 260 | setup_irq(irq, &t->irqaction); |
3abd5acf | 261 | } |
7c6337e2 KH |
262 | } |
263 | } | |
264 | ||
265 | /* | |
266 | * clocksource | |
267 | */ | |
8e19608e | 268 | static cycle_t read_cycles(struct clocksource *cs) |
7c6337e2 KH |
269 | { |
270 | struct timer_s *t = &timers[TID_CLOCKSOURCE]; | |
271 | ||
272 | return (cycles_t)timer32_read(t); | |
273 | } | |
274 | ||
6d1c57c8 AG |
275 | /* |
276 | * Kernel assumes that sched_clock can be called early but may not have | |
277 | * things ready yet. | |
278 | */ | |
279 | static cycle_t read_dummy(struct clocksource *cs) | |
280 | { | |
281 | return 0; | |
282 | } | |
283 | ||
284 | ||
7c6337e2 | 285 | static struct clocksource clocksource_davinci = { |
7c6337e2 | 286 | .rating = 300, |
6d1c57c8 | 287 | .read = read_dummy, |
7c6337e2 | 288 | .mask = CLOCKSOURCE_MASK(32), |
7c6337e2 KH |
289 | .flags = CLOCK_SOURCE_IS_CONTINUOUS, |
290 | }; | |
291 | ||
6d1c57c8 AG |
292 | /* |
293 | * Overwrite weak default sched_clock with something more precise | |
294 | */ | |
295 | unsigned long long notrace sched_clock(void) | |
296 | { | |
297 | const cycle_t cyc = clocksource_davinci.read(&clocksource_davinci); | |
298 | ||
299 | return clocksource_cyc2ns(cyc, clocksource_davinci.mult, | |
300 | clocksource_davinci.shift); | |
301 | } | |
302 | ||
7c6337e2 KH |
303 | /* |
304 | * clockevent | |
305 | */ | |
306 | static int davinci_set_next_event(unsigned long cycles, | |
307 | struct clock_event_device *evt) | |
308 | { | |
309 | struct timer_s *t = &timers[TID_CLOCKEVENT]; | |
310 | ||
311 | t->period = cycles; | |
312 | timer32_config(t); | |
313 | return 0; | |
314 | } | |
315 | ||
316 | static void davinci_set_mode(enum clock_event_mode mode, | |
317 | struct clock_event_device *evt) | |
318 | { | |
319 | struct timer_s *t = &timers[TID_CLOCKEVENT]; | |
320 | ||
321 | switch (mode) { | |
322 | case CLOCK_EVT_MODE_PERIODIC: | |
e6099002 | 323 | t->period = davinci_clock_tick_rate / (HZ); |
3abd5acf MG |
324 | t->opts &= ~TIMER_OPTS_STATE_MASK; |
325 | t->opts |= TIMER_OPTS_PERIODIC; | |
7c6337e2 KH |
326 | timer32_config(t); |
327 | break; | |
328 | case CLOCK_EVT_MODE_ONESHOT: | |
3abd5acf MG |
329 | t->opts &= ~TIMER_OPTS_STATE_MASK; |
330 | t->opts |= TIMER_OPTS_ONESHOT; | |
7c6337e2 KH |
331 | break; |
332 | case CLOCK_EVT_MODE_UNUSED: | |
333 | case CLOCK_EVT_MODE_SHUTDOWN: | |
3abd5acf MG |
334 | t->opts &= ~TIMER_OPTS_STATE_MASK; |
335 | t->opts |= TIMER_OPTS_DISABLED; | |
7c6337e2 | 336 | break; |
18de5bc4 TG |
337 | case CLOCK_EVT_MODE_RESUME: |
338 | break; | |
7c6337e2 KH |
339 | } |
340 | } | |
341 | ||
342 | static struct clock_event_device clockevent_davinci = { | |
7c6337e2 KH |
343 | .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT, |
344 | .shift = 32, | |
345 | .set_next_event = davinci_set_next_event, | |
346 | .set_mode = davinci_set_mode, | |
347 | }; | |
348 | ||
349 | ||
350 | static void __init davinci_timer_init(void) | |
351 | { | |
e6099002 | 352 | struct clk *timer_clk; |
f64691b3 | 353 | struct davinci_soc_info *soc_info = &davinci_soc_info; |
3abd5acf MG |
354 | unsigned int clockevent_id; |
355 | unsigned int clocksource_id; | |
7c6337e2 KH |
356 | static char err[] __initdata = KERN_ERR |
357 | "%s: can't register clocksource!\n"; | |
d99c3871 | 358 | int i; |
7c6337e2 | 359 | |
3abd5acf MG |
360 | clockevent_id = soc_info->timer_info->clockevent_id; |
361 | clocksource_id = soc_info->timer_info->clocksource_id; | |
362 | ||
363 | timers[TID_CLOCKEVENT].id = clockevent_id; | |
364 | timers[TID_CLOCKSOURCE].id = clocksource_id; | |
365 | ||
366 | /* | |
367 | * If using same timer for both clock events & clocksource, | |
368 | * a compare register must be used to generate an event interrupt. | |
369 | * This is equivalent to a oneshot timer only (not periodic). | |
370 | */ | |
371 | if (clockevent_id == clocksource_id) { | |
372 | struct davinci_timer_instance *dtip = | |
373 | soc_info->timer_info->timers; | |
374 | int event_timer = ID_TO_TIMER(clockevent_id); | |
375 | ||
376 | /* Only bottom timers can use compare regs */ | |
377 | if (IS_TIMER_TOP(clockevent_id)) | |
378 | pr_warning("davinci_timer_init: Invalid use" | |
379 | " of system timers. Results unpredictable.\n"); | |
380 | else if ((dtip[event_timer].cmp_off == 0) | |
381 | || (dtip[event_timer].cmp_irq == 0)) | |
382 | pr_warning("davinci_timer_init: Invalid timer instance" | |
383 | " setup. Results unpredictable.\n"); | |
384 | else { | |
385 | timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE; | |
386 | clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT; | |
387 | } | |
388 | } | |
f64691b3 | 389 | |
e6099002 KH |
390 | timer_clk = clk_get(NULL, "timer0"); |
391 | BUG_ON(IS_ERR(timer_clk)); | |
392 | clk_enable(timer_clk); | |
393 | ||
8ca2e597 CC |
394 | /* init timer hw */ |
395 | timer_init(); | |
396 | ||
e6099002 KH |
397 | davinci_clock_tick_rate = clk_get_rate(timer_clk); |
398 | ||
7c6337e2 | 399 | /* setup clocksource */ |
6d1c57c8 | 400 | clocksource_davinci.read = read_cycles; |
3abd5acf | 401 | clocksource_davinci.name = id_to_name[clocksource_id]; |
7c044be5 RK |
402 | if (clocksource_register_hz(&clocksource_davinci, |
403 | davinci_clock_tick_rate)) | |
7c6337e2 KH |
404 | printk(err, clocksource_davinci.name); |
405 | ||
406 | /* setup clockevent */ | |
f64691b3 | 407 | clockevent_davinci.name = id_to_name[timers[TID_CLOCKEVENT].id]; |
e6099002 | 408 | clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC, |
7c6337e2 KH |
409 | clockevent_davinci.shift); |
410 | clockevent_davinci.max_delta_ns = | |
411 | clockevent_delta2ns(0xfffffffe, &clockevent_davinci); | |
3abd5acf | 412 | clockevent_davinci.min_delta_ns = 50000; /* 50 usec */ |
7c6337e2 | 413 | |
320ab2b0 | 414 | clockevent_davinci.cpumask = cpumask_of(0); |
7c6337e2 | 415 | clockevents_register_device(&clockevent_davinci); |
d99c3871 KH |
416 | |
417 | for (i=0; i< ARRAY_SIZE(timers); i++) | |
418 | timer32_config(&timers[i]); | |
7c6337e2 KH |
419 | } |
420 | ||
421 | struct sys_timer davinci_timer = { | |
422 | .init = davinci_timer_init, | |
423 | }; | |
424 | ||
425 | ||
426 | /* reset board using watchdog timer */ | |
c78a5bc2 | 427 | void davinci_watchdog_reset(struct platform_device *pdev) |
fb631387 | 428 | { |
f5c122da | 429 | u32 tgcr, wdtcr; |
c78a5bc2 | 430 | void __iomem *base; |
e6099002 | 431 | struct clk *wd_clk; |
e6099002 | 432 | |
c78a5bc2 CC |
433 | base = ioremap(pdev->resource[0].start, SZ_4K); |
434 | if (WARN_ON(!base)) | |
435 | return; | |
436 | ||
5fcd294d | 437 | wd_clk = clk_get(&pdev->dev, NULL); |
e6099002 KH |
438 | if (WARN_ON(IS_ERR(wd_clk))) |
439 | return; | |
440 | clk_enable(wd_clk); | |
7c6337e2 KH |
441 | |
442 | /* disable, internal clock source */ | |
f5c122da | 443 | __raw_writel(0, base + TCR); |
7c6337e2 KH |
444 | |
445 | /* reset timer, set mode to 64-bit watchdog, and unreset */ | |
446 | tgcr = 0; | |
a23f7dc8 | 447 | __raw_writel(tgcr, base + TGCR); |
7c6337e2 KH |
448 | tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT; |
449 | tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) | | |
450 | (TGCR_UNRESET << TGCR_TIM34RS_SHIFT); | |
a23f7dc8 | 451 | __raw_writel(tgcr, base + TGCR); |
7c6337e2 KH |
452 | |
453 | /* clear counter and period regs */ | |
f5c122da KH |
454 | __raw_writel(0, base + TIM12); |
455 | __raw_writel(0, base + TIM34); | |
456 | __raw_writel(0, base + PRD12); | |
457 | __raw_writel(0, base + PRD34); | |
7c6337e2 | 458 | |
7c6337e2 | 459 | /* put watchdog in pre-active state */ |
a23f7dc8 | 460 | wdtcr = __raw_readl(base + WDTCR); |
7c6337e2 KH |
461 | wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) | |
462 | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); | |
f5c122da | 463 | __raw_writel(wdtcr, base + WDTCR); |
7c6337e2 KH |
464 | |
465 | /* put watchdog in active state */ | |
466 | wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) | | |
467 | (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT); | |
f5c122da | 468 | __raw_writel(wdtcr, base + WDTCR); |
7c6337e2 KH |
469 | |
470 | /* write an invalid value to the WDKEY field to trigger | |
471 | * a watchdog reset */ | |
472 | wdtcr = 0x00004000; | |
f5c122da | 473 | __raw_writel(wdtcr, base + WDTCR); |
7c6337e2 | 474 | } |