1 /*	$OpenBSD: clock.c,v 1.19 2004/04/08 01:11:21 deraadt Exp $	*/
2 /*	$NetBSD: clock.c,v 1.52 1997/05/24 20:16:05 pk Exp $ */
3 
4 /*
5  * Copyright (c) 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  * Copyright (c) 1994 Gordon W. Ross
8  * Copyright (c) 1993 Adam Glass
9  * Copyright (c) 1996 Paul Kranenburg
10  * Copyright (c) 1996
11  * 	The President and Fellows of Harvard College. All rights reserved.
12  *
13  * This software was developed by the Computer Systems Engineering group
14  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
15  * contributed to Berkeley.
16  *
17  * All advertising materials mentioning features or use of this software
18  * must display the following acknowledgement:
19  *	This product includes software developed by Harvard University.
20  *	This product includes software developed by the University of
21  *	California, Lawrence Berkeley Laboratory.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  * 2. Redistributions in binary form must reproduce the above copyright
30  *    notice, this list of conditions and the following disclaimer in the
31  *    documentation and/or other materials provided with the distribution.
32  * 3. All advertising materials mentioning features or use of this software
33  *    must display the following acknowledgement:
34  *	This product includes software developed by the University of
35  *	California, Berkeley and its contributors.
36  *	This product includes software developed by Paul Kranenburg.
37  *	This product includes software developed by Harvard University.
38  * 4. Neither the name of the University nor the names of its contributors
39  *    may be used to endorse or promote products derived from this software
40  *    without specific prior written permission.
41  *
42  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52  * SUCH DAMAGE.
53  *
54  *	@(#)clock.c	8.1 (Berkeley) 6/11/93
55  *
56  */
57 
58 /*
59  * Clock driver.  This is the id prom and eeprom driver as well
60  * and includes the timer register functions too.
61  */
62 
63 #include <sys/param.h>
64 #include <sys/kernel.h>
65 #include <sys/device.h>
66 #include <sys/proc.h>
67 #include <sys/resourcevar.h>
68 #include <sys/malloc.h>
69 #include <sys/systm.h>
70 
71 #include <dev/rndvar.h>
72 
73 #include <uvm/uvm_extern.h>
74 
75 #include <machine/autoconf.h>
76 #include <machine/eeprom.h>
77 #include <machine/cpu.h>
78 
79 #include <sparc/sparc/vaddrs.h>
80 #include <sparc/sparc/cpuvar.h>
81 #include <sparc/sparc/clockreg.h>
82 #include <sparc/sparc/intreg.h>
83 #include <sparc/sparc/timerreg.h>
84 
85 /*
86  * Statistics clock interval and variance, in usec.  Variance must be a
87  * power of two.  Since this gives us an even number, not an odd number,
88  * we discard one case and compensate.  That is, a variance of 1024 would
89  * give us offsets in [0..1023].  Instead, we take offsets in [1..1023].
90  * This is symmetric about the point 512, or statvar/2, and thus averages
91  * to that value (assuming uniform random numbers).
92  */
93 /* XXX fix comment to match value */
94 int statvar = 8192;
95 int statmin;			/* statclock interval - 1/2*variance */
96 int timerok;
97 
98 #include <dev/ic/intersil7170.h>
99 
100 extern struct idprom idprom;
101 
102 #define intersil_command(run, interrupt) \
103     (run | interrupt | INTERSIL_CMD_FREQ_32K | INTERSIL_CMD_24HR_MODE | \
104      INTERSIL_CMD_NORMAL_MODE)
105 
106 #define intersil_disable(CLOCK) \
107     CLOCK->clk_cmd_reg = \
108     intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IDISABLE)
109 
110 #define intersil_enable(CLOCK) \
111     CLOCK->clk_cmd_reg = \
112     intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE)
113 
114 #define intersil_clear(CLOCK) CLOCK->clk_intr_reg
115 
116 #if defined(SUN4)
117 /*
118  * OCLOCK support: 4/100's and 4/200's have the old clock.
119  */
120 static int oldclk = 0;
121 struct intersil7170 *i7;
122 
123 long	oclk_get_secs(void);
124 void	oclk_get_dt(struct intersil_dt *);
125 void	dt_to_gmt(struct intersil_dt *, long *);
126 void	oclk_set_dt(struct intersil_dt *);
127 void	oclk_set_secs(long);
128 void	gmt_to_dt(long *, struct intersil_dt *);
129 #endif
130 
131 int	oclockmatch(struct device *, void *, void *);
132 void	oclockattach(struct device *, struct device *, void *);
133 
134 struct cfattach oclock_ca = {
135 	sizeof(struct device), oclockmatch, oclockattach
136 };
137 
138 struct cfdriver oclock_cd = {
139 	NULL, "oclock", DV_DULL
140 };
141 
142 /*
143  * Sun 4 machines use the old-style (a'la Sun 3) EEPROM.  On the
144  * 4/100's and 4/200's, this is at a separate obio space.  On the
145  * 4/300's and 4/400's, however, it is the cl_nvram[] chunk of the
146  * Mostek chip.  Therefore, eeprom_match will only return true on
147  * the 100/200 models, and the eeprom will be attached separately.
148  * On the 300/400 models, the eeprom will be dealt with when the clock is
149  * attached.
150  */
151 char		*eeprom_va = NULL;
152 #if defined(SUN4)
153 static int	eeprom_busy = 0;
154 static int	eeprom_wanted = 0;
155 static int	eeprom_nvram = 0;	/* non-zero if eeprom is on Mostek */
156 int	eeprom_take(void);
157 void	eeprom_give(void);
158 int	eeprom_update(char *, int, int);
159 #endif
160 
161 int	eeprom_match(struct device *, void *, void *);
162 void	eeprom_attach(struct device *, struct device *, void *);
163 
164 struct cfattach eeprom_ca = {
165 	sizeof(struct device), eeprom_match, eeprom_attach
166 };
167 
168 struct	cfdriver eeprom_cd = {
169 	NULL, "eeprom", DV_DULL
170 };
171 
172 int	clockmatch(struct device *, void *, void *);
173 void	clockattach(struct device *, struct device *, void *);
174 
175 struct cfattach clock_ca = {
176 	sizeof(struct device), clockmatch, clockattach
177 };
178 
179 struct cfdriver clock_cd = {
180 	NULL, "clock", DV_DULL
181 };
182 
183 int	timermatch(struct device *, void *, void *);
184 void	timerattach(struct device *, struct device *, void *);
185 
186 struct timer_4m	*timerreg_4m;	/* XXX - need more cleanup */
187 struct counter_4m	*counterreg_4m;
188 #define	timerreg4		((struct timerreg_4 *)TIMERREG_VA)
189 
190 struct cfattach timer_ca = {
191 	sizeof(struct device), timermatch, timerattach
192 };
193 
194 struct cfdriver timer_cd = {
195 	NULL, "timer", DV_DULL
196 };
197 
198 struct chiptime;
199 void clk_wenable(int);
200 void myetheraddr(u_char *);
201 int chiptotime(int, int, int, int, int, int);
202 void timetochip(struct chiptime *);
203 
204 int timerblurb = 10; /* Guess a value; used before clock is attached */
205 
206 /*
207  * old clock match routine
208  */
209 int
oclockmatch(parent,vcf,aux)210 oclockmatch(parent, vcf, aux)
211 	struct device *parent;
212 	void *vcf, *aux;
213 {
214 	struct confargs *ca = aux;
215 
216 	/* Only these sun4s have oclock */
217 	if (!CPU_ISSUN4 ||
218 	    (cpuinfo.cpu_type != CPUTYP_4_100 &&
219 	     cpuinfo.cpu_type != CPUTYP_4_200))
220 		return (0);
221 
222 	/* Check configuration name */
223 	if (strcmp(oclock_cd.cd_name, ca->ca_ra.ra_name) != 0)
224 		return (0);
225 
226 	/* Make sure there is something there */
227 	if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
228 		return (0);
229 
230 	return (1);
231 }
232 
233 /* ARGSUSED */
234 void
oclockattach(parent,self,aux)235 oclockattach(parent, self, aux)
236 	struct device *parent, *self;
237 	void *aux;
238 {
239 #if defined(SUN4)
240 	struct confargs *ca = aux;
241 	struct romaux *ra = &ca->ca_ra;
242 	struct idprom *idp;
243 	int h;
244 
245 	oldclk = 1;  /* we've got an oldie! */
246 
247 	i7 = (struct intersil7170 *) mapiodev(ra->ra_reg, 0, sizeof(*i7));
248 
249 	idp = &idprom;
250 	h = idp->id_machine << 24;
251 	h |= idp->id_hostid[0] << 16;
252 	h |= idp->id_hostid[1] << 8;
253 	h |= idp->id_hostid[2];
254 	hostid = h;
255 
256 	/*
257 	 * calibrate delay()
258 	 */
259 	ienab_bic(IE_L14 | IE_L10);	/* disable all clock intrs */
260 	for (timerblurb = 1; ; timerblurb++) {
261 		volatile register char *ireg = &i7->clk_intr_reg;
262 		int ival;
263 		*ireg = INTERSIL_INTER_CSECONDS; /* 1/100 sec */
264 		intersil_enable(i7);		 /* enable clock */
265 		while ((*ireg & INTERSIL_INTER_PENDING) == 0)
266 			/* sync with interrupt */;
267 		while ((*ireg & INTERSIL_INTER_PENDING) == 0)
268 			/* XXX: do it again, seems to need it */;
269 		delay(10000);			/* Probe 1/100 sec delay */
270 		ival = *ireg;			/* clear, save value */
271 		intersil_disable(i7);		/* disable clock */
272 		if (ival & INTERSIL_INTER_PENDING) {
273 			printf(" delay constant %d%s\n", timerblurb,
274 				(timerblurb == 1) ? " [TOO SMALL?]" : "");
275 			break;
276 		}
277 		if (timerblurb > 10) {
278 			printf("\noclock: calibration failing; clamped at %d\n",
279 			       timerblurb);
280 			break;
281 		}
282 	}
283 #endif /* SUN4 */
284 }
285 
286 /*
287  * Sun 4/100, 4/200 EEPROM match routine.
288  */
289 int
eeprom_match(parent,vcf,aux)290 eeprom_match(parent, vcf, aux)
291 	struct device *parent;
292 	void *vcf, *aux;
293 {
294 	struct cfdata *cf = vcf;
295 	struct confargs *ca = aux;
296 
297 	if (!CPU_ISSUN4)
298 		return (0);
299 
300 	if (cf->cf_unit != 0)
301 		return (0);
302 
303 	if (cpuinfo.cpu_type != CPUTYP_4_100 &&
304 	    cpuinfo.cpu_type != CPUTYP_4_200)
305 		return (0);
306 
307 	if (strcmp(eeprom_cd.cd_name, ca->ca_ra.ra_name) != 0)
308 		return (0);
309 
310 	/*
311 	 * Make sure there's something there...
312 	 * This is especially important if we want to
313 	 * use the same kernel on a 4/100 as a 4/200.
314 	 */
315 	if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
316 		return (0);
317 
318 	/* Passed all tests */
319 	return (1);
320 }
321 
322 void
eeprom_attach(parent,self,aux)323 eeprom_attach(parent, self, aux)
324 	struct device *parent, *self;
325 	void *aux;
326 {
327 #if defined(SUN4)
328 	struct confargs *ca = aux;
329 	struct romaux *ra = &ca->ca_ra;
330 
331 	printf("\n");
332 
333 	eeprom_va = (char *)mapiodev(ra->ra_reg, 0, EEPROM_SIZE);
334 
335 	eeprom_nvram = 0;
336 #endif /* SUN4 */
337 }
338 
339 /*
340  * The OPENPROM calls the clock the "eeprom", so we have to have our
341  * own special match function to call it the "clock".
342  */
343 int
clockmatch(parent,vcf,aux)344 clockmatch(parent, vcf, aux)
345 	struct device *parent;
346 	void *vcf, *aux;
347 {
348 	struct confargs *ca = aux;
349 
350 	if (CPU_ISSUN4) {
351 		/* Only these sun4s have "clock" (others have "oclock") */
352 		if (cpuinfo.cpu_type != CPUTYP_4_300 &&
353 		    cpuinfo.cpu_type != CPUTYP_4_400)
354 			return (0);
355 
356 		if (strcmp(clock_cd.cd_name, ca->ca_ra.ra_name) != 0)
357 			return (0);
358 
359 		/* Make sure there is something there */
360 		if (probeget(ca->ca_ra.ra_vaddr, 1) == -1)
361 			return (0);
362 
363 		return (1);
364 	}
365 
366 	return (strcmp("eeprom", ca->ca_ra.ra_name) == 0);
367 }
368 
369 /* ARGSUSED */
370 void
clockattach(parent,self,aux)371 clockattach(parent, self, aux)
372 	struct device *parent, *self;
373 	void *aux;
374 {
375 	int h;
376 	struct clockreg *cl;
377 	struct idprom *idp;
378 	struct confargs *ca = aux;
379 	struct romaux *ra = &ca->ca_ra;
380 	char *prop = NULL;
381 
382 	if (CPU_ISSUN4)
383 		prop = "mk48t02";
384 
385 	if (CPU_ISSUN4COR4M)
386 		prop = getpropstring(ra->ra_node, "model");
387 
388 #ifdef DIAGNOSTIC
389 	if (prop == NULL)
390 		panic("no prop");
391 #endif
392 	printf(": %s (eeprom)\n", prop);
393 
394 	/*
395 	 * We ignore any existing virtual address as we need to map
396 	 * this read-only and make it read-write only temporarily,
397 	 * whenever we read or write the clock chip.  The clock also
398 	 * contains the ID ``PROM'', and I have already had the pleasure
399 	 * of reloading the cpu type, Ethernet address, etc, by hand from
400 	 * the console FORTH interpreter.  I intend not to enjoy it again.
401 	 */
402 	if (strcmp(prop, "mk48t08") == 0) {
403 		/*
404 		 * the MK48T08 is 8K
405 		 */
406 		cl = (struct clockreg *)mapiodev(ra->ra_reg, 0, 8192);
407 		pmap_changeprot(pmap_kernel(), (vaddr_t)cl, VM_PROT_READ, 1);
408 		pmap_changeprot(pmap_kernel(), (vaddr_t)cl + 4096,
409 				VM_PROT_READ, 1);
410 		cl = (struct clockreg *)((int)cl + CLK_MK48T08_OFF);
411 	} else {
412 		/*
413 		 * the MK48T02 is 2K
414 		 */
415 		cl = (struct clockreg *)mapiodev(ra->ra_reg, 0,
416 						 sizeof *clockreg);
417 		pmap_changeprot(pmap_kernel(), (vaddr_t)cl, VM_PROT_READ, 1);
418 	}
419 	idp = &cl->cl_idprom;
420 
421 #if defined(SUN4)
422 	if (CPU_ISSUN4) {
423 		idp = &idprom;
424 
425 		if (cpuinfo.cpu_type == CPUTYP_4_300 ||
426 		    cpuinfo.cpu_type == CPUTYP_4_400) {
427 			eeprom_va = (char *)cl->cl_nvram;
428 			eeprom_nvram = 1;
429 		}
430 	}
431 #endif
432 
433 	h = idp->id_machine << 24;
434 	h |= idp->id_hostid[0] << 16;
435 	h |= idp->id_hostid[1] << 8;
436 	h |= idp->id_hostid[2];
437 	hostid = h;
438 	clockreg = cl;
439 }
440 
441 /*
442  * The OPENPROM calls the timer the "counter-timer".
443  */
444 int
timermatch(parent,vcf,aux)445 timermatch(parent, vcf, aux)
446 	struct device *parent;
447 	void *vcf, *aux;
448 {
449 	struct confargs *ca = aux;
450 
451 	if (CPU_ISSUN4) {
452 		if (cpuinfo.cpu_type != CPUTYP_4_300 &&
453 		    cpuinfo.cpu_type != CPUTYP_4_400)
454 			return (0);
455 
456 		if (strcmp("timer", ca->ca_ra.ra_name) != 0)
457 			return (0);
458 
459 		/* Make sure there is something there */
460 		if (probeget(ca->ca_ra.ra_vaddr, 4) == -1)
461 			return (0);
462 
463 		return (1);
464 	}
465 
466 	if (CPU_ISSUN4C) {
467 		return (strcmp("counter-timer", ca->ca_ra.ra_name) == 0);
468 	}
469 
470 	if (CPU_ISSUN4M) {
471 		return (strcmp("counter", ca->ca_ra.ra_name) == 0);
472 	}
473 
474 	return (0);
475 }
476 
477 /* ARGSUSED */
478 void
timerattach(parent,self,aux)479 timerattach(parent, self, aux)
480 	struct device *parent, *self;
481 	void *aux;
482 {
483 	struct confargs *ca = aux;
484 	struct romaux *ra = &ca->ca_ra;
485 	volatile int *cnt = NULL, *lim = NULL;
486 		/* XXX: must init to NULL to avoid stupid gcc -Wall warning */
487 
488 	if (CPU_ISSUN4M) {
489 		(void)mapdev(&ra->ra_reg[ra->ra_nreg-1], TIMERREG_VA, 0,
490 			     sizeof(struct timer_4m));
491 		(void)mapdev(&ra->ra_reg[0], COUNTERREG_VA, 0,
492 			     sizeof(struct counter_4m));
493 		timerreg_4m = (struct timer_4m *)TIMERREG_VA;
494 		counterreg_4m = (struct counter_4m *)COUNTERREG_VA;
495 
496 		/* Put processor counter in "timer" mode */
497 		timerreg_4m->t_cfg = 0;
498 
499 		cnt = &counterreg_4m->t_counter;
500 		lim = &counterreg_4m->t_limit;
501 	}
502 
503 	if (CPU_ISSUN4OR4C) {
504 		/*
505 		 * This time, we ignore any existing virtual address because
506 		 * we have a fixed virtual address for the timer, to make
507 		 * microtime() faster (in SUN4/SUN4C kernel only).
508 		 */
509 		(void)mapdev(ra->ra_reg, TIMERREG_VA, 0,
510 			     sizeof(struct timerreg_4));
511 
512 		cnt = &timerreg4->t_c14.t_counter;
513 		lim = &timerreg4->t_c14.t_limit;
514 	}
515 
516 	timerok = 1;
517 
518 	/*
519 	 * Calibrate delay() by tweaking the magic constant
520 	 * until a delay(100) actually reads (at least) 100 us on the clock.
521 	 * Note: sun4m clocks tick with 500ns periods.
522 	 */
523 
524 	for (timerblurb = 1; ; timerblurb++) {
525 		volatile int discard;
526 		int t0, t1;
527 
528 		/* Reset counter register by writing some large limit value */
529 		discard = *lim;
530 		*lim = tmr_ustolim(TMR_MASK-1);
531 
532 		t0 = *cnt;
533 		delay(100);
534 		t1 = *cnt;
535 
536 		if (t1 & TMR_LIMIT)
537 			panic("delay calibration");
538 
539 		t0 = (t0 >> TMR_SHIFT) & TMR_MASK;
540 		t1 = (t1 >> TMR_SHIFT) & TMR_MASK;
541 
542 		if (t1 >= t0 + 100)
543 			break;
544 
545 	}
546 
547 	printf(" delay constant %d\n", timerblurb);
548 
549 	/* should link interrupt handlers here, rather than compiled-in? */
550 }
551 
552 /*
553  * Write en/dis-able clock registers.  We coordinate so that several
554  * writers can run simultaneously.
555  */
556 void
clk_wenable(onoff)557 clk_wenable(onoff)
558 	int onoff;
559 {
560 	int s;
561 	vm_prot_t prot;/* nonzero => change prot */
562 	static int writers;
563 
564 	s = splhigh();
565 	if (onoff)
566 		prot = writers++ == 0 ? VM_PROT_READ|VM_PROT_WRITE : 0;
567 	else
568 		prot = --writers == 0 ? VM_PROT_READ : 0;
569 	splx(s);
570 	if (prot)
571 		pmap_changeprot(pmap_kernel(), (vaddr_t)clockreg & ~(NBPG-1),
572 				prot, 1);
573 }
574 
575 /*
576  * XXX this belongs elsewhere
577  */
578 void
myetheraddr(cp)579 myetheraddr(cp)
580 	u_char *cp;
581 {
582 	struct clockreg *cl = clockreg;
583 	struct idprom *idp = &cl->cl_idprom;
584 
585 #if defined(SUN4)
586 	if (CPU_ISSUN4)
587 		idp = &idprom;
588 #endif
589 
590 	cp[0] = idp->id_ether[0];
591 	cp[1] = idp->id_ether[1];
592 	cp[2] = idp->id_ether[2];
593 	cp[3] = idp->id_ether[3];
594 	cp[4] = idp->id_ether[4];
595 	cp[5] = idp->id_ether[5];
596 }
597 
598 /*
599  * Set up the real-time and statistics clocks.  Leave stathz 0 only if
600  * no alternative timer is available.
601  *
602  * The frequencies of these clocks must be an even number of microseconds.
603  */
604 void
cpu_initclocks()605 cpu_initclocks()
606 {
607 	int statint, minint;
608 
609 #if defined(SUN4)
610 	if (oldclk) {
611 		int dummy;
612 
613 		if (hz != 100) {
614 			printf("oclock0: cannot get %d Hz clock; using 100 Hz\n", hz);
615 		}
616 
617 		profhz = hz = 100;
618 		tick = 1000000 / hz;
619 
620 		i7->clk_intr_reg = INTERSIL_INTER_CSECONDS; /* 1/100 sec */
621 
622 		ienab_bic(IE_L14 | IE_L10);	/* disable all clock intrs */
623 		intersil_disable(i7);		/* disable clock */
624 		dummy = intersil_clear(i7);	/* clear interrupts */
625 		ienab_bis(IE_L10);		/* enable l10 interrupt */
626 		intersil_enable(i7);		/* enable clock */
627 
628 		return;
629 	}
630 #endif /* SUN4 */
631 
632 	if (1000000 % hz) {
633 		printf("clock0: cannot get %d Hz clock; using 100 Hz\n", hz);
634 		hz = 100;
635 		tick = 1000000 / hz;
636 	}
637 	if (stathz == 0)
638 		stathz = hz;
639 	if (1000000 % stathz) {
640 		printf("clock0: cannot get %d Hz statclock; using 100 Hz\n", stathz);
641 		stathz = 100;
642 	}
643 	profhz = stathz;		/* always */
644 
645 	statint = 1000000 / stathz;
646 	minint = statint / 2 + 100;
647 	while (statvar > minint)
648 		statvar >>= 1;
649 
650 	if (CPU_ISSUN4M) {
651 		timerreg_4m->t_limit = tmr_ustolim4m(tick);
652 		counterreg_4m->t_limit = tmr_ustolim4m(statint);
653 	}
654 
655 	if (CPU_ISSUN4OR4C) {
656 		timerreg4->t_c10.t_limit = tmr_ustolim(tick);
657 		timerreg4->t_c14.t_limit = tmr_ustolim(statint);
658 	}
659 
660 	statmin = statint - (statvar >> 1);
661 
662 #if defined(SUN4M)
663 	if (CPU_ISSUN4M)
664 		ienab_bic(SINTR_T);
665 #endif
666 
667 	if (CPU_ISSUN4OR4C)
668 		ienab_bis(IE_L14 | IE_L10);
669 
670 }
671 
672 /*
673  * Dummy setstatclockrate(), since we know profhz==hz.
674  */
675 /* ARGSUSED */
676 void
setstatclockrate(newhz)677 setstatclockrate(newhz)
678 	int newhz;
679 {
680 	/* nothing */
681 }
682 
683 /*
684  * Level 10 (clock) interrupts.  If we are using the FORTH PROM for
685  * console input, we need to check for that here as well, and generate
686  * a software interrupt to read it.
687  */
688 int
clockintr(cap)689 clockintr(cap)
690 	void *cap;
691 {
692 	volatile int discard;
693 	int s;
694 
695 	/*
696 	 * Protect the clearing of the clock interrupt.  If we don't
697 	 * do this, and we're interrupted (by the zs, for example),
698 	 * the clock stops!
699 	 * XXX WHY DOES THIS HAPPEN?
700 	 */
701 	s = splhigh();
702 
703 #if defined(SUN4)
704 	if (oldclk) {
705 		discard = intersil_clear(i7);
706 		ienab_bic(IE_L10);  /* clear interrupt */
707 		ienab_bis(IE_L10);  /* enable interrupt */
708 		goto forward;
709 	}
710 #endif
711 #if defined(SUN4M)
712 	/* read the limit register to clear the interrupt */
713 	if (CPU_ISSUN4M) {
714 		discard = timerreg_4m->t_limit;
715 	}
716 #endif
717 #if defined(SUN4) || defined(SUN4C)
718 	if (CPU_ISSUN4OR4C) {
719 		discard = timerreg4->t_c10.t_limit;
720 	}
721 #endif
722 #if defined(SUN4)
723 forward:
724 #endif
725 	splx(s);
726 
727 	hardclock((struct clockframe *)cap);
728 
729 	return (1);
730 }
731 
732 /*
733  * Level 14 (stat clock) interrupt handler.
734  */
735 int
statintr(cap)736 statintr(cap)
737 	void *cap;
738 {
739 	volatile int discard;
740 	u_long newint, r, var;
741 
742 #if defined(SUN4)
743 	if (oldclk) {
744 		panic("oldclk statintr");
745 		return (1);
746 	}
747 #endif
748 
749 	/* read the limit register to clear the interrupt */
750 	if (CPU_ISSUN4M) {
751 		discard = counterreg_4m->t_limit;
752 		if (timerok == 0) {
753 			/* Stop the clock */
754 			counterreg_4m->t_limit = 0;
755 			counterreg_4m->t_ss = 0;
756 			timerreg_4m->t_cfg = TMR_CFG_USER;
757 			return 1;
758 		}
759 	}
760 
761 	if (CPU_ISSUN4OR4C) {
762 		discard = timerreg4->t_c14.t_limit;
763 	}
764 	statclock((struct clockframe *)cap);
765 
766 	/*
767 	 * Compute new randomized interval.  The intervals are uniformly
768 	 * distributed on [statint - statvar / 2, statint + statvar / 2],
769 	 * and therefore have mean statint, giving a stathz frequency clock.
770 	 */
771 	var = statvar;
772 	do {
773 		r = arc4random() & (var - 1);
774 	} while (r == 0);
775 	newint = statmin + r;
776 
777 	if (CPU_ISSUN4M) {
778 		counterreg_4m->t_limit = tmr_ustolim4m(newint);
779 	}
780 
781 	if (CPU_ISSUN4OR4C) {
782 		timerreg4->t_c14.t_limit = tmr_ustolim(newint);
783 	}
784 	return (1);
785 }
786 
787 /*
788  * BCD to decimal and decimal to BCD.
789  */
790 #define	FROMBCD(x)	(((x) >> 4) * 10 + ((x) & 0xf))
791 #define	TOBCD(x)	(((x) / 10 * 16) + ((x) % 10))
792 
793 #define	SECDAY		(24 * 60 * 60)
794 #define	SECYR		(SECDAY * 365)
795 /*
796  * should use something like
797  * #define LEAPYEAR(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
798  * but it's unlikely that we'll still be around in 2100.
799  */
800 #define	LEAPYEAR(y)	(((y) & 3) == 0)
801 
802 /*
803  * This code is defunct after 2068.
804  * Will Unix still be here then??
805  */
806 const short dayyr[12] =
807     { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
808 
809 int
chiptotime(sec,min,hour,day,mon,year)810 chiptotime(sec, min, hour, day, mon, year)
811 	int sec, min, hour, day, mon, year;
812 {
813 	int days, yr;
814 
815 	sec = FROMBCD(sec);
816 	min = FROMBCD(min);
817 	hour = FROMBCD(hour);
818 	day = FROMBCD(day);
819 	mon = FROMBCD(mon);
820 	year = FROMBCD(year) + YEAR0;
821 
822 	/* simple sanity checks */
823 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31)
824 		return (0);
825 	days = 0;
826 	for (yr = 70; yr < year; yr++)
827 		days += LEAPYEAR(yr) ? 366 : 365;
828 	days += dayyr[mon - 1] + day - 1;
829 	if (LEAPYEAR(yr) && mon > 2)
830 		days++;
831 	/* now have days since Jan 1, 1970; the rest is easy... */
832 	return (days * SECDAY + hour * 3600 + min * 60 + sec);
833 }
834 
835 struct chiptime {
836 	int	sec;
837 	int	min;
838 	int	hour;
839 	int	wday;
840 	int	day;
841 	int	mon;
842 	int	year;
843 };
844 
845 void
timetochip(c)846 timetochip(c)
847 	struct chiptime *c;
848 {
849 	int t, t2, t3, now = time.tv_sec;
850 
851 	/* compute the year */
852 	t2 = now / SECDAY;
853 	t3 = (t2 + 2) % 7;	/* day of week */
854 	c->wday = TOBCD(t3 + 1);
855 
856 	t = 69;
857 	while (t2 >= 0) {	/* whittle off years */
858 		t3 = t2;
859 		t++;
860 		t2 -= LEAPYEAR(t) ? 366 : 365;
861 	}
862 	c->year = t;
863 
864 	/* t3 = month + day; separate */
865 	t = LEAPYEAR(t);
866 	for (t2 = 1; t2 < 12; t2++)
867 		if (t3 < dayyr[t2] + (t && t2 > 1))
868 			break;
869 
870 	/* t2 is month */
871 	c->mon = t2;
872 	c->day = t3 - dayyr[t2 - 1] + 1;
873 	if (t && t2 > 2)
874 		c->day--;
875 
876 	/* the rest is easy */
877 	t = now % SECDAY;
878 	c->hour = t / 3600;
879 	t %= 3600;
880 	c->min = t / 60;
881 	c->sec = t % 60;
882 
883 	c->sec = TOBCD(c->sec);
884 	c->min = TOBCD(c->min);
885 	c->hour = TOBCD(c->hour);
886 	c->day = TOBCD(c->day);
887 	c->mon = TOBCD(c->mon);
888 	c->year = TOBCD(c->year - YEAR0);
889 }
890 
891 /*
892  * Set up the system's time, given a `reasonable' time value.
893  */
894 void
inittodr(base)895 inittodr(base)
896 	time_t base;
897 {
898 	struct clockreg *cl = clockreg;
899 	int sec, min, hour, day, mon, year;
900 	int badbase = 0, waszero = base == 0;
901 	char *bad = NULL;
902 	time_t x[2];
903 
904 	if (base < 5 * SECYR) {
905 		/*
906 		 * If base is 0, assume filesystem time is just unknown
907 		 * in stead of preposterous. Don't bark.
908 		 */
909 		if (base != 0)
910 			printf("WARNING: preposterous time in file system\n");
911 		/* not going to use it anyway, if the chip is readable */
912 		base = 21*SECYR + 186*SECDAY + SECDAY/2;
913 		badbase = 1;
914 	}
915 #if defined(SUN4)
916 	if (oldclk) {
917 		time.tv_sec = oclk_get_secs();
918 		goto forward;
919 	}
920 #endif
921 	clk_wenable(1);
922 	cl->cl_csr |= CLK_READ;		/* enable read (stop time) */
923 	sec = cl->cl_sec;
924 	min = cl->cl_min;
925 	hour = cl->cl_hour;
926 	day = cl->cl_mday;
927 	mon = cl->cl_month;
928 	year = cl->cl_year;
929 	cl->cl_csr &= ~CLK_READ;	/* time wears on */
930 	clk_wenable(0);
931 	time.tv_sec = chiptotime(sec, min, hour, day, mon, year);
932 
933 #if defined(SUN4)
934 forward:
935 #endif
936 	x[0] = time.tv_sec;
937 	x[1] = base;
938 	rnd_lopool_add(x, sizeof(x));
939 
940 	if (time.tv_sec == 0) {
941 		/*
942 		 * Believe the time in the file system for lack of
943 		 * anything better, resetting the clock.
944 		 */
945 		bad = "WARNING: bad date in battery clock";
946 		time.tv_sec = base;
947 		if (!badbase)
948 			resettodr();
949 	} else {
950 		int deltat = time.tv_sec - base;
951 
952 		if (deltat < 0)
953 			deltat = -deltat;
954 		if (waszero || deltat < 2 * SECDAY)
955 			return;
956 
957 #ifndef SMALL_KERNEL
958 		printf("WARNING: clock %s %d days",
959 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
960 		bad = "";
961 #endif
962 	}
963 	if (bad) {
964 		printf("%s", bad);
965 		printf(" -- CHECK AND RESET THE DATE!\n");
966 	}
967 }
968 
969 /*
970  * Reset the clock based on the current time.
971  * Used when the current clock is preposterous, when the time is changed,
972  * and when rebooting.  Do nothing if the time is not yet known, e.g.,
973  * when crashing during autoconfig.
974  */
975 void
resettodr()976 resettodr()
977 {
978 	struct clockreg *cl;
979 	struct chiptime c;
980 
981 #if defined(SUN4)
982 	if (oldclk) {
983 		if (!time.tv_sec || i7 == NULL)
984 			return;
985 		oclk_set_secs(time.tv_sec);
986 		return;
987 	}
988 #endif
989 
990 	if (!time.tv_sec || (cl = clockreg) == NULL)
991 		return;
992 	timetochip(&c);
993 	clk_wenable(1);
994 	cl->cl_csr |= CLK_WRITE;	/* enable write */
995 	cl->cl_sec = c.sec;
996 	cl->cl_min = c.min;
997 	cl->cl_hour = c.hour;
998 	cl->cl_wday = c.wday;
999 	cl->cl_mday = c.day;
1000 	cl->cl_month = c.mon;
1001 	cl->cl_year = c.year;
1002 	cl->cl_csr &= ~CLK_WRITE;	/* load them up */
1003 	clk_wenable(0);
1004 }
1005 
1006 #if defined(SUN4)
1007 /*
1008  * Now routines to get and set clock as POSIX time.
1009  */
1010 long
oclk_get_secs()1011 oclk_get_secs()
1012 {
1013         struct intersil_dt dt;
1014         long gmt;
1015 
1016         oclk_get_dt(&dt);
1017         dt_to_gmt(&dt, &gmt);
1018         return (gmt);
1019 }
1020 
1021 void
oclk_set_secs(secs)1022 oclk_set_secs(secs)
1023 	long secs;
1024 {
1025         struct intersil_dt dt;
1026         long gmt;
1027 
1028         gmt = secs;
1029         gmt_to_dt(&gmt, &dt);
1030         oclk_set_dt(&dt);
1031 }
1032 
1033 /*
1034  * Routine to copy state into and out of the clock.
1035  * The clock registers have to be read or written
1036  * in sequential order (or so it appears). -gwr
1037  */
1038 void
oclk_get_dt(dt)1039 oclk_get_dt(dt)
1040 	struct intersil_dt *dt;
1041 {
1042         int s;
1043         register volatile char *src, *dst;
1044 
1045         src = (char *) &i7->counters;
1046 
1047         s = splhigh();
1048         i7->clk_cmd_reg =
1049                 intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
1050 
1051         dst = (char *) dt;
1052         dt++;   /* end marker */
1053         do {
1054                 *dst++ = *src++;
1055         } while (dst < (char *)dt);
1056 
1057         i7->clk_cmd_reg =
1058                 intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
1059         splx(s);
1060 }
1061 
1062 void
oclk_set_dt(dt)1063 oclk_set_dt(dt)
1064 	struct intersil_dt *dt;
1065 {
1066         int s;
1067         register volatile char *src, *dst;
1068 
1069         dst = (char *) &i7->counters;
1070 
1071         s = splhigh();
1072         i7->clk_cmd_reg =
1073                 intersil_command(INTERSIL_CMD_STOP, INTERSIL_CMD_IENABLE);
1074 
1075         src = (char *) dt;
1076         dt++;   /* end marker */
1077         do {
1078                 *dst++ = *src++;
1079         } while (src < (char *)dt);
1080 
1081         i7->clk_cmd_reg =
1082                 intersil_command(INTERSIL_CMD_RUN, INTERSIL_CMD_IENABLE);
1083         splx(s);
1084 }
1085 
1086 
1087 /*
1088  * Machine dependent base year:
1089  * Note: must be < 1970
1090  */
1091 #define CLOCK_BASE_YEAR 1968
1092 
1093 /* Traditional UNIX base year */
1094 #define POSIX_BASE_YEAR 1970
1095 #define FEBRUARY        2
1096 
1097 #define leapyear(year)          ((year) % 4 == 0)
1098 #define days_in_year(a)         (leapyear(a) ? 366 : 365)
1099 #define days_in_month(a)        (month_days[(a) - 1])
1100 
1101 static int month_days[12] = {
1102         31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
1103 };
1104 
1105 void
gmt_to_dt(tp,dt)1106 gmt_to_dt(tp, dt)
1107 	long *tp;
1108 	struct intersil_dt *dt;
1109 {
1110         int i;
1111         long days, secs;
1112 
1113         days = *tp / SECDAY;
1114         secs = *tp % SECDAY;
1115 
1116         /* Hours, minutes, seconds are easy */
1117         dt->dt_hour = secs / 3600;
1118         secs = secs % 3600;
1119         dt->dt_min  = secs / 60;
1120         secs = secs % 60;
1121         dt->dt_sec  = secs;
1122 
1123         /* Day of week (Note: 1/1/1970 was a Thursday) */
1124         dt->dt_dow = (days + 4) % 7;
1125 
1126         /* Number of years in days */
1127         i = POSIX_BASE_YEAR;
1128         while (days >= days_in_year(i)) {
1129                 days -= days_in_year(i);
1130                 i++;
1131         }
1132         dt->dt_year = i - CLOCK_BASE_YEAR;
1133 
1134         /* Number of months in days left */
1135         if (leapyear(i))
1136                 days_in_month(FEBRUARY) = 29;
1137         for (i = 1; days >= days_in_month(i); i++)
1138                 days -= days_in_month(i);
1139         days_in_month(FEBRUARY) = 28;
1140         dt->dt_month = i;
1141 
1142         /* Days are what is left over (+1) from all that. */
1143         dt->dt_day = days + 1;
1144 }
1145 
1146 
1147 void
dt_to_gmt(dt,tp)1148 dt_to_gmt(dt, tp)
1149 	struct intersil_dt *dt;
1150 	long *tp;
1151 {
1152         int i;
1153         long tmp;
1154         int year;
1155 
1156         /*
1157          * Hours are different for some reason. Makes no sense really.
1158          */
1159 
1160         tmp = 0;
1161 
1162         if (dt->dt_hour >= 24) goto out;
1163         if (dt->dt_day  >  31) goto out;
1164         if (dt->dt_month > 12) goto out;
1165 
1166         year = dt->dt_year + CLOCK_BASE_YEAR;
1167 
1168 
1169         /*
1170          * Compute days since start of time
1171          * First from years, then from months.
1172          */
1173         for (i = POSIX_BASE_YEAR; i < year; i++)
1174                 tmp += days_in_year(i);
1175         if (leapyear(year) && dt->dt_month > FEBRUARY)
1176                 tmp++;
1177 
1178         /* Months */
1179         for (i = 1; i < dt->dt_month; i++)
1180                 tmp += days_in_month(i);
1181         tmp += (dt->dt_day - 1);
1182 
1183         /* Now do hours */
1184         tmp = tmp * 24 + dt->dt_hour;
1185 
1186         /* Now do minutes */
1187         tmp = tmp * 60 + dt->dt_min;
1188 
1189         /* Now do seconds */
1190         tmp = tmp * 60 + dt->dt_sec;
1191 
1192 out:
1193         *tp = tmp;
1194 }
1195 #endif /* SUN4 */
1196 
1197 #if defined(SUN4)
1198 /*
1199  * Return the best possible estimate of the time in the timeval
1200  * to which tvp points.  We do this by returning the current time
1201  * plus the amount of time since the last clock interrupt.
1202  *
1203  * Check that this time is no less than any previously-reported time,
1204  * which could happen around the time of a clock adjustment.  Just for
1205  * fun, we guarantee that the time will be greater than the value
1206  * obtained by a previous call.
1207  */
1208 void
microtime(tvp)1209 microtime(tvp)
1210 	struct timeval *tvp;
1211 {
1212 	int s;
1213 	static struct timeval lasttime;
1214 	static struct timeval oneusec = {0, 1};
1215 
1216 	if (!oldclk) {
1217 		lo_microtime(tvp);
1218 		return;
1219 	}
1220 
1221 	s = splhigh();
1222 	*tvp = time;
1223 	splx(s);
1224 
1225 	if (timercmp(tvp, &lasttime, <=))
1226 		timeradd(&lasttime, &oneusec, tvp);
1227 
1228 	lasttime = *tvp;
1229 }
1230 #endif /* SUN4 */
1231 
1232 /*
1233  * XXX: these may actually belong somewhere else, but since the
1234  * EEPROM is so closely tied to the clock on some models, perhaps
1235  * it needs to stay here...
1236  */
1237 int
eeprom_uio(uio)1238 eeprom_uio(uio)
1239 	struct uio *uio;
1240 {
1241 #if defined(SUN4)
1242 	int error;
1243 	int off;	/* NOT off_t */
1244 	u_int cnt, bcnt;
1245 	caddr_t buf = NULL;
1246 
1247 	if (!CPU_ISSUN4)
1248 		return (ENODEV);
1249 
1250 	off = uio->uio_offset;
1251 	if (off > EEPROM_SIZE)
1252 		return (EFAULT);
1253 
1254 	cnt = uio->uio_resid;
1255 	if (cnt > (EEPROM_SIZE - off))
1256 		cnt = (EEPROM_SIZE - off);
1257 
1258 	if ((error = eeprom_take()) != 0)
1259 		return (error);
1260 
1261 	if (eeprom_va == NULL) {
1262 		error = ENXIO;
1263 		goto out;
1264 	}
1265 
1266 	/*
1267 	 * The EEPROM can only be accessed one byte at a time, yet
1268 	 * uiomove() will attempt long-word access.  To circumvent
1269 	 * this, we byte-by-byte copy the eeprom contents into a
1270 	 * temporary buffer.
1271 	 */
1272 	buf = malloc(EEPROM_SIZE, M_DEVBUF, M_WAITOK);
1273 
1274 	if (uio->uio_rw == UIO_READ)
1275 		for (bcnt = 0; bcnt < EEPROM_SIZE; ++bcnt)
1276 			*(char *)(buf + bcnt) = *(char *)(eeprom_va + bcnt);
1277 
1278 	if ((error = uiomove(buf + off, (int)cnt, uio)) != 0)
1279 		goto out;
1280 
1281 	if (uio->uio_rw != UIO_READ)
1282 		error = eeprom_update(buf, off, cnt);
1283 
1284  out:
1285 	if (buf)
1286 		free(buf, M_DEVBUF);
1287 	eeprom_give();
1288 	return (error);
1289 #else /* ! SUN4 */
1290 	return (ENODEV);
1291 #endif /* SUN4 */
1292 }
1293 
1294 #if defined(SUN4)
1295 /*
1296  * Update the EEPROM from the passed buf.
1297  */
1298 int
eeprom_update(buf,off,cnt)1299 eeprom_update(buf, off, cnt)
1300 	char *buf;
1301 	int off, cnt;
1302 {
1303 	int error = 0;
1304 	volatile char *ep;
1305 	char *bp;
1306 
1307 	if (eeprom_va == NULL)
1308 		return (ENXIO);
1309 
1310 	ep = eeprom_va + off;
1311 	bp = buf + off;
1312 
1313 	if (eeprom_nvram)
1314 		clk_wenable(1);
1315 
1316 	while (cnt > 0) {
1317 		/*
1318 		 * DO NOT WRITE IT UNLESS WE HAVE TO because the
1319 		 * EEPROM has a limited number of write cycles.
1320 		 * After some number of writes it just fails!
1321 		 */
1322 		if (*ep != *bp) {
1323 			*ep = *bp;
1324 			/*
1325 			 * We have written the EEPROM, so now we must
1326 			 * sleep for at least 10 milliseconds while
1327 			 * holding the lock to prevent all access to
1328 			 * the EEPROM while it recovers.
1329 			 */
1330 			(void)tsleep(eeprom_va, PZERO - 1, "eeprom", hz/50);
1331 		}
1332 		/* Make sure the write worked. */
1333 		if (*ep != *bp) {
1334 			error = EIO;
1335 			goto out;
1336 		}
1337 		++ep;
1338 		++bp;
1339 		--cnt;
1340 	}
1341  out:
1342 	if (eeprom_nvram)
1343 		clk_wenable(0);
1344 
1345 	return (error);
1346 }
1347 
1348 /* Take a lock on the eeprom. */
1349 int
eeprom_take()1350 eeprom_take()
1351 {
1352 	int error = 0;
1353 
1354 	while (eeprom_busy) {
1355 		eeprom_wanted = 1;
1356 		error = tsleep(&eeprom_busy, PZERO | PCATCH, "eeprom", 0);
1357 		eeprom_wanted = 0;
1358 		if (error)	/* interrupted */
1359 			goto out;
1360 	}
1361 	eeprom_busy = 1;
1362  out:
1363 	return (error);
1364 }
1365 
1366 /* Give a lock on the eeprom away. */
1367 void
eeprom_give()1368 eeprom_give()
1369 {
1370 
1371 	eeprom_busy = 0;
1372 	if (eeprom_wanted) {
1373 		eeprom_wanted = 0;
1374 		wakeup(&eeprom_busy);
1375 	}
1376 }
1377 #endif /* SUN4 */
1378