1*f43f8ee6SDavid du Colombier /*
2*f43f8ee6SDavid du Colombier * ar7161 clocks and timers
3*f43f8ee6SDavid du Colombier */
4*f43f8ee6SDavid du Colombier #include "u.h"
5*f43f8ee6SDavid du Colombier #include "../port/lib.h"
6*f43f8ee6SDavid du Colombier #include "mem.h"
7*f43f8ee6SDavid du Colombier #include "dat.h"
8*f43f8ee6SDavid du Colombier #include "fns.h"
9*f43f8ee6SDavid du Colombier #include "io.h"
10*f43f8ee6SDavid du Colombier
11*f43f8ee6SDavid du Colombier #include "ureg.h"
12*f43f8ee6SDavid du Colombier
13*f43f8ee6SDavid du Colombier enum {
14*f43f8ee6SDavid du Colombier Cyccntres = 2, /* counter advances at ½ clock rate (mips 24k) */
15*f43f8ee6SDavid du Colombier Basetickfreq = 680*Mhz / Cyccntres, /* rb450g */
16*f43f8ee6SDavid du Colombier };
17*f43f8ee6SDavid du Colombier
18*f43f8ee6SDavid du Colombier void (*kproftimer)(ulong);
19*f43f8ee6SDavid du Colombier
20*f43f8ee6SDavid du Colombier void
silencewdog(void)21*f43f8ee6SDavid du Colombier silencewdog(void)
22*f43f8ee6SDavid du Colombier {
23*f43f8ee6SDavid du Colombier *Rstwdogtimer = Basetickfreq * 2 * 5; /* pet the dog */
24*f43f8ee6SDavid du Colombier }
25*f43f8ee6SDavid du Colombier
26*f43f8ee6SDavid du Colombier void
sicwdog(void)27*f43f8ee6SDavid du Colombier sicwdog(void)
28*f43f8ee6SDavid du Colombier {
29*f43f8ee6SDavid du Colombier *Rstwdogtimer = Basetickfreq * 2;
30*f43f8ee6SDavid du Colombier *Rstwdogctl = Wdogreset; /* wake the dog */
31*f43f8ee6SDavid du Colombier }
32*f43f8ee6SDavid du Colombier
33*f43f8ee6SDavid du Colombier void
wdogreset(void)34*f43f8ee6SDavid du Colombier wdogreset(void)
35*f43f8ee6SDavid du Colombier {
36*f43f8ee6SDavid du Colombier *Rstwdogtimer = Basetickfreq / 100;
37*f43f8ee6SDavid du Colombier *Rstwdogctl = Wdogreset; /* wake the dog */
38*f43f8ee6SDavid du Colombier coherence();
39*f43f8ee6SDavid du Colombier *Rstwdogtimer = Basetickfreq / 10000;
40*f43f8ee6SDavid du Colombier coherence();
41*f43f8ee6SDavid du Colombier }
42*f43f8ee6SDavid du Colombier
43*f43f8ee6SDavid du Colombier void
stopwdog(void)44*f43f8ee6SDavid du Colombier stopwdog(void)
45*f43f8ee6SDavid du Colombier {
46*f43f8ee6SDavid du Colombier *Rstwdogtimer = ~0;
47*f43f8ee6SDavid du Colombier *Rstwdogctl = Wdognoaction; /* put the dog to sleep */
48*f43f8ee6SDavid du Colombier }
49*f43f8ee6SDavid du Colombier
50*f43f8ee6SDavid du Colombier void
clockshutdown(void)51*f43f8ee6SDavid du Colombier clockshutdown(void)
52*f43f8ee6SDavid du Colombier {
53*f43f8ee6SDavid du Colombier stopwdog();
54*f43f8ee6SDavid du Colombier }
55*f43f8ee6SDavid du Colombier
56*f43f8ee6SDavid du Colombier /*
57*f43f8ee6SDavid du Colombier * delay for l milliseconds more or less.
58*f43f8ee6SDavid du Colombier */
59*f43f8ee6SDavid du Colombier void
delay(int l)60*f43f8ee6SDavid du Colombier delay(int l)
61*f43f8ee6SDavid du Colombier {
62*f43f8ee6SDavid du Colombier while(l-- > 0)
63*f43f8ee6SDavid du Colombier microdelay(1000);
64*f43f8ee6SDavid du Colombier }
65*f43f8ee6SDavid du Colombier
66*f43f8ee6SDavid du Colombier /*
67*f43f8ee6SDavid du Colombier * microseconds delay
68*f43f8ee6SDavid du Colombier */
69*f43f8ee6SDavid du Colombier void
microdelay(int l)70*f43f8ee6SDavid du Colombier microdelay(int l)
71*f43f8ee6SDavid du Colombier {
72*f43f8ee6SDavid du Colombier int s;
73*f43f8ee6SDavid du Colombier ulong x, cyc, cnt, speed;
74*f43f8ee6SDavid du Colombier
75*f43f8ee6SDavid du Colombier speed = m->speed;
76*f43f8ee6SDavid du Colombier if (speed == 0)
77*f43f8ee6SDavid du Colombier speed = Basetickfreq / Mhz * Cyccntres;
78*f43f8ee6SDavid du Colombier cyc = (ulong)l * (speed / Cyccntres);
79*f43f8ee6SDavid du Colombier s = splhi();
80*f43f8ee6SDavid du Colombier cnt = rdcount();
81*f43f8ee6SDavid du Colombier x = cnt + cyc;
82*f43f8ee6SDavid du Colombier if (x < cnt || x >= ~0ul - Basetickfreq) {
83*f43f8ee6SDavid du Colombier /* counter will wrap between now and x, or x is too near ~0 */
84*f43f8ee6SDavid du Colombier wrcount(0); /* somewhat drastic */
85*f43f8ee6SDavid du Colombier wrcompare(rdcompare() - cnt); /* match new count */
86*f43f8ee6SDavid du Colombier x = cyc;
87*f43f8ee6SDavid du Colombier }
88*f43f8ee6SDavid du Colombier while(rdcount() < x)
89*f43f8ee6SDavid du Colombier ;
90*f43f8ee6SDavid du Colombier splx(s);
91*f43f8ee6SDavid du Colombier silencewdog();
92*f43f8ee6SDavid du Colombier }
93*f43f8ee6SDavid du Colombier
94*f43f8ee6SDavid du Colombier void
clock(Ureg * ureg)95*f43f8ee6SDavid du Colombier clock(Ureg *ureg)
96*f43f8ee6SDavid du Colombier {
97*f43f8ee6SDavid du Colombier wrcompare(rdcount()+m->maxperiod); /* side-effect: dismiss intr */
98*f43f8ee6SDavid du Colombier silencewdog();
99*f43f8ee6SDavid du Colombier timerintr(ureg, 0);
100*f43f8ee6SDavid du Colombier }
101*f43f8ee6SDavid du Colombier
102*f43f8ee6SDavid du Colombier enum {
103*f43f8ee6SDavid du Colombier Instrs = 10*Mhz,
104*f43f8ee6SDavid du Colombier };
105*f43f8ee6SDavid du Colombier
106*f43f8ee6SDavid du Colombier static long
issue1loop(void)107*f43f8ee6SDavid du Colombier issue1loop(void)
108*f43f8ee6SDavid du Colombier {
109*f43f8ee6SDavid du Colombier register int i;
110*f43f8ee6SDavid du Colombier long st;
111*f43f8ee6SDavid du Colombier
112*f43f8ee6SDavid du Colombier i = Instrs;
113*f43f8ee6SDavid du Colombier st = perfticks();
114*f43f8ee6SDavid du Colombier do {
115*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
116*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
117*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
118*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
119*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
120*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
121*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
122*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
123*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
124*f43f8ee6SDavid du Colombier --i; --i; --i; --i; --i;
125*f43f8ee6SDavid du Colombier /* omit 3 (--i) to account for conditional branch, nop & jump */
126*f43f8ee6SDavid du Colombier i -= 1+3; /* --i plus 3 omitted (--i) instructions */
127*f43f8ee6SDavid du Colombier } while(--i >= 0);
128*f43f8ee6SDavid du Colombier return perfticks() - st;
129*f43f8ee6SDavid du Colombier }
130*f43f8ee6SDavid du Colombier
131*f43f8ee6SDavid du Colombier /* estimate instructions/s. */
132*f43f8ee6SDavid du Colombier static int
guessmips(long (* loop)(void),char *)133*f43f8ee6SDavid du Colombier guessmips(long (*loop)(void), char *)
134*f43f8ee6SDavid du Colombier {
135*f43f8ee6SDavid du Colombier int s;
136*f43f8ee6SDavid du Colombier long cyc;
137*f43f8ee6SDavid du Colombier
138*f43f8ee6SDavid du Colombier do {
139*f43f8ee6SDavid du Colombier s = splhi();
140*f43f8ee6SDavid du Colombier cyc = loop();
141*f43f8ee6SDavid du Colombier splx(s);
142*f43f8ee6SDavid du Colombier if (cyc < 0)
143*f43f8ee6SDavid du Colombier iprint("again...");
144*f43f8ee6SDavid du Colombier } while (cyc < 0);
145*f43f8ee6SDavid du Colombier /*
146*f43f8ee6SDavid du Colombier * Instrs instructions took cyc cycles @ Basetickfreq Hz.
147*f43f8ee6SDavid du Colombier * round the result.
148*f43f8ee6SDavid du Colombier */
149*f43f8ee6SDavid du Colombier return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz;
150*f43f8ee6SDavid du Colombier }
151*f43f8ee6SDavid du Colombier
152*f43f8ee6SDavid du Colombier void
clockinit(void)153*f43f8ee6SDavid du Colombier clockinit(void)
154*f43f8ee6SDavid du Colombier {
155*f43f8ee6SDavid du Colombier int mips;
156*f43f8ee6SDavid du Colombier
157*f43f8ee6SDavid du Colombier silencewdog();
158*f43f8ee6SDavid du Colombier
159*f43f8ee6SDavid du Colombier /*
160*f43f8ee6SDavid du Colombier * calibrate fastclock
161*f43f8ee6SDavid du Colombier */
162*f43f8ee6SDavid du Colombier mips = guessmips(issue1loop, "single");
163*f43f8ee6SDavid du Colombier
164*f43f8ee6SDavid du Colombier /*
165*f43f8ee6SDavid du Colombier * m->delayloop should be the number of delay loop iterations
166*f43f8ee6SDavid du Colombier * needed to consume 1 ms, assuming 2 instr'ns in the delay loop.
167*f43f8ee6SDavid du Colombier */
168*f43f8ee6SDavid du Colombier m->delayloop = mips*Mhz / (1000 * 2);
169*f43f8ee6SDavid du Colombier if(m->delayloop == 0)
170*f43f8ee6SDavid du Colombier m->delayloop = 1;
171*f43f8ee6SDavid du Colombier
172*f43f8ee6SDavid du Colombier m->speed = mips;
173*f43f8ee6SDavid du Colombier m->hz = m->speed*Mhz;
174*f43f8ee6SDavid du Colombier
175*f43f8ee6SDavid du Colombier m->maxperiod = Basetickfreq / HZ;
176*f43f8ee6SDavid du Colombier m->minperiod = Basetickfreq / (100*HZ);
177*f43f8ee6SDavid du Colombier wrcompare(rdcount()+m->maxperiod);
178*f43f8ee6SDavid du Colombier
179*f43f8ee6SDavid du Colombier /*
180*f43f8ee6SDavid du Colombier * desynchronize the processor clocks so that they all don't
181*f43f8ee6SDavid du Colombier * try to resched at the same time.
182*f43f8ee6SDavid du Colombier */
183*f43f8ee6SDavid du Colombier delay(m->machno*2);
184*f43f8ee6SDavid du Colombier
185*f43f8ee6SDavid du Colombier syncclock();
186*f43f8ee6SDavid du Colombier intron(INTR7);
187*f43f8ee6SDavid du Colombier }
188*f43f8ee6SDavid du Colombier
189*f43f8ee6SDavid du Colombier /*
190*f43f8ee6SDavid du Colombier * Tval is supposed to be in fastticks units.
191*f43f8ee6SDavid du Colombier * One fasttick unit is 1/Basetickfreq seconds.
192*f43f8ee6SDavid du Colombier */
193*f43f8ee6SDavid du Colombier void
timerset(Tval next)194*f43f8ee6SDavid du Colombier timerset(Tval next)
195*f43f8ee6SDavid du Colombier {
196*f43f8ee6SDavid du Colombier int x;
197*f43f8ee6SDavid du Colombier long period;
198*f43f8ee6SDavid du Colombier
199*f43f8ee6SDavid du Colombier if(next == 0)
200*f43f8ee6SDavid du Colombier return;
201*f43f8ee6SDavid du Colombier x = splhi(); /* don't let us get scheduled */
202*f43f8ee6SDavid du Colombier period = next - fastticks(nil);
203*f43f8ee6SDavid du Colombier if(period > m->maxperiod - m->minperiod)
204*f43f8ee6SDavid du Colombier period = m->maxperiod;
205*f43f8ee6SDavid du Colombier else if(period < m->minperiod)
206*f43f8ee6SDavid du Colombier period = m->minperiod;
207*f43f8ee6SDavid du Colombier wrcompare(rdcount()+period);
208*f43f8ee6SDavid du Colombier silencewdog();
209*f43f8ee6SDavid du Colombier splx(x);
210*f43f8ee6SDavid du Colombier }
211*f43f8ee6SDavid du Colombier
212*f43f8ee6SDavid du Colombier /*
213*f43f8ee6SDavid du Colombier * The rewriting of compare in this routine shouldn't be necessary.
214*f43f8ee6SDavid du Colombier * However, we lose clock interrupts if I don't, either a chip bug
215*f43f8ee6SDavid du Colombier * or one of ours -- presotto
216*f43f8ee6SDavid du Colombier */
217*f43f8ee6SDavid du Colombier uvlong
fastticks(uvlong * hz)218*f43f8ee6SDavid du Colombier fastticks(uvlong *hz)
219*f43f8ee6SDavid du Colombier {
220*f43f8ee6SDavid du Colombier int x;
221*f43f8ee6SDavid du Colombier ulong delta, count;
222*f43f8ee6SDavid du Colombier
223*f43f8ee6SDavid du Colombier if(hz)
224*f43f8ee6SDavid du Colombier *hz = Basetickfreq;
225*f43f8ee6SDavid du Colombier
226*f43f8ee6SDavid du Colombier /* avoid reentry on interrupt or trap, to prevent recursion */
227*f43f8ee6SDavid du Colombier x = splhi();
228*f43f8ee6SDavid du Colombier count = rdcount();
229*f43f8ee6SDavid du Colombier if(rdcompare() - count > m->maxperiod)
230*f43f8ee6SDavid du Colombier wrcompare(count+m->maxperiod);
231*f43f8ee6SDavid du Colombier silencewdog();
232*f43f8ee6SDavid du Colombier
233*f43f8ee6SDavid du Colombier if (count < m->lastcount) /* wrapped around? */
234*f43f8ee6SDavid du Colombier delta = count + ((1ull<<32) - m->lastcount);
235*f43f8ee6SDavid du Colombier else
236*f43f8ee6SDavid du Colombier delta = count - m->lastcount;
237*f43f8ee6SDavid du Colombier m->lastcount = count;
238*f43f8ee6SDavid du Colombier m->fastticks += delta;
239*f43f8ee6SDavid du Colombier splx(x);
240*f43f8ee6SDavid du Colombier return m->fastticks;
241*f43f8ee6SDavid du Colombier }
242*f43f8ee6SDavid du Colombier
243*f43f8ee6SDavid du Colombier ulong
s(void)244*f43f8ee6SDavid du Colombier µs(void)
245*f43f8ee6SDavid du Colombier {
246*f43f8ee6SDavid du Colombier return fastticks2us(fastticks(nil));
247*f43f8ee6SDavid du Colombier }
248*f43f8ee6SDavid du Colombier
249*f43f8ee6SDavid du Colombier /*
250*f43f8ee6SDavid du Colombier * performance measurement ticks. must be low overhead.
251*f43f8ee6SDavid du Colombier * doesn't have to count over a second.
252*f43f8ee6SDavid du Colombier */
253*f43f8ee6SDavid du Colombier ulong
perfticks(void)254*f43f8ee6SDavid du Colombier perfticks(void)
255*f43f8ee6SDavid du Colombier {
256*f43f8ee6SDavid du Colombier return rdcount();
257*f43f8ee6SDavid du Colombier }
258*f43f8ee6SDavid du Colombier
259*f43f8ee6SDavid du Colombier long
lcycles(void)260*f43f8ee6SDavid du Colombier lcycles(void)
261*f43f8ee6SDavid du Colombier {
262*f43f8ee6SDavid du Colombier return perfticks();
263*f43f8ee6SDavid du Colombier }
264*f43f8ee6SDavid du Colombier
265*f43f8ee6SDavid du Colombier /* should use vlong hw counters ideally; lcycles is inadequate */
266*f43f8ee6SDavid du Colombier void
cycles(uvlong * cycp)267*f43f8ee6SDavid du Colombier cycles(uvlong *cycp)
268*f43f8ee6SDavid du Colombier {
269*f43f8ee6SDavid du Colombier *cycp = fastticks(nil);
270*f43f8ee6SDavid du Colombier }
271*f43f8ee6SDavid du Colombier
272*f43f8ee6SDavid du Colombier Lock mpsynclock;
273*f43f8ee6SDavid du Colombier
274*f43f8ee6SDavid du Colombier /*
275*f43f8ee6SDavid du Colombier * synchronize all clocks with processor 0
276*f43f8ee6SDavid du Colombier */
277*f43f8ee6SDavid du Colombier void
syncclock(void)278*f43f8ee6SDavid du Colombier syncclock(void)
279*f43f8ee6SDavid du Colombier {
280*f43f8ee6SDavid du Colombier uvlong x;
281*f43f8ee6SDavid du Colombier
282*f43f8ee6SDavid du Colombier if(m->machno == 0){
283*f43f8ee6SDavid du Colombier m->lastcount = rdcount();
284*f43f8ee6SDavid du Colombier m->fastticks = 0;
285*f43f8ee6SDavid du Colombier m->ticks = 0;
286*f43f8ee6SDavid du Colombier wrcompare(rdcount()+m->maxperiod);
287*f43f8ee6SDavid du Colombier } else {
288*f43f8ee6SDavid du Colombier /* wait for processor 0's soft clock to change and then sync ours */
289*f43f8ee6SDavid du Colombier lock(&mpsynclock);
290*f43f8ee6SDavid du Colombier x = MACHP(0)->fastticks;
291*f43f8ee6SDavid du Colombier while(MACHP(0)->fastticks == x)
292*f43f8ee6SDavid du Colombier ;
293*f43f8ee6SDavid du Colombier m->lastcount = rdcount();
294*f43f8ee6SDavid du Colombier m->fastticks = MACHP(0)->fastticks;
295*f43f8ee6SDavid du Colombier m->ticks = MACHP(0)->ticks;
296*f43f8ee6SDavid du Colombier wrcompare(rdcount()+m->maxperiod);
297*f43f8ee6SDavid du Colombier unlock(&mpsynclock);
298*f43f8ee6SDavid du Colombier }
299*f43f8ee6SDavid du Colombier }
300