xref: /openbsd/sys/arch/i386/isa/clock.c (revision db3296cf)
1 /*	$OpenBSD: clock.c,v 1.30 2003/06/02 23:27:47 millert Exp $	*/
2 /*	$NetBSD: clock.c,v 1.39 1996/05/12 23:11:54 mycroft Exp $	*/
3 
4 /*-
5  * Copyright (c) 1993, 1994 Charles Hannum.
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * William Jolitz and Don Ahn.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
37  */
38 /*
39  * Mach Operating System
40  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
41  * All Rights Reserved.
42  *
43  * Permission to use, copy, modify and distribute this software and its
44  * documentation is hereby granted, provided that both the copyright
45  * notice and this permission notice appear in all copies of the
46  * software, derivative works or modified versions, and any portions
47  * thereof, and that both notices appear in supporting documentation.
48  *
49  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
50  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
51  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
52  *
53  * Carnegie Mellon requests users of this software to return to
54  *
55  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
56  *  School of Computer Science
57  *  Carnegie Mellon University
58  *  Pittsburgh PA 15213-3890
59  *
60  * any improvements or extensions that they make and grant Carnegie Mellon
61  * the rights to redistribute these changes.
62  */
63 /*
64   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
65 
66 		All Rights Reserved
67 
68 Permission to use, copy, modify, and distribute this software and
69 its documentation for any purpose and without fee is hereby
70 granted, provided that the above copyright notice appears in all
71 copies and that both the copyright notice and this permission notice
72 appear in supporting documentation, and that the name of Intel
73 not be used in advertising or publicity pertaining to distribution
74 of the software without specific, written prior permission.
75 
76 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
77 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
78 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
79 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
80 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
81 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
82 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
83 */
84 
85 /*
86  * Primitive clock interrupt routines.
87  */
88 #include <sys/types.h>
89 #include <sys/param.h>
90 #include <sys/systm.h>
91 #include <sys/time.h>
92 #include <sys/kernel.h>
93 #include <sys/device.h>
94 #include <sys/timeout.h>
95 
96 #include <machine/cpu.h>
97 #include <machine/intr.h>
98 #include <machine/pio.h>
99 #include <machine/cpufunc.h>
100 
101 #include <dev/clock_subr.h>
102 #include <dev/isa/isareg.h>
103 #include <dev/isa/isavar.h>
104 #include <dev/ic/mc146818reg.h>
105 #include <i386/isa/nvram.h>
106 #include <i386/isa/timerreg.h>
107 
108 #include "pcppi.h"
109 #if (NPCPPI > 0)
110 #include <dev/isa/pcppivar.h>
111 
112 #define __BROKEN_INDIRECT_CONFIG /* XXX */
113 #ifdef __BROKEN_INDIRECT_CONFIG
114 int sysbeepmatch(struct device *, void *, void *);
115 #else
116 int sysbeepmatch(struct device *, struct cfdata *, void *);
117 #endif
118 void sysbeepattach(struct device *, struct device *, void *);
119 
120 struct cfattach sysbeep_ca = {
121 	sizeof(struct device), sysbeepmatch, sysbeepattach
122 };
123 
124 struct cfdriver sysbeep_cd = {
125 	NULL, "sysbeep", DV_DULL
126 };
127 
128 static int ppi_attached;
129 static pcppi_tag_t ppicookie;
130 #endif /* PCPPI */
131 
132 void	spinwait(int);
133 void	findcpuspeed(void);
134 int	clockintr(void *);
135 int	gettick(void);
136 void	sysbeep(int, int);
137 int	rtcget(mc_todregs *);
138 void	rtcput(mc_todregs *);
139 int 	hexdectodec(int);
140 int	dectohexdec(int);
141 int	rtcintr(void *);
142 void	rtcdrain(void *);
143 
144 u_int mc146818_read(void *, u_int);
145 void mc146818_write(void *, u_int, u_int);
146 
147 #if defined(I486_CPU) || defined(I586_CPU) || defined(I686_CPU)
148 int pentium_mhz, clock_broken_latch;
149 #endif
150 
151 #define	SECMIN	((unsigned)60)			/* seconds per minute */
152 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
153 
154 u_int
155 mc146818_read(sc, reg)
156 	void *sc;					/* XXX use it? */
157 	u_int reg;
158 {
159 	int s;
160 	u_char v;
161 
162 	s = splhigh();
163 	outb(IO_RTC, reg);
164 	DELAY(1);
165 	v = inb(IO_RTC+1);
166 	DELAY(1);
167 	splx(s);
168 	return (v);
169 }
170 
171 void
172 mc146818_write(sc, reg, datum)
173 	void *sc;					/* XXX use it? */
174 	u_int reg, datum;
175 {
176 	int s;
177 
178 	s = splhigh();
179 	outb(IO_RTC, reg);
180 	DELAY(1);
181 	outb(IO_RTC+1, datum);
182 	DELAY(1);
183 	splx(s);
184 }
185 
186 void
187 startrtclock()
188 {
189 	int s;
190 
191 	findcpuspeed();		/* use the clock (while it's free)
192 					to find the cpu speed */
193 	initrtclock();
194 
195 	/* Check diagnostic status */
196 	if ((s = mc146818_read(NULL, NVRAM_DIAG)) != 0)	/* XXX softc */
197 		printf("RTC BIOS diagnostic error %b\n", (unsigned int) s,
198 		    NVRAM_DIAG_BITS);
199 }
200 
201 void
202 rtcdrain(void *v)
203 {
204 	struct timeout *to = (struct timeout *)v;
205 
206 	if (to != NULL)
207 		timeout_del(to);
208 
209 	/*
210 	 * Drain any un-acknowledged RTC interrupts.
211 	 * See comment in cpu_initclocks().
212 	 */
213   	while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF)
214 		; /* Nothing. */
215 }
216 
217 void
218 initrtclock()
219 {
220 	/* initialize 8253 clock */
221 	outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
222 
223 	/* Correct rounding will buy us a better precision in timekeeping */
224 	outb(IO_TIMER1, TIMER_DIV(hz) % 256);
225 	outb(IO_TIMER1, TIMER_DIV(hz) / 256);
226 }
227 
228 int
229 clockintr(arg)
230 	void *arg;
231 {
232 	struct clockframe *frame = arg;		/* not strictly necessary */
233 
234 	hardclock(frame);
235 	return (1);
236 }
237 
238 int
239 rtcintr(arg)
240 	void *arg;
241 {
242 	struct clockframe *frame = arg;		/* not strictly necessary */
243 	u_int stat = 0;
244 
245 	/*
246 	 * If rtcintr is 'late', next intr may happen immediately.
247 	 * Get them all. (Also, see comment in cpu_initclocks().)
248 	 */
249 	while (mc146818_read(NULL, MC_REGC) & MC_REGC_PF) {
250 		statclock(frame);
251 		stat = 1;
252 	}
253 	return (stat);
254 }
255 
256 int
257 gettick()
258 {
259 
260 #if defined(I586_CPU) || defined(I686_CPU)
261 	if (clock_broken_latch) {
262 		int v1, v2, v3;
263 		int w1, w2, w3;
264 
265 		disable_intr();
266 
267 		v1 = inb(TIMER_CNTR0);
268 		v1 |= inb(TIMER_CNTR0) << 8;
269 		v2 = inb(TIMER_CNTR0);
270 		v2 |= inb(TIMER_CNTR0) << 8;
271 		v3 = inb(TIMER_CNTR0);
272 		v3 |= inb(TIMER_CNTR0) << 8;
273 
274 		enable_intr();
275 
276 		if (v1 >= v2 && v2 >= v3 && v1 - v3 < 0x200)
277 			return (v2);
278 
279 #define _swap_val(a, b) do { \
280 	int c = a; \
281 	a = b; \
282 	b = c; \
283 } while (0)
284 
285 		/* sort v1 v2 v3 */
286 		if (v1 < v2)
287 			_swap_val(v1, v2);
288 		if (v2 < v3)
289 			_swap_val(v2, v3);
290 		if (v1 < v2)
291 			_swap_val(v1, v2);
292 
293 		/* compute the middle value */
294 		if (v1 - v3 < 0x200)
295 			return (v2);
296 		w1 = v2 - v3;
297 		w2 = v3 - v1 + TIMER_DIV(hz);
298 		w3 = v1 - v2;
299 		if (w1 >= w2) {
300 			if (w1 >= w3)
301 				return (v1);
302 		} else {
303 			if (w2 >= w3)
304 				return (v2);
305 		}
306 		return (v3);
307 	} else
308 #endif
309 	{
310 		u_char lo, hi;
311 
312 		disable_intr();
313 		/* Select counter 0 and latch it. */
314 		outb(TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
315 		lo = inb(TIMER_CNTR0);
316 		hi = inb(TIMER_CNTR0);
317 
318 		enable_intr();
319 		return ((hi << 8) | lo);
320 	}
321 }
322 
323 /*
324  * Wait "n" microseconds.
325  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
326  * Note: timer had better have been programmed before this is first used!
327  * (Note that we use `rate generator' mode, which counts at 1:1; `square
328  * wave' mode counts at 2:1).
329  */
330 void
331 delay(n)
332 	int n;
333 {
334 	int limit, tick, otick;
335 
336 	/*
337 	 * Read the counter first, so that the rest of the setup overhead is
338 	 * counted.
339 	 */
340 	otick = gettick();
341 
342 #ifdef __GNUC__
343 	/*
344 	 * Calculate ((n * TIMER_FREQ) / 1e6) using explicit assembler code so
345 	 * we can take advantage of the intermediate 64-bit quantity to prevent
346 	 * loss of significance.
347 	 */
348 	n -= 5;
349 	if (n < 0)
350 		return;
351 	__asm __volatile("mul %2\n\tdiv %3"
352 			 : "=a" (n)
353 			 : "0" (n), "r" (TIMER_FREQ), "r" (1000000)
354 			 : "%edx", "cc");
355 #else
356 	/*
357 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
358 	 * without any avoidable overflows.
359 	 */
360 	n -= 20;
361 	{
362 		int sec = n / 1000000,
363 		    usec = n % 1000000;
364 		n = sec * TIMER_FREQ +
365 		    usec * (TIMER_FREQ / 1000000) +
366 		    usec * ((TIMER_FREQ % 1000000) / 1000) / 1000 +
367 		    usec * (TIMER_FREQ % 1000) / 1000000;
368 	}
369 #endif
370 
371 	limit = TIMER_FREQ / hz;
372 
373 	while (n > 0) {
374 		tick = gettick();
375 		if (tick > otick)
376 			n -= limit - (tick - otick);
377 		else
378 			n -= otick - tick;
379 		otick = tick;
380 	}
381 }
382 
383 #if (NPCPPI > 0)
384 int
385 sysbeepmatch(parent, match, aux)
386 	struct device *parent;
387 #ifdef __BROKEN_INDIRECT_CONFIG
388 	void *match;
389 #else
390 	struct cfdata *match;
391 #endif
392 	void *aux;
393 {
394 	return (!ppi_attached);
395 }
396 
397 void
398 sysbeepattach(parent, self, aux)
399 	struct device *parent, *self;
400 	void *aux;
401 {
402 	printf("\n");
403 
404 	ppicookie = ((struct pcppi_attach_args *)aux)->pa_cookie;
405 	ppi_attached = 1;
406 }
407 #endif
408 
409 void
410 sysbeep(pitch, period)
411 	int pitch, period;
412 {
413 #if (NPCPPI > 0)
414 	if (ppi_attached)
415 		pcppi_bell(ppicookie, pitch, period, 0);
416 #endif
417 }
418 
419 unsigned int delaycount;	/* calibrated loop variable (1 millisecond) */
420 
421 #define FIRST_GUESS   0x2000
422 
423 void
424 findcpuspeed()
425 {
426 	int i;
427 	int remainder;
428 
429 	/* Put counter in count down mode */
430 	outb(TIMER_MODE, TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
431 	outb(TIMER_CNTR0, 0xff);
432 	outb(TIMER_CNTR0, 0xff);
433 	for (i = FIRST_GUESS; i; i--)
434 		;
435 	/* Read the value left in the counter */
436 	remainder = gettick();
437 	/*
438 	 * Formula for delaycount is:
439 	 *  (loopcount * timer clock speed) / (counter ticks * 1000)
440 	 */
441 	delaycount = (FIRST_GUESS * TIMER_DIV(1000)) / (0xffff-remainder);
442 }
443 
444 #if defined(I586_CPU) || defined(I686_CPU)
445 void
446 calibrate_cyclecounter()
447 {
448 	unsigned long long count, last_count;
449 
450 	__asm __volatile("rdtsc" : "=A" (last_count));
451 	delay(1000000);
452 	__asm __volatile("rdtsc" : "=A" (count));
453 	pentium_mhz = ((count - last_count) + 500000) / 1000000;
454 }
455 #endif
456 
457 void
458 cpu_initclocks()
459 {
460 	static struct timeout rtcdrain_timeout;
461 	stathz = 128;
462 	profhz = 1024;
463 
464 	/*
465 	 * XXX If you're doing strange things with multiple clocks, you might
466 	 * want to keep track of clock handlers.
467 	 */
468 	(void)isa_intr_establish(NULL, 0, IST_PULSE, IPL_CLOCK, clockintr,
469 	    0, "clock");
470 	(void)isa_intr_establish(NULL, 8, IST_PULSE, IPL_CLOCK, rtcintr,
471 	    0, "rtc");
472 
473 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
474 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR | MC_REGB_PIE);
475 
476 	/*
477 	 * On a number of i386 systems, the rtc will fail to start when booting
478 	 * the system. This is due to us missing to acknowledge an interrupt
479 	 * during early stages of the boot process. If we do not acknowledge
480 	 * the interrupt, the rtc clock will not generate further interrupts.
481 	 * To solve this, once interrupts are enabled, use a timeout (once)
482 	 * to drain any un-acknowledged rtc interrupt(s).
483 	 */
484 
485 	timeout_set(&rtcdrain_timeout, rtcdrain, (void *)&rtcdrain_timeout);
486 	timeout_add(&rtcdrain_timeout, 1);
487 }
488 
489 int
490 rtcget(regs)
491 	mc_todregs *regs;
492 {
493 	if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
494 		return (-1);
495 	MC146818_GETTOD(NULL, regs);			/* XXX softc */
496 	return (0);
497 }
498 
499 void
500 rtcput(regs)
501 	mc_todregs *regs;
502 {
503 	MC146818_PUTTOD(NULL, regs);			/* XXX softc */
504 }
505 
506 int
507 hexdectodec(n)
508 	int n;
509 {
510 
511 	return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
512 }
513 
514 int
515 dectohexdec(n)
516 	int n;
517 {
518 
519 	return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
520 }
521 
522 static int timeset;
523 
524 /*
525  * check whether the CMOS layout is "standard"-like (ie, not PS/2-like),
526  * to be called at splclock()
527  */
528 int cmoscheck(void);
529 int
530 cmoscheck()
531 {
532 	int i;
533 	unsigned short cksum = 0;
534 
535 	for (i = 0x10; i <= 0x2d; i++)
536 		cksum += mc146818_read(NULL, i); /* XXX softc */
537 
538 	return (cksum == (mc146818_read(NULL, 0x2e) << 8)
539 			  + mc146818_read(NULL, 0x2f));
540 }
541 
542 /*
543  * patchable to control century byte handling:
544  * 1: always update
545  * -1: never touch
546  * 0: try to figure out itself
547  */
548 int rtc_update_century = 0;
549 
550 /*
551  * Expand a two-digit year as read from the clock chip
552  * into full width.
553  * Being here, deal with the CMOS century byte.
554  */
555 int clock_expandyear(int);
556 int
557 clock_expandyear(clockyear)
558 	int clockyear;
559 {
560 	int s, clockcentury, cmoscentury;
561 
562 	clockcentury = (clockyear < 70) ? 20 : 19;
563 	clockyear += 100 * clockcentury;
564 
565 	if (rtc_update_century < 0)
566 		return (clockyear);
567 
568 	s = splclock();
569 	if (cmoscheck())
570 		cmoscentury = mc146818_read(NULL, NVRAM_CENTURY);
571 	else
572 		cmoscentury = 0;
573 	splx(s);
574 	if (!cmoscentury) {
575 #ifdef DIAGNOSTIC
576 		printf("clock: unknown CMOS layout\n");
577 #endif
578 		return (clockyear);
579 	}
580 	cmoscentury = hexdectodec(cmoscentury);
581 
582 	if (cmoscentury != clockcentury) {
583 		/* XXX note: saying "century is 20" might confuse the naive. */
584 		printf("WARNING: NVRAM century is %d but RTC year is %d\n",
585 		       cmoscentury, clockyear);
586 
587 		/* Kludge to roll over century. */
588 		if ((rtc_update_century > 0) ||
589 		    ((cmoscentury == 19) && (clockcentury == 20) &&
590 		     (clockyear == 2000))) {
591 			printf("WARNING: Setting NVRAM century to %d\n",
592 			       clockcentury);
593 			s = splclock();
594 			mc146818_write(NULL, NVRAM_CENTURY,
595 				       dectohexdec(clockcentury));
596 			splx(s);
597 		}
598 	} else if (cmoscentury == 19 && rtc_update_century == 0)
599 		rtc_update_century = 1; /* will update later in resettodr() */
600 
601 	return (clockyear);
602 }
603 
604 /*
605  * Initialize the time of day register, based on the time base which is, e.g.
606  * from a filesystem.
607  */
608 void
609 inittodr(base)
610 	time_t base;
611 {
612 	mc_todregs rtclk;
613 	struct clock_ymdhms dt;
614 	int s;
615 
616 	/*
617 	 * We mostly ignore the suggested time and go for the RTC clock time
618 	 * stored in the CMOS RAM.  If the time can't be obtained from the
619 	 * CMOS, or if the time obtained from the CMOS is 5 or more years
620 	 * less than the suggested time, we used the suggested time.  (In
621 	 * the latter case, it's likely that the CMOS battery has died.)
622 	 */
623 
624 	if (base < 15*SECYR) {	/* if before 1985, something's odd... */
625 		printf("WARNING: preposterous time in file system\n");
626 		/* read the system clock anyway */
627 		base = 17*SECYR + 186*SECDAY + SECDAY/2;
628 	}
629 
630 	time.tv_usec = 0;
631 
632 	s = splclock();
633 	if (rtcget(&rtclk)) {
634 		splx(s);
635 		printf("WARNING: invalid time in clock chip\n");
636 		goto fstime;
637 	}
638 	splx(s);
639 
640 	dt.dt_sec = hexdectodec(rtclk[MC_SEC]);
641 	dt.dt_min = hexdectodec(rtclk[MC_MIN]);
642 	dt.dt_hour = hexdectodec(rtclk[MC_HOUR]);
643 	dt.dt_day = hexdectodec(rtclk[MC_DOM]);
644 	dt.dt_mon = hexdectodec(rtclk[MC_MONTH]);
645 	dt.dt_year = clock_expandyear(hexdectodec(rtclk[MC_YEAR]));
646 
647 
648 	/*
649 	 * If time_t is 32 bits, then the "End of Time" is
650 	 * Mon Jan 18 22:14:07 2038 (US/Eastern)
651 	 * This code copes with RTC's past the end of time if time_t
652 	 * is an int32 or less. Needed because sometimes RTCs screw
653 	 * up or are badly set, and that would cause the time to go
654 	 * negative in the calculation below, which causes Very Bad
655 	 * Mojo. This at least lets the user boot and fix the problem.
656 	 * Note the code is self eliminating once time_t goes to 64 bits.
657 	 */
658 	if (sizeof(time_t) <= sizeof(int32_t)) {
659 		if (dt.dt_year >= 2038) {
660 			printf("WARNING: RTC time at or beyond 2038.\n");
661 			dt.dt_year = 2037;
662 			printf("WARNING: year set back to 2037.\n");
663 			printf("WARNING: CHECK AND RESET THE DATE!\n");
664 		}
665 	}
666 
667 	time.tv_sec = clock_ymdhms_to_secs(&dt) + tz.tz_minuteswest * 60;
668 	if (tz.tz_dsttime)
669 		time.tv_sec -= 3600;
670 
671 	if (base < time.tv_sec - 5*SECYR)
672 		printf("WARNING: file system time much less than clock time\n");
673 	else if (base > time.tv_sec + 5*SECYR) {
674 		printf("WARNING: clock time much less than file system time\n");
675 		printf("WARNING: using file system time\n");
676 		goto fstime;
677 	}
678 
679 	timeset = 1;
680 	return;
681 
682 fstime:
683 	timeset = 1;
684 	time.tv_sec = base;
685 	printf("WARNING: CHECK AND RESET THE DATE!\n");
686 }
687 
688 /*
689  * Reset the clock.
690  */
691 void
692 resettodr()
693 {
694 	mc_todregs rtclk;
695 	struct clock_ymdhms dt;
696 	int diff;
697 	int century;
698 	int s;
699 
700 	/*
701 	 * We might have been called by boot() due to a crash early
702 	 * on.  Don't reset the clock chip in this case.
703 	 */
704 	if (!timeset)
705 		return;
706 
707 	s = splclock();
708 	if (rtcget(&rtclk))
709 		bzero(&rtclk, sizeof(rtclk));
710 	splx(s);
711 
712 	diff = tz.tz_minuteswest * 60;
713 	if (tz.tz_dsttime)
714 		diff -= 3600;
715 	clock_secs_to_ymdhms(time.tv_sec - diff, &dt);
716 
717 	rtclk[MC_SEC] = dectohexdec(dt.dt_sec);
718 	rtclk[MC_MIN] = dectohexdec(dt.dt_min);
719 	rtclk[MC_HOUR] = dectohexdec(dt.dt_hour);
720 	rtclk[MC_DOW] = dt.dt_wday;
721 	rtclk[MC_YEAR] = dectohexdec(dt.dt_year % 100);
722 	rtclk[MC_MONTH] = dectohexdec(dt.dt_mon);
723 	rtclk[MC_DOM] = dectohexdec(dt.dt_day);
724 	s = splclock();
725 	rtcput(&rtclk);
726 	if (rtc_update_century > 0) {
727 		century = dectohexdec(dt.dt_year / 100);
728 		mc146818_write(NULL, NVRAM_CENTURY, century); /* XXX softc */
729 	}
730 	splx(s);
731 }
732 
733 void
734 setstatclockrate(arg)
735 	int arg;
736 {
737 	if (arg == stathz)
738 		mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_128_Hz);
739 	else
740 		mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | MC_RATE_1024_Hz);
741 }
742