4 * timers count up to zero.
6 * the source clock signals for the timers are sometimes selectable. for
7 * WDTIMER[23] and GPTIMER12, it's always the 32kHz clock. for the
8 * others, it can be the 32kHz clock or the system clock. we use only
9 * WDTIMER2 and GPTIMER[12], and configure GPTIMER[12] in archomap.c to
10 * use the 32kHZ clock. WDTIMER1 is not accessible to us on GP
11 * (general-purpose) omaps.
14 #include "../port/lib.h"
26 /* irq 36 is watchdog timer module 3 overflow */
27 Tn0irq = 37, /* base IRQ for all timers */
29 Freebase = 1, /* base of free-running timer */
32 * clock is 32K (32,768) Hz, so one tick is 30.517µs,
33 * so 327.68 ticks is 10ms, 32.768 ticks is 1ms.
35 Clockfreqbase = 32 * 1024, /* base rate in Hz */
36 Tcycles = Clockfreqbase / HZ, /* cycles per clock tick */
38 MinPeriod = (Tcycles / 100 < 2? 2: Tcycles / 100),
41 Dogtimeout = 20 * Clockfreqbase, /* was 4 s.; must be ≤ 21 s. */
53 Ovf_it = 1<<1, /* gp: overflow intr */
54 Mat_it = 1<<0, /* gp: match intr */
55 Wdovf_it = 1<<0, /* wdog: overflow intr */
58 Ar = 1<<1, /* gp only: autoreload mode overflow */
59 St = 1<<0, /* gp only: start the timer */
62 /* omap35x timer registers */
63 typedef struct Timerregs Timerregs;
65 /* common to all timers, gp and watchdog */
68 ulong tistat; /* ro: low bit: reset done */
73 ulong tcrr; /* counter: cycles to zero */
75 ulong ttgr; /* trigger */
76 ulong twps; /* ro: write posted pending */
78 /* gp timers only, unused by us */
79 ulong tmar; /* value to compare with counter */
84 ulong tpir; /* gp: 1 ms tick generation: +ve */
85 ulong wspr; /* wdog: start/stop control */
87 ulong tnir; /* 1 ms tick generation: -ve */
88 ulong tcvr; /* 1 ms tick generation: next counter value */
89 ulong tocr; /* intr mask for n ticks */
93 static int ticks; /* for sanity checking; m->ticks doesn't always get called */
96 static ulong rdcycles(void), rdbaseticks(void);
98 /* write a watchdog timer's start/stop register */
100 wdogwrss(Timerregs *tn, ulong val)
102 while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
106 while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
111 resetwait(Timerregs *tn)
115 for (bound = 400*Mhz; !(tn->tistat & Resetdone) && bound > 0; bound--)
118 iprint("clock reset didn't complete\n");
123 wdogoff(Timerregs *tn)
127 wdogwrss(tn, 0xaaaa); /* magic off sequence */
128 wdogwrss(tn, 0x5555);
132 tn->tcrr = 1; /* paranoia */
136 static void wdogassure(void);
139 wdogon(Timerregs *tn)
144 tn->tldr = -Dogtimeout;
145 tn->tcrr = -Dogtimeout;
147 wdogwrss(tn, 0xbbbb); /* magic on sequence */
148 wdogwrss(tn, 0x4444); /* magic on sequence */
152 /* touching the dog is not quick, so do it infrequently */
153 addclock0link(wdogassure, HZ);
158 wdogassure(void) /* reset the watch dog's counter */
162 tn = (Timerregs *)PHYSWDOG;
165 tn->tcrr = -Dogtimeout;
172 clockintr(Ureg* ureg, void *arg)
180 if (nesting == 0) { /* if the clock interrupted itself, bail out */
187 tn->tisr = Ovf_it; /* dismiss the interrupt */
192 clockreset(Timerregs *tn)
194 if (probeaddr((uintptr)&tn->ticpcfg) < 0)
195 panic("no clock at %#p", tn);
196 tn->ticpcfg = Softreset | Noidle;
199 tn->tier = tn->tclr = 0;
203 /* stop clock interrupts and disable the watchdog timer */
207 clockreset((Timerregs *)PHYSWDT2);
208 wdogoff((Timerregs *)PHYSWDT2);
209 clockreset((Timerregs *)PHYSWDT3);
210 wdogoff((Timerregs *)PHYSWDT3);
212 clockreset((Timerregs *)Tn0);
213 clockreset((Timerregs *)Tn1);
229 --i; --i; --i; --i; --i;
232 return rdbaseticks() - st;
249 return rdbaseticks() - st;
252 /* estimate instructions/s. using 32kHz clock */
254 guessmips(long (*loop)(void), char *lab)
267 * Instrs instructions took tcks ticks @ Clockfreqbase Hz.
269 s = ((vlong)Clockfreqbase * Instrs) / tcks / 1000000;
271 iprint("%ud mips (%s-issue)", s, lab);
283 /* turn cycle counter on */
284 cpwrsc(0, CpCLD, CpCLDena, CpCLDenacyc, 1<<31);
286 /* turn all counters on and clear the cycle counter */
287 cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1<<2 | 1);
289 /* let users read the cycle counter directly */
290 cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1);
294 m->ticks = ticks = 0;
297 * T0 is a freerunning timer (cycle counter); it wraps,
298 * automatically reloads, and does not dispatch interrupts.
300 tn = (Timerregs *)Tn0;
301 tn->tcrr = Freebase; /* count up to 0 */
308 * T1 is the interrupting timer and does not participate
309 * in measuring time. It is initially set to HZ.
311 tn = (Timerregs *)Tn1;
312 irqenable(Tn0irq+1, clockintr, tn, "clock");
314 tn->tcrr = -Tcycles; /* approx.; count up to 0 */
324 * verify sanity of timer1
326 s = spllo(); /* risky */
327 for (i = 0; i < 5 && ticks == 0; i++) {
329 cachedwbinvse(&ticks, sizeof ticks);
334 panic("clock not interrupting");
335 else if (tn->tcrr == tn->tldr)
336 panic("clock not ticking at all");
339 panic("clock running very slowly");
343 guessmips(issue1loop, "single");
346 guessmips(issue2loop, "dual");
351 * m->delayloop should be the number of delay loop iterations
352 * needed to consume 1 ms. 2 is min. instructions in the delay loop.
354 m->delayloop = m->cpuhz / (1000 * 2);
355 // iprint("m->delayloop = %lud\n", m->delayloop);
358 * desynchronize the processor clocks so that they all don't
359 * try to resched at the same time.
373 return fastticks2us(fastticks(nil));
380 Timerregs *tn = (Timerregs *)Tn1;
384 offset = next - fastticks(nil);
385 if(offset < MinPeriod)
387 else if(offset > MaxPeriod)
399 /* reads 32-bit cycle counter (counting up) */
400 v = cprdsc(0, CpCLD, CpCLDcyc, 0);
401 /* keep it positive; prevent m->fastclock ever going to 0 */
410 v = ((Timerregs *)Tn0)->tcrr; /* tcrr should be counting up */
411 /* keep it positive; prevent m->fastclock ever going to 0 */
428 * until 5[cal] inline vlong ops, avoid them where possible,
429 * they are currently slow function calls.
431 typedef union Counter Counter;
434 struct { /* little-endian */
445 fastticks(uvlong *hz)
452 if (m->ticks > HZ/10 && m->fastclock == 0)
453 panic("fastticks: zero m->fastclock; ticks %lud fastclock %#llux",
454 m->ticks, m->fastclock);
456 now.uvl = m->fastclock;
457 now.low = rdcycles();
458 if(now.uvl < m->fastclock) /* low bits must have wrapped */
460 m->fastclock = now.uvl;
463 sclnow.uvl = now.uvl;
473 l = l * (vlong)m->delayloop / 1000;
476 for(i = 0; i < l; i++)