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