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