xref: /original-bsd/sys/sparc/sparc/clock.c (revision f4a18198)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This software was developed by the Computer Systems Engineering group
6  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
7  * contributed to Berkeley.
8  *
9  * All advertising materials mentioning features or use of this software
10  * must display the following acknowledgement:
11  *	This product includes software developed by the University of
12  *	California, Lawrence Berkeley Laboratory.
13  *
14  * %sccs.include.redist.c%
15  *
16  *	@(#)clock.c	8.2 (Berkeley) 05/08/94
17  *
18  * from: $Header: clock.c,v 1.17 92/11/26 03:04:47 torek Exp $ (LBL)
19  */
20 
21 /*
22  * Clock driver.  This is the id prom (``eeprom'') driver as well
23  * and includes the timer register functions too.
24  */
25 
26 #include <sys/param.h>
27 #include <sys/kernel.h>
28 #include <sys/device.h>
29 #include <sys/proc.h>
30 #include <sys/resourcevar.h>
31 #ifdef GPROF
32 #include <sys/gmon.h>
33 #endif
34 
35 #include <vm/vm.h>
36 
37 #include <machine/autoconf.h>
38 
39 #include <sparc/sparc/clockreg.h>
40 #include <sparc/sparc/intreg.h>
41 #include <sparc/sparc/timerreg.h>
42 
43 /*
44  * Statistics clock interval and variance, in usec.  Variance must be a
45  * power of two.  Since this gives us an even number, not an odd number,
46  * we discard one case and compensate.  That is, a variance of 1024 would
47  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
48  * This is symmetric about the point 512, or statvar/2, and thus averages
49  * to that value (assuming uniform random numbers).
50  */
51 /* XXX fix comment to match value */
52 int statvar = 8192;
53 int statmin;			/* statclock interval - 1/2*variance */
54 
55 static int clockmatch __P((struct device *, struct cfdata *, void *));
56 static void clockattach __P((struct device *, struct device *, void *));
57 
58 struct cfdriver clockcd =
59     { NULL, "clock", clockmatch, clockattach, DV_DULL, sizeof(struct device) };
60 
61 static int timermatch __P((struct device *, struct cfdata *, void *));
62 static void timerattach __P((struct device *, struct device *, void *));
63 struct cfdriver timercd =
64     { NULL, "timer", timermatch, timerattach, DV_DULL, sizeof(struct device) };
65 
66 /*
67  * The OPENPROM calls the clock the "eeprom", so we have to have our
68  * own special match function to call it the "clock".
69  */
70 static int
71 clockmatch(parent, cf, aux)
72 	struct device *parent;
73 	struct cfdata *cf;
74 	void *aux;
75 {
76 
77 	return (strcmp("eeprom", ((struct romaux *)aux)->ra_name) == 0);
78 }
79 
80 /* ARGSUSED */
81 static void
82 clockattach(parent, self, aux)
83 	struct device *parent, *self;
84 	void *aux;
85 {
86 	register int h;
87 	register struct clockreg *cl;
88 	struct romaux *ra = aux;
89 
90 	printf(": %s (eeprom)\n", getpropstring(ra->ra_node, "model"));
91 	/*
92 	 * We ignore any existing virtual address as we need to map
93 	 * this read-only and make it read-write only temporarily,
94 	 * whenever we read or write the clock chip.  The clock also
95 	 * contains the ID ``PROM'', and I have already had the pleasure
96 	 * of reloading the cpu type, Ethernet address, etc, by hand from
97 	 * the console FORTH interpreter.  I intend not to enjoy it again.
98 	 */
99 	cl = (struct clockreg *)mapiodev(ra->ra_paddr, sizeof *clockreg);
100 	pmap_changeprot(kernel_pmap, (vm_offset_t)clockreg, VM_PROT_READ, 1);
101 	h = cl->cl_idprom.id_machine << 24;
102 	h |= cl->cl_idprom.id_hostid[0] << 16;
103 	h |= cl->cl_idprom.id_hostid[1] << 8;
104 	h |= cl->cl_idprom.id_hostid[2];
105 	hostid = h;
106 	clockreg = cl;
107 }
108 
109 /*
110  * The OPENPROM calls the timer the "counter-timer".
111  */
112 static int
113 timermatch(parent, cf, aux)
114 	struct device *parent;
115 	struct cfdata *cf;
116 	void *aux;
117 {
118 
119 	return (strcmp("counter-timer", ((struct romaux *)aux)->ra_name) == 0);
120 }
121 
122 /* ARGSUSED */
123 static void
124 timerattach(parent, self, aux)
125 	struct device *parent, *self;
126 	void *aux;
127 {
128 	register struct romaux *ra = aux;
129 
130 	printf("\n");
131 	/*
132 	 * This time, we ignore any existing virtual address because
133 	 * we have a fixed virtual address for the timer, to make
134 	 * microtime() faster.
135 	 */
136 	(void)mapdev(ra->ra_paddr, TIMERREG_VA, sizeof(struct timerreg));
137 	/* should link interrupt handlers here, rather than compiled-in? */
138 }
139 
140 /*
141  * Write en/dis-able clock registers.  We coordinate so that several
142  * writers can run simultaneously.
143  */
144 void
145 clk_wenable(onoff)
146 	int onoff;
147 {
148 	register int s;
149 	register vm_prot_t prot;/* nonzero => change prot */
150 	static int writers;
151 
152 	s = splhigh();
153 	if (onoff)
154 		prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
155 	else
156 		prot = --writers == 0 ? VM_PROT_READ : 0;
157 	splx(s);
158 	if (prot)
159 		pmap_changeprot(kernel_pmap, (vm_offset_t)clockreg, prot, 1);
160 }
161 
162 /*
163  * XXX this belongs elsewhere
164  */
165 void
166 myetheraddr(cp)
167 	u_char *cp;
168 {
169 	register struct clockreg *cl = clockreg;
170 
171 	cp[0] = cl->cl_idprom.id_ether[0];
172 	cp[1] = cl->cl_idprom.id_ether[1];
173 	cp[2] = cl->cl_idprom.id_ether[2];
174 	cp[3] = cl->cl_idprom.id_ether[3];
175 	cp[4] = cl->cl_idprom.id_ether[4];
176 	cp[5] = cl->cl_idprom.id_ether[5];
177 }
178 
179 /*
180  * Delay: wait for `about' n microseconds to pass.
181  * This is easy to do on the SparcStation since we have
182  * freerunning microsecond timers -- no need to guess at
183  * cpu speed factors.  We just wait for it to change n times
184  * (if we calculated a limit, we might overshoot, and precision
185  * is irrelevant here---we want less object code).
186  */
187 delay(n)
188 	register int n;
189 {
190 	register int c, t;
191 
192 	if (timercd.cd_ndevs == 0)
193 		panic("delay");
194 	c = TIMERREG->t_c10.t_counter;
195 	while (--n >= 0) {
196 		while ((t = TIMERREG->t_c10.t_counter) == c)
197 			continue;
198 		c = t;
199 	}
200 }
201 
202 /*
203  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
204  * no alternative timer is available.
205  *
206  * The frequencies of these clocks must be an even number of microseconds.
207  */
208 cpu_initclocks()
209 {
210 	register int statint, minint;
211 
212 	if (1000000 % hz) {
213 		printf("cannot get %d Hz clock; using 100 Hz\n", hz);
214 		hz = 100;
215 		tick = 1000000 / hz;
216 	}
217 	if (stathz == 0)
218 		stathz = hz;
219 	if (1000000 % stathz) {
220 		printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
221 		stathz = 100;
222 	}
223 	profhz = stathz;		/* always */
224 
225 	statint = 1000000 / stathz;
226 	minint = statint / 2 + 100;
227 	while (statvar > minint)
228 		statvar >>= 1;
229 	TIMERREG->t_c10.t_limit = tmr_ustolim(tick);
230 	TIMERREG->t_c14.t_limit = tmr_ustolim(statint);
231 	statmin = statint - (statvar >> 1);
232 	ienab_bis(IE_L14 | IE_L10);
233 }
234 
235 /*
236  * Dummy setstatclockrate(), since we know profhz==hz.
237  */
238 /* ARGSUSED */
239 void
240 setstatclockrate(newhz)
241 	int newhz;
242 {
243 	/* nothing */
244 }
245 
246 /*
247  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
248  * console input, we need to check for that here as well, and generate
249  * a software interrupt to read it.
250  */
251 int
252 clockintr(cap)
253 	void *cap;
254 {
255 	register int discard;
256 	extern int rom_console_input;
257 
258 	/* read the limit register to clear the interrupt */
259 	discard = TIMERREG->t_c10.t_limit;
260 	hardclock((struct clockframe *)cap);
261 	if (rom_console_input && cnrom())
262 		setsoftint();
263 
264 	return (1);
265 }
266 
267 /*
268  * Level 14 (stat clock) interrupt handler.
269  */
270 int
271 statintr(cap)
272 	void *cap;
273 {
274 	register int discard;
275 	register u_long newint, r, var;
276 
277 	/* read the limit register to clear the interrupt */
278 	discard = TIMERREG->t_c14.t_limit;
279 	statclock((struct clockframe *)cap);
280 
281 	/*
282 	 * Compute new randomized interval.  The intervals are uniformly
283 	 * distributed on [statint - statvar / 2, statint + statvar / 2],
284 	 * and therefore have mean statint, giving a stathz frequency clock.
285 	 */
286 	var = statvar;
287 	do {
288 		r = random() & (var - 1);
289 	} while (r == 0);
290 	newint = statmin + r;
291 
292 	TIMERREG->t_c14.t_limit = tmr_ustolim(newint);
293 	return (1);
294 }
295 
296 /*
297  * BCD to decimal and decimal to BCD.
298  */
299 #define	FROMBCD(x)	(((x) >> 4) * 10 + ((x) & 0xf))
300 #define	TOBCD(x)	(((x) / 10 * 16) + ((x) % 10))
301 
302 #define	SECDAY		(24 * 60 * 60)
303 #define	SECYR		(SECDAY * 365)
304 #define	LEAPYEAR(y)	(((y) & 3) == 0)
305 
306 /*
307  * This code is defunct after 2068.
308  * Will Unix still be here then??
309  */
310 const short dayyr[12] =
311     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
312 
313 chiptotime(sec, min, hour, day, mon, year)
314 	register int sec, min, hour, day, mon, year;
315 {
316 	register int days, yr;
317 
318 	sec = FROMBCD(sec);
319 	min = FROMBCD(min);
320 	hour = FROMBCD(hour);
321 	day = FROMBCD(day);
322 	mon = FROMBCD(mon);
323 	year = FROMBCD(year) + YEAR0;
324 
325 	/* simple sanity checks */
326 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31)
327 		return (0);
328 	days = 0;
329 	for (yr = 70; yr < year; yr++)
330 		days += LEAPYEAR(yr) ? 366 : 365;
331 	days += dayyr[mon - 1] + day - 1;
332 	if (LEAPYEAR(yr) && mon > 2)
333 		days++;
334 	/* now have days since Jan 1, 1970; the rest is easy... */
335 	return (days * SECDAY + hour * 3600 + min * 60 + sec);
336 }
337 
338 struct chiptime {
339 	int	sec;
340 	int	min;
341 	int	hour;
342 	int	wday;
343 	int	day;
344 	int	mon;
345 	int	year;
346 };
347 
348 timetochip(c)
349 	register struct chiptime *c;
350 {
351 	register int t, t2, t3, now = time.tv_sec;
352 
353 	/* compute the year */
354 	t2 = now / SECDAY;
355 	t3 = (t2 + 2) % 7;	/* day of week */
356 	c->wday = TOBCD(t3 + 1);
357 
358 	t = 69;
359 	while (t2 >= 0) {	/* whittle off years */
360 		t3 = t2;
361 		t++;
362 		t2 -= LEAPYEAR(t) ? 366 : 365;
363 	}
364 	c->year = t;
365 
366 	/* t3 = month + day; separate */
367 	t = LEAPYEAR(t);
368 	for (t2 = 1; t2 < 12; t2++)
369 		if (t3 < dayyr[t2] + (t && t2 > 1))
370 			break;
371 
372 	/* t2 is month */
373 	c->mon = t2;
374 	c->day = t3 - dayyr[t2 - 1] + 1;
375 	if (t && t2 > 2)
376 		c->day--;
377 
378 	/* the rest is easy */
379 	t = now % SECDAY;
380 	c->hour = t / 3600;
381 	t %= 3600;
382 	c->min = t / 60;
383 	c->sec = t % 60;
384 
385 	c->sec = TOBCD(c->sec);
386 	c->min = TOBCD(c->min);
387 	c->hour = TOBCD(c->hour);
388 	c->day = TOBCD(c->day);
389 	c->mon = TOBCD(c->mon);
390 	c->year = TOBCD(c->year - YEAR0);
391 }
392 
393 /*
394  * Set up the system's time, given a `reasonable' time value.
395  */
396 inittodr(base)
397 	time_t base;
398 {
399 	register struct clockreg *cl = clockreg;
400 	int sec, min, hour, day, mon, year;
401 	int badbase = 0;
402 
403 	if (base < 5 * SECYR) {
404 		printf("WARNING: preposterous time in file system\n");
405 		/* not going to use it anyway, if the chip is readable */
406 		base = 21*SECYR + 186*SECDAY + SECDAY/2;
407 		badbase = 1;
408 	}
409 	clk_wenable(1);
410 	cl->cl_csr |= CLK_READ;		/* enable read (stop time) */
411 	sec = cl->cl_sec;
412 	min = cl->cl_min;
413 	hour = cl->cl_hour;
414 	day = cl->cl_mday;
415 	mon = cl->cl_month;
416 	year = cl->cl_year;
417 	cl->cl_csr &= ~CLK_READ;	/* time wears on */
418 	clk_wenable(0);
419 	if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) {
420 		printf("WARNING: bad date in battery clock");
421 		/*
422 		 * Believe the time in the file system for lack of
423 		 * anything better, resetting the clock.
424 		 */
425 		time.tv_sec = base;
426 		if (!badbase)
427 			resettodr();
428 	} else {
429 		int deltat = time.tv_sec - base;
430 
431 		if (deltat < 0)
432 			deltat = -deltat;
433 		if (deltat < 2 * SECDAY)
434 			return;
435 		printf("WARNING: clock %s %d days",
436 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
437 	}
438 	printf(" -- CHECK AND RESET THE DATE!\n");
439 }
440 
441 /*
442  * Reset the clock based on the current time.
443  * Used when the current clock is preposterous, when the time is changed,
444  * and when rebooting.  Do nothing if the time is not yet known, e.g.,
445  * when crashing during autoconfig.
446  */
447 resettodr()
448 {
449 	register struct clockreg *cl;
450 	struct chiptime c;
451 
452 	if (!time.tv_sec || (cl = clockreg) == NULL)
453 		return;
454 	timetochip(&c);
455 	clk_wenable(1);
456 	cl->cl_csr |= CLK_WRITE;	/* enable write */
457 	cl->cl_sec = c.sec;
458 	cl->cl_min = c.min;
459 	cl->cl_hour = c.hour;
460 	cl->cl_wday = c.wday;
461 	cl->cl_mday = c.day;
462 	cl->cl_month = c.mon;
463 	cl->cl_year = c.year;
464 	cl->cl_csr &= ~CLK_WRITE;	/* load them up */
465 	clk_wenable(0);
466 }
467