davinci: Move interrupt ctlr info to SoC infrastructure
[deliverable/linux.git] / arch / arm / mach-davinci / time.c
CommitLineData
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>
17#include <linux/spinlock.h>
fced80c7 18#include <linux/io.h>
f5c122da
KH
19#include <linux/clk.h>
20#include <linux/err.h>
21#include <linux/device.h>
fb631387 22#include <linux/platform_device.h>
7c6337e2 23
a09e64fb 24#include <mach/hardware.h>
7c6337e2
KH
25#include <asm/system.h>
26#include <asm/irq.h>
27#include <asm/mach/irq.h>
28#include <asm/mach/time.h>
29#include <asm/errno.h>
a09e64fb 30#include <mach/io.h>
f5c122da
KH
31#include <mach/cputype.h>
32#include "clock.h"
7c6337e2
KH
33
34static struct clock_event_device clockevent_davinci;
e6099002 35static unsigned int davinci_clock_tick_rate;
7c6337e2
KH
36
37#define DAVINCI_TIMER0_BASE (IO_PHYS + 0x21400)
38#define DAVINCI_TIMER1_BASE (IO_PHYS + 0x21800)
39#define DAVINCI_WDOG_BASE (IO_PHYS + 0x21C00)
40
41enum {
42 T0_BOT = 0, T0_TOP, T1_BOT, T1_TOP, NUM_TIMERS,
43};
44
45#define IS_TIMER1(id) (id & 0x2)
46#define IS_TIMER0(id) (!IS_TIMER1(id))
47#define IS_TIMER_TOP(id) ((id & 0x1))
48#define IS_TIMER_BOT(id) (!IS_TIMER_TOP(id))
49
50static int timer_irqs[NUM_TIMERS] = {
51 IRQ_TINT0_TINT12,
52 IRQ_TINT0_TINT34,
53 IRQ_TINT1_TINT12,
54 IRQ_TINT1_TINT34,
55};
56
57/*
58 * This driver configures the 2 64-bit count-up timers as 4 independent
59 * 32-bit count-up timers used as follows:
60 *
61 * T0_BOT: Timer 0, bottom: clockevent source for hrtimers
62 * T0_TOP: Timer 0, top : clocksource for generic timekeeping
63 * T1_BOT: Timer 1, bottom: (used by DSP in TI DSPLink code)
64 * T1_TOP: Timer 1, top : <unused>
65 */
66#define TID_CLOCKEVENT T0_BOT
67#define TID_CLOCKSOURCE T0_TOP
68
69/* Timer register offsets */
70#define PID12 0x0
71#define TIM12 0x10
72#define TIM34 0x14
73#define PRD12 0x18
74#define PRD34 0x1c
75#define TCR 0x20
76#define TGCR 0x24
77#define WDTCR 0x28
78
79/* Timer register bitfields */
80#define TCR_ENAMODE_DISABLE 0x0
81#define TCR_ENAMODE_ONESHOT 0x1
82#define TCR_ENAMODE_PERIODIC 0x2
83#define TCR_ENAMODE_MASK 0x3
84
85#define TGCR_TIMMODE_SHIFT 2
86#define TGCR_TIMMODE_64BIT_GP 0x0
87#define TGCR_TIMMODE_32BIT_UNCHAINED 0x1
88#define TGCR_TIMMODE_64BIT_WDOG 0x2
89#define TGCR_TIMMODE_32BIT_CHAINED 0x3
90
91#define TGCR_TIM12RS_SHIFT 0
92#define TGCR_TIM34RS_SHIFT 1
93#define TGCR_RESET 0x0
94#define TGCR_UNRESET 0x1
95#define TGCR_RESET_MASK 0x3
96
97#define WDTCR_WDEN_SHIFT 14
98#define WDTCR_WDEN_DISABLE 0x0
99#define WDTCR_WDEN_ENABLE 0x1
100#define WDTCR_WDKEY_SHIFT 16
101#define WDTCR_WDKEY_SEQ0 0xa5c6
102#define WDTCR_WDKEY_SEQ1 0xda7e
103
104struct timer_s {
105 char *name;
106 unsigned int id;
107 unsigned long period;
108 unsigned long opts;
f5c122da
KH
109 void __iomem *base;
110 unsigned long tim_off;
111 unsigned long prd_off;
7c6337e2
KH
112 unsigned long enamode_shift;
113 struct irqaction irqaction;
114};
115static struct timer_s timers[];
116
117/* values for 'opts' field of struct timer_s */
118#define TIMER_OPTS_DISABLED 0x00
119#define TIMER_OPTS_ONESHOT 0x01
120#define TIMER_OPTS_PERIODIC 0x02
121
122static int timer32_config(struct timer_s *t)
123{
f5c122da 124 u32 tcr = __raw_readl(t->base + TCR);
7c6337e2
KH
125
126 /* disable timer */
127 tcr &= ~(TCR_ENAMODE_MASK << t->enamode_shift);
f5c122da 128 __raw_writel(tcr, t->base + TCR);
7c6337e2
KH
129
130 /* reset counter to zero, set new period */
f5c122da
KH
131 __raw_writel(0, t->base + t->tim_off);
132 __raw_writel(t->period, t->base + t->prd_off);
7c6337e2
KH
133
134 /* Set enable mode */
135 if (t->opts & TIMER_OPTS_ONESHOT) {
136 tcr |= TCR_ENAMODE_ONESHOT << t->enamode_shift;
137 } else if (t->opts & TIMER_OPTS_PERIODIC) {
138 tcr |= TCR_ENAMODE_PERIODIC << t->enamode_shift;
139 }
140
f5c122da 141 __raw_writel(tcr, t->base + TCR);
7c6337e2
KH
142 return 0;
143}
144
145static inline u32 timer32_read(struct timer_s *t)
146{
f5c122da 147 return __raw_readl(t->base + t->tim_off);
7c6337e2
KH
148}
149
150static irqreturn_t timer_interrupt(int irq, void *dev_id)
151{
152 struct clock_event_device *evt = &clockevent_davinci;
153
154 evt->event_handler(evt);
155 return IRQ_HANDLED;
156}
157
158/* called when 32-bit counter wraps */
159static irqreturn_t freerun_interrupt(int irq, void *dev_id)
160{
161 return IRQ_HANDLED;
162}
163
164static struct timer_s timers[] = {
165 [TID_CLOCKEVENT] = {
166 .name = "clockevent",
167 .opts = TIMER_OPTS_DISABLED,
168 .irqaction = {
169 .flags = IRQF_DISABLED | IRQF_TIMER,
170 .handler = timer_interrupt,
171 }
172 },
173 [TID_CLOCKSOURCE] = {
174 .name = "free-run counter",
175 .period = ~0,
176 .opts = TIMER_OPTS_PERIODIC,
177 .irqaction = {
178 .flags = IRQF_DISABLED | IRQF_TIMER,
179 .handler = freerun_interrupt,
180 }
181 },
182};
183
184static void __init timer_init(void)
185{
f5c122da 186 u32 phys_bases[] = {DAVINCI_TIMER0_BASE, DAVINCI_TIMER1_BASE};
7c6337e2
KH
187 int i;
188
189 /* Global init of each 64-bit timer as a whole */
190 for(i=0; i<2; i++) {
f5c122da
KH
191 u32 tgcr;
192 void __iomem *base = IO_ADDRESS(phys_bases[i]);
7c6337e2
KH
193
194 /* Disabled, Internal clock source */
f5c122da 195 __raw_writel(0, base + TCR);
7c6337e2
KH
196
197 /* reset both timers, no pre-scaler for timer34 */
198 tgcr = 0;
f5c122da 199 __raw_writel(tgcr, base + TGCR);
7c6337e2
KH
200
201 /* Set both timers to unchained 32-bit */
202 tgcr = TGCR_TIMMODE_32BIT_UNCHAINED << TGCR_TIMMODE_SHIFT;
f5c122da 203 __raw_writel(tgcr, base + TGCR);
7c6337e2
KH
204
205 /* Unreset timers */
206 tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
207 (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
f5c122da 208 __raw_writel(tgcr, base + TGCR);
7c6337e2
KH
209
210 /* Init both counters to zero */
f5c122da
KH
211 __raw_writel(0, base + TIM12);
212 __raw_writel(0, base + TIM34);
7c6337e2
KH
213 }
214
215 /* Init of each timer as a 32-bit timer */
216 for (i=0; i< ARRAY_SIZE(timers); i++) {
217 struct timer_s *t = &timers[i];
f5c122da 218 u32 phys_base;
7c6337e2
KH
219
220 if (t->name) {
221 t->id = i;
f5c122da 222 phys_base = (IS_TIMER1(t->id) ?
7c6337e2 223 DAVINCI_TIMER1_BASE : DAVINCI_TIMER0_BASE);
f5c122da 224 t->base = IO_ADDRESS(phys_base);
7c6337e2
KH
225
226 if (IS_TIMER_BOT(t->id)) {
227 t->enamode_shift = 6;
f5c122da
KH
228 t->tim_off = TIM12;
229 t->prd_off = PRD12;
7c6337e2
KH
230 } else {
231 t->enamode_shift = 22;
f5c122da
KH
232 t->tim_off = TIM34;
233 t->prd_off = PRD34;
7c6337e2
KH
234 }
235
236 /* Register interrupt */
237 t->irqaction.name = t->name;
238 t->irqaction.dev_id = (void *)t;
239 if (t->irqaction.handler != NULL) {
240 setup_irq(timer_irqs[t->id], &t->irqaction);
241 }
242
243 timer32_config(&timers[i]);
244 }
245 }
246}
247
248/*
249 * clocksource
250 */
8e19608e 251static cycle_t read_cycles(struct clocksource *cs)
7c6337e2
KH
252{
253 struct timer_s *t = &timers[TID_CLOCKSOURCE];
254
255 return (cycles_t)timer32_read(t);
256}
257
258static struct clocksource clocksource_davinci = {
259 .name = "timer0_1",
260 .rating = 300,
261 .read = read_cycles,
262 .mask = CLOCKSOURCE_MASK(32),
263 .shift = 24,
264 .flags = CLOCK_SOURCE_IS_CONTINUOUS,
265};
266
267/*
268 * clockevent
269 */
270static int davinci_set_next_event(unsigned long cycles,
271 struct clock_event_device *evt)
272{
273 struct timer_s *t = &timers[TID_CLOCKEVENT];
274
275 t->period = cycles;
276 timer32_config(t);
277 return 0;
278}
279
280static void davinci_set_mode(enum clock_event_mode mode,
281 struct clock_event_device *evt)
282{
283 struct timer_s *t = &timers[TID_CLOCKEVENT];
284
285 switch (mode) {
286 case CLOCK_EVT_MODE_PERIODIC:
e6099002 287 t->period = davinci_clock_tick_rate / (HZ);
7c6337e2
KH
288 t->opts = TIMER_OPTS_PERIODIC;
289 timer32_config(t);
290 break;
291 case CLOCK_EVT_MODE_ONESHOT:
292 t->opts = TIMER_OPTS_ONESHOT;
293 break;
294 case CLOCK_EVT_MODE_UNUSED:
295 case CLOCK_EVT_MODE_SHUTDOWN:
296 t->opts = TIMER_OPTS_DISABLED;
297 break;
18de5bc4
TG
298 case CLOCK_EVT_MODE_RESUME:
299 break;
7c6337e2
KH
300 }
301}
302
303static struct clock_event_device clockevent_davinci = {
304 .name = "timer0_0",
305 .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
306 .shift = 32,
307 .set_next_event = davinci_set_next_event,
308 .set_mode = davinci_set_mode,
309};
310
311
312static void __init davinci_timer_init(void)
313{
e6099002
KH
314 struct clk *timer_clk;
315
7c6337e2
KH
316 static char err[] __initdata = KERN_ERR
317 "%s: can't register clocksource!\n";
318
319 /* init timer hw */
320 timer_init();
321
e6099002
KH
322 timer_clk = clk_get(NULL, "timer0");
323 BUG_ON(IS_ERR(timer_clk));
324 clk_enable(timer_clk);
325
326 davinci_clock_tick_rate = clk_get_rate(timer_clk);
327
7c6337e2
KH
328 /* setup clocksource */
329 clocksource_davinci.mult =
e6099002 330 clocksource_khz2mult(davinci_clock_tick_rate/1000,
7c6337e2
KH
331 clocksource_davinci.shift);
332 if (clocksource_register(&clocksource_davinci))
333 printk(err, clocksource_davinci.name);
334
335 /* setup clockevent */
e6099002 336 clockevent_davinci.mult = div_sc(davinci_clock_tick_rate, NSEC_PER_SEC,
7c6337e2
KH
337 clockevent_davinci.shift);
338 clockevent_davinci.max_delta_ns =
339 clockevent_delta2ns(0xfffffffe, &clockevent_davinci);
340 clockevent_davinci.min_delta_ns =
341 clockevent_delta2ns(1, &clockevent_davinci);
342
320ab2b0 343 clockevent_davinci.cpumask = cpumask_of(0);
7c6337e2
KH
344 clockevents_register_device(&clockevent_davinci);
345}
346
347struct sys_timer davinci_timer = {
348 .init = davinci_timer_init,
349};
350
351
352/* reset board using watchdog timer */
fb631387
KH
353void davinci_watchdog_reset(void)
354{
f5c122da
KH
355 u32 tgcr, wdtcr;
356 void __iomem *base = IO_ADDRESS(DAVINCI_WDOG_BASE);
e6099002 357 struct clk *wd_clk;
e6099002 358
fb631387 359 wd_clk = clk_get(&davinci_wdt_device.dev, NULL);
e6099002
KH
360 if (WARN_ON(IS_ERR(wd_clk)))
361 return;
362 clk_enable(wd_clk);
7c6337e2
KH
363
364 /* disable, internal clock source */
f5c122da 365 __raw_writel(0, base + TCR);
7c6337e2
KH
366
367 /* reset timer, set mode to 64-bit watchdog, and unreset */
368 tgcr = 0;
f5c122da 369 __raw_writel(tgcr, base + TCR);
7c6337e2
KH
370 tgcr = TGCR_TIMMODE_64BIT_WDOG << TGCR_TIMMODE_SHIFT;
371 tgcr |= (TGCR_UNRESET << TGCR_TIM12RS_SHIFT) |
372 (TGCR_UNRESET << TGCR_TIM34RS_SHIFT);
f5c122da 373 __raw_writel(tgcr, base + TCR);
7c6337e2
KH
374
375 /* clear counter and period regs */
f5c122da
KH
376 __raw_writel(0, base + TIM12);
377 __raw_writel(0, base + TIM34);
378 __raw_writel(0, base + PRD12);
379 __raw_writel(0, base + PRD34);
7c6337e2
KH
380
381 /* enable */
f5c122da 382 wdtcr = __raw_readl(base + WDTCR);
7c6337e2 383 wdtcr |= WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT;
f5c122da 384 __raw_writel(wdtcr, base + WDTCR);
7c6337e2
KH
385
386 /* put watchdog in pre-active state */
387 wdtcr = (WDTCR_WDKEY_SEQ0 << WDTCR_WDKEY_SHIFT) |
388 (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
f5c122da 389 __raw_writel(wdtcr, base + WDTCR);
7c6337e2
KH
390
391 /* put watchdog in active state */
392 wdtcr = (WDTCR_WDKEY_SEQ1 << WDTCR_WDKEY_SHIFT) |
393 (WDTCR_WDEN_ENABLE << WDTCR_WDEN_SHIFT);
f5c122da 394 __raw_writel(wdtcr, base + WDTCR);
7c6337e2
KH
395
396 /* write an invalid value to the WDKEY field to trigger
397 * a watchdog reset */
398 wdtcr = 0x00004000;
f5c122da 399 __raw_writel(wdtcr, base + WDTCR);
7c6337e2 400}
This page took 0.22005 seconds and 5 git commands to generate.