1 /*
2 * omap3530 clocks
3 *
4 * timers count up to zero.
5 *
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.
12 */
13 #include "u.h"
14 #include "../port/lib.h"
15 #include "mem.h"
16 #include "dat.h"
17 #include "fns.h"
18 #include "arm.h"
19
20 enum {
21 Debug = 0,
22
23 Tn0 = PHYSTIMER1,
24 Tn1 = PHYSTIMER2,
25
26 /* irq 36 is watchdog timer module 3 overflow */
27 Tn0irq = 37, /* base IRQ for all timers */
28
29 Freebase = 1, /* base of free-running timer */
30
31 /*
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.
34 */
35 Clockfreqbase = 32 * 1024, /* base rate in Hz */
36 Tcycles = Clockfreqbase / HZ, /* cycles per clock tick */
37
38 MinPeriod = (Tcycles / 100 < 2? 2: Tcycles / 100),
39 MaxPeriod = Tcycles,
40
41 Dogtimeout = 20 * Clockfreqbase, /* was 4 s.; must be ≤ 21 s. */
42 };
43
44 enum {
45 /* ticpcfg bits */
46 Noidle = 1<<3,
47 Softreset = 1<<1,
48
49 /* tistat bits */
50 Resetdone = 1<<0,
51
52 /* tisr/tier bits */
53 Ovf_it = 1<<1, /* gp: overflow intr */
54 Mat_it = 1<<0, /* gp: match intr */
55 Wdovf_it = 1<<0, /* wdog: overflow intr */
56
57 /* tclr bits */
58 Ar = 1<<1, /* gp only: autoreload mode overflow */
59 St = 1<<0, /* gp only: start the timer */
60 };
61
62 /* omap35x timer registers */
63 typedef struct Timerregs Timerregs;
64 struct Timerregs {
65 /* common to all timers, gp and watchdog */
66 uchar pad0[0x10];
67 ulong ticpcfg;
68 ulong tistat; /* ro: low bit: reset done */
69 ulong tisr;
70 ulong tier;
71 ulong twer;
72 ulong tclr;
73 ulong tcrr; /* counter: cycles to zero */
74 ulong tldr;
75 ulong ttgr; /* trigger */
76 ulong twps; /* ro: write posted pending */
77
78 /* gp timers only, unused by us */
79 ulong tmar; /* value to compare with counter */
80 ulong tcar1; /* ro */
81 ulong tsicr;
82 ulong tcar2; /* ro */
83 union {
84 ulong tpir; /* gp: 1 ms tick generation: +ve */
85 ulong wspr; /* wdog: start/stop control */
86 };
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 */
90 ulong towr;
91 };
92
93 static int ticks; /* for sanity checking; m->ticks doesn't always get called */
94 static Lock clklck;
95
96 static ulong rdcycles(void), rdbaseticks(void);
97
98 /* write a watchdog timer's start/stop register */
99 static void
wdogwrss(Timerregs * tn,ulong val)100 wdogwrss(Timerregs *tn, ulong val)
101 {
102 while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
103 ;
104 tn->wspr = val;
105 coherence();
106 while (tn->twps & (1 << 4)) /* pending write to start/stop reg? */
107 ;
108 }
109
110 static void
resetwait(Timerregs * tn)111 resetwait(Timerregs *tn)
112 {
113 long bound;
114
115 for (bound = 400*Mhz; !(tn->tistat & Resetdone) && bound > 0; bound--)
116 ;
117 if (bound <= 0)
118 iprint("clock reset didn't complete\n");
119 }
120
121
122 static void
wdogoff(Timerregs * tn)123 wdogoff(Timerregs *tn)
124 {
125 resetwait(tn);
126
127 wdogwrss(tn, 0xaaaa); /* magic off sequence */
128 wdogwrss(tn, 0x5555);
129
130 tn->tldr = 1;
131 coherence();
132 tn->tcrr = 1; /* paranoia */
133 coherence();
134 }
135
136 static void wdogassure(void);
137
138 static void
wdogon(Timerregs * tn)139 wdogon(Timerregs *tn)
140 {
141 static int beenhere;
142
143 resetwait(tn);
144 tn->tldr = -Dogtimeout;
145 tn->tcrr = -Dogtimeout;
146 coherence();
147 wdogwrss(tn, 0xbbbb); /* magic on sequence */
148 wdogwrss(tn, 0x4444); /* magic on sequence */
149
150 if (!beenhere) {
151 beenhere = 1;
152 /* touching the dog is not quick, so do it infrequently */
153 addclock0link(wdogassure, HZ);
154 }
155 }
156
157 static void
wdogassure(void)158 wdogassure(void) /* reset the watch dog's counter */
159 {
160 Timerregs *tn;
161
162 tn = (Timerregs *)PHYSWDOG;
163 wdogoff(tn);
164
165 tn->tcrr = -Dogtimeout;
166 coherence();
167
168 wdogon(tn);
169 }
170
171 static void
clockintr(Ureg * ureg,void * arg)172 clockintr(Ureg* ureg, void *arg)
173 {
174 Timerregs *tn;
175 static int nesting;
176
177 ticks++;
178 coherence();
179
180 if (nesting == 0) { /* if the clock interrupted itself, bail out */
181 ++nesting;
182 timerintr(ureg, 0);
183 --nesting;
184 }
185
186 tn = arg;
187 tn->tisr = Ovf_it; /* dismiss the interrupt */
188 coherence();
189 }
190
191 static void
clockreset(Timerregs * tn)192 clockreset(Timerregs *tn)
193 {
194 if (probeaddr((uintptr)&tn->ticpcfg) < 0)
195 panic("no clock at %#p", tn);
196 tn->ticpcfg = Softreset | Noidle;
197 coherence();
198 resetwait(tn);
199 tn->tier = tn->tclr = 0;
200 coherence();
201 }
202
203 /* stop clock interrupts and disable the watchdog timer */
204 void
clockshutdown(void)205 clockshutdown(void)
206 {
207 clockreset((Timerregs *)PHYSWDT2);
208 wdogoff((Timerregs *)PHYSWDT2);
209 clockreset((Timerregs *)PHYSWDT3);
210 wdogoff((Timerregs *)PHYSWDT3);
211
212 clockreset((Timerregs *)Tn0);
213 clockreset((Timerregs *)Tn1);
214 }
215
216 enum {
217 Instrs = 10*Mhz,
218 };
219
220 static long
issue1loop(void)221 issue1loop(void)
222 {
223 register int i;
224 long st;
225
226 st = rdbaseticks();
227 i = Instrs;
228 do {
229 --i; --i; --i; --i; --i;
230 --i; --i; --i; --i;
231 } while(--i >= 0);
232 return rdbaseticks() - st;
233 }
234
235 static long
issue2loop(void)236 issue2loop(void)
237 {
238 register int i, j;
239 long st;
240
241 st = rdbaseticks();
242 i = Instrs / 2;
243 j = 0;
244 do {
245 --i; --j; --i; --j;
246 --i; --j; --i; --j;
247 --j;
248 } while(--i >= 0);
249 return rdbaseticks() - st;
250 }
251
252 /* estimate instructions/s. using 32kHz clock */
253 static void
guessmips(long (* loop)(void),char * lab)254 guessmips(long (*loop)(void), char *lab)
255 {
256 int s;
257 long tcks;
258
259 do {
260 s = splhi();
261 tcks = loop();
262 splx(s);
263 if (tcks < 0)
264 iprint("again...");
265 } while (tcks < 0);
266 /*
267 * Instrs instructions took tcks ticks @ Clockfreqbase Hz.
268 */
269 s = ((vlong)Clockfreqbase * Instrs) / tcks / 1000000;
270 if (Debug)
271 iprint("%ud mips (%s-issue)", s, lab);
272 USED(s);
273 }
274
275 void
clockinit(void)276 clockinit(void)
277 {
278 int i, s;
279 Timerregs *tn;
280
281 clockshutdown();
282
283 /* turn cycle counter on */
284 cpwrsc(0, CpCLD, CpCLDena, CpCLDenacyc, 1<<31);
285
286 /* turn all counters on and clear the cycle counter */
287 cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1<<2 | 1);
288
289 /* let users read the cycle counter directly */
290 cpwrsc(0, CpCLD, CpCLDena, CpCLDenapmnc, 1);
291
292 ilock(&clklck);
293 m->fastclock = 1;
294 m->ticks = ticks = 0;
295
296 /*
297 * T0 is a freerunning timer (cycle counter); it wraps,
298 * automatically reloads, and does not dispatch interrupts.
299 */
300 tn = (Timerregs *)Tn0;
301 tn->tcrr = Freebase; /* count up to 0 */
302 tn->tldr = Freebase;
303 coherence();
304 tn->tclr = Ar | St;
305 iunlock(&clklck);
306
307 /*
308 * T1 is the interrupting timer and does not participate
309 * in measuring time. It is initially set to HZ.
310 */
311 tn = (Timerregs *)Tn1;
312 irqenable(Tn0irq+1, clockintr, tn, "clock");
313 ilock(&clklck);
314 tn->tcrr = -Tcycles; /* approx.; count up to 0 */
315 tn->tldr = -Tcycles;
316 coherence();
317 tn->tclr = Ar | St;
318 coherence();
319 tn->tier = Ovf_it;
320 coherence();
321 iunlock(&clklck);
322
323 /*
324 * verify sanity of timer1
325 */
326 s = spllo(); /* risky */
327 for (i = 0; i < 5 && ticks == 0; i++) {
328 delay(10);
329 cachedwbinvse(&ticks, sizeof ticks);
330 }
331 splx(s);
332 if (ticks == 0) {
333 if (tn->tcrr == 0)
334 panic("clock not interrupting");
335 else if (tn->tcrr == tn->tldr)
336 panic("clock not ticking at all");
337 #ifdef PARANOID
338 else
339 panic("clock running very slowly");
340 #endif
341 }
342
343 guessmips(issue1loop, "single");
344 if (Debug)
345 iprint(", ");
346 guessmips(issue2loop, "dual");
347 if (Debug)
348 iprint("\n");
349
350 /*
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.
353 */
354 m->delayloop = m->cpuhz / (1000 * 2);
355 // iprint("m->delayloop = %lud\n", m->delayloop);
356
357 /*
358 * desynchronize the processor clocks so that they all don't
359 * try to resched at the same time.
360 */
361 delay(m->machno*2);
362 }
363
364 void
watchdoginit(void)365 watchdoginit(void)
366 {
367 wdogassure();
368 }
369
370 ulong
s(void)371 µs(void)
372 {
373 return fastticks2us(fastticks(nil));
374 }
375
376 void
timerset(Tval next)377 timerset(Tval next)
378 {
379 long offset;
380 Timerregs *tn = (Timerregs *)Tn1;
381 static Lock setlck;
382
383 ilock(&setlck);
384 offset = next - fastticks(nil);
385 if(offset < MinPeriod)
386 offset = MinPeriod;
387 else if(offset > MaxPeriod)
388 offset = MaxPeriod;
389 tn->tcrr = -offset;
390 coherence();
391 iunlock(&setlck);
392 }
393
394 static ulong
rdcycles(void)395 rdcycles(void)
396 {
397 ulong v;
398
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 */
402 return v == 0? 1: v;
403 }
404
405 static ulong
rdbaseticks(void)406 rdbaseticks(void)
407 {
408 ulong v;
409
410 v = ((Timerregs *)Tn0)->tcrr; /* tcrr should be counting up */
411 /* keep it positive; prevent m->fastclock ever going to 0 */
412 return v == 0? 1: v;
413 }
414
415 ulong
perfticks(void)416 perfticks(void)
417 {
418 return rdcycles();
419 }
420
421 long
lcycles(void)422 lcycles(void)
423 {
424 return perfticks();
425 }
426
427 /*
428 * until 5[cal] inline vlong ops, avoid them where possible,
429 * they are currently slow function calls.
430 */
431 typedef union Counter Counter;
432 union Counter {
433 uvlong uvl;
434 struct { /* little-endian */
435 ulong low;
436 ulong high;
437 };
438 };
439
440 enum {
441 Fastvlongops = 0,
442 };
443
444 uvlong
fastticks(uvlong * hz)445 fastticks(uvlong *hz)
446 {
447 Counter now, sclnow;
448
449 if(hz)
450 *hz = m->cpuhz;
451 ilock(&clklck);
452 if (m->ticks > HZ/10 && m->fastclock == 0)
453 panic("fastticks: zero m->fastclock; ticks %lud fastclock %#llux",
454 m->ticks, m->fastclock);
455
456 now.uvl = m->fastclock;
457 now.low = rdcycles();
458 if(now.uvl < m->fastclock) /* low bits must have wrapped */
459 now.high++;
460 m->fastclock = now.uvl;
461 coherence();
462
463 sclnow.uvl = now.uvl;
464 iunlock(&clklck);
465 return sclnow.uvl;
466 }
467
468 void
microdelay(int l)469 microdelay(int l)
470 {
471 int i;
472
473 l = l * (vlong)m->delayloop / 1000;
474 if(l <= 0)
475 l = 1;
476 for(i = 0; i < l; i++)
477 ;
478 }
479
480 void
delay(int l)481 delay(int l)
482 {
483 ulong i, j;
484
485 j = m->delayloop;
486 while(l-- > 0)
487 for(i=0; i < j; i++)
488 ;
489 }
490