tsc.c revision 2913
1153761Swollman/*-
2198270Sedwin * Copyright (c) 1990 The Regents of the University of California.
3192886Sedwin * All rights reserved.
4192886Sedwin *
5153761Swollman * This code is derived from software contributed to Berkeley by
62742Swollman * William Jolitz and Don Ahn.
786464Swollman *
82742Swollman * Redistribution and use in source and binary forms, with or without
92742Swollman * modification, are permitted provided that the following conditions
102742Swollman * are met:
112742Swollman * 1. Redistributions of source code must retain the above copyright
122742Swollman *    notice, this list of conditions and the following disclaimer.
132742Swollman * 2. Redistributions in binary form must reproduce the above copyright
1486222Swollman *    notice, this list of conditions and the following disclaimer in the
1586222Swollman *    documentation and/or other materials provided with the distribution.
162742Swollman * 3. All advertising materials mentioning features or use of this software
1758787Sru *    must display the following acknowledgement:
182742Swollman *	This product includes software developed by the University of
192742Swollman *	California, Berkeley and its contributors.
202742Swollman * 4. Neither the name of the University nor the names of its contributors
212742Swollman *    may be used to endorse or promote products derived from this software
222742Swollman *    without specific prior written permission.
232742Swollman *
2458787Sru * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2558787Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2658787Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
272742Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
282742Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
299908Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
302742Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3130711Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
322742Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
339908Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34169811Swollman * SUCH DAMAGE.
35169811Swollman *
36169811Swollman *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
37169811Swollman *	$Id: clock.c,v 1.19 1994/09/18 23:08:55 bde Exp $
38169811Swollman */
39169811Swollman
40169811Swollman /*
41169811Swollman  * inittodr, settodr and support routines written
42169811Swollman  * by Christoph Robitschko <chmr@edvz.tu-graz.ac.at>
43169811Swollman  *
44169811Swollman  * reintroduced and updated by Chris Stenton <chris@gnome.co.uk> 8/10/94
452742Swollman */
4658787Sru
47169811Swollman/*
48169811Swollman * Primitive clock interrupt routines.
49169811Swollman */
50169811Swollman#include <sys/param.h>
51169811Swollman#include <sys/systm.h>
529908Swollman#include <sys/time.h>
5320094Swollman#include <sys/kernel.h>
54149514Swollman#include <machine/frame.h>
5520094Swollman#include <i386/isa/icu.h>
5620094Swollman#include <i386/isa/isa.h>
5720094Swollman#include <i386/isa/rtc.h>
5820094Swollman#include <i386/isa/timerreg.h>
5920094Swollman
6020094Swollman/*
6120094Swollman * 32-bit time_t's can't reach leap years before 1904 or after 2036, so we
6220094Swollman * can use a simple formula for leap years.
6320094Swollman */
6420094Swollman#define	LEAPYEAR(y) ((u_int)(y) % 4 == 0)
6520094Swollman#define DAYSPERYEAR   (31+28+31+30+31+30+31+31+30+31+30+31)
6658787Sru
6758787Sru/* X-tals being what they are, it's nice to be able to fudge this one... */
6821217Swollman/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
6921217Swollman#ifndef TIMER_FREQ
7058787Sru#define	TIMER_FREQ	1193182	/* XXX - should be in isa.h */
7158787Sru#endif
722742Swollman#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
7358787Sru
7421217Swollmanstatic	int beeping;
7520094Swollmanint 	timer0_divisor = TIMER_DIV(100);	/* XXX should be hz */
7658787Sruu_int 	timer0_prescale;
7758787Sruint	adjkerntz = 0;	/* offset from CMOS clock */
7820094Swollmanstatic 	char timer0_state = 0, timer2_state = 0;
792742Swollmanstatic 	char timer0_reprogram = 0;
809908Swollmanstatic 	void (*timer_func)() = hardclock;
812742Swollmanstatic 	void (*new_function)();
8214343Swollmanstatic 	u_int new_rate;
8314343Swollmanstatic 	u_int hardclock_divisor;
84171948Sedwinstatic	const u_char daysinmonth[] = {31,28,31,30,31,30,31,31,30,31,30,31};
8514343Swollman
8614343Swollman#ifdef I586_CPU
8714343Swollmanint pentium_mhz = 0;
8864499Swollman#endif
8964499Swollman
9064499Swollmanvoid
9164499Swollmanclkintr(frame)
9264499Swollman	struct clockframe frame;
93149514Swollman{
94149514Swollman	hardclock(&frame);
95171948Sedwin}
96171948Sedwin
97171948Sedwinstatic u_char rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
982742Swollman
992742Swollman/*
1002742Swollman * This routine receives statistical clock interrupts from the RTC.
10158787Sru * As explained above, these occur at 128 interrupts per second.
1022742Swollman * When profiling, we receive interrupts at a rate of 1024 Hz.
1032742Swollman *
1049908Swollman * This does not actually add as much overhead as it sounds, because
105149514Swollman * when the statistical clock is active, the hardclock driver no longer
106149514Swollman * needs to keep (inaccurate) statistics on its own.  This decouples
107149514Swollman * statistics gathering from scheduling interrupts.
108149514Swollman *
109149514Swollman * The RTC chip requires that we read status register C (RTC_INTR)
1102742Swollman * to acknowledge an interrupt, before it will generate the next one.
11158787Sru */
11258787Sruvoid
11314343Swollmanrtcintr(struct clockframe frame)
11414343Swollman{
11558787Sru	u_char stat;
11614343Swollman	stat = rtcin(RTC_INTR);
11714343Swollman	if(stat & RTCIR_PERIOD) {
11814343Swollman		statclock(&frame);
11958787Sru	}
12014343Swollman}
12158787Sru
12258787Sru#ifdef DEBUG
12358787Sruvoid
124149514Swollmanprintrtc(void)
12558787Sru{
12658787Sru	outb(IO_RTC, RTC_STATUSA);
127149514Swollman	printf("RTC status A = %x", inb(IO_RTC+1));
128171948Sedwin	outb(IO_RTC, RTC_STATUSB);
129171948Sedwin	printf(", B = %x", inb(IO_RTC+1));
1302742Swollman	outb(IO_RTC, RTC_INTR);
1312742Swollman	printf(", C = %x\n", inb(IO_RTC+1));
13258787Sru}
13358787Sru#endif
13458787Sru
1352742Swollman#if 0
136149514Swollmanvoid
137149514Swollmantimerintr(struct clockframe frame)
138149514Swollman{
139149514Swollman	timer_func(&frame);
140149514Swollman	switch (timer0_state) {
1412742Swollman	case 0:
1429908Swollman		break;
1432742Swollman	case 1:
14414343Swollman		if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
14558787Sru			hardclock(&frame);
14614343Swollman			timer0_prescale = 0;
14714343Swollman		}
14858787Sru		break;
14958787Sru	case 2:
15014343Swollman		disable_intr();
151149514Swollman		outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
15258787Sru		outb(TIMER_CNTR0, TIMER_DIV(new_rate)%256);
153171948Sedwin		outb(TIMER_CNTR0, TIMER_DIV(new_rate)/256);
154149514Swollman		enable_intr();
155171948Sedwin		timer0_divisor = TIMER_DIV(new_rate);
156171948Sedwin		timer0_prescale = 0;
157171948Sedwin		timer_func = new_function;
1582742Swollman		timer0_state = 1;
1592742Swollman		break;
16058787Sru	case 3:
1612742Swollman		if ((timer0_prescale+=timer0_divisor) >= hardclock_divisor) {
1622742Swollman			hardclock(&frame);
1639908Swollman			disable_intr();
1642742Swollman			outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
16514343Swollman			outb(TIMER_CNTR0, TIMER_DIV(hz)%256);
16614343Swollman			outb(TIMER_CNTR0, TIMER_DIV(hz)/256);
16714343Swollman			enable_intr();
16814343Swollman			timer0_divisor = TIMER_DIV(hz);
16914343Swollman			timer0_prescale = 0;
17014343Swollman			timer_func = hardclock;;
17114343Swollman			timer0_state = 0;
17243543Swollman		}
17314343Swollman		break;
174149514Swollman	}
17558787Sru}
176171948Sedwin
177149514Swollman#endif
178171948Sedwin
179171948Sedwinint
180171948Sedwinacquire_timer0(int rate, void (*function)() )
1812742Swollman{
1822742Swollman	if (timer0_state || !function)
18358787Sru		return -1;
1842742Swollman
1852742Swollman	new_function = function;
1862742Swollman	new_rate = rate;
1872742Swollman	timer0_state = 2;
18858787Sru	return 0;
18958787Sru}
19058787Sru
1918029Swollman
19214343Swollmanint
19314343Swollmanacquire_timer2(int mode)
19475267Swollman{
19575267Swollman	if (timer2_state)
19675267Swollman		return -1;
19775267Swollman	timer2_state = 1;
19875267Swollman	outb(TIMER_MODE, TIMER_SEL2 | (mode &0x3f));
19975267Swollman	return 0;
20075267Swollman}
201149514Swollman
20275267Swollman
203171948Sedwinint
204149514Swollmanrelease_timer0()
205171948Sedwin{
206171948Sedwin	if (!timer0_state)
207171948Sedwin		return -1;
2082742Swollman	timer0_state = 3;
2092742Swollman	return 0;
21014343Swollman}
2118029Swollman
21214343Swollman
2132742Swollmanint
2142742Swollmanrelease_timer2()
21514343Swollman{
216169811Swollman	if (!timer2_state)
2172742Swollman		return -1;
21814343Swollman	timer2_state = 0;
21914343Swollman	outb(TIMER_MODE, TIMER_SEL2|TIMER_SQWAVE|TIMER_16BIT);
220169811Swollman	return 0;
22114343Swollman}
22230711Swollman
22330711Swollman
22458787Srustatic int
225169811Swollmangetit()
2262742Swollman{
22743014Swollman	int high, low;
22843014Swollman
22943014Swollman	disable_intr();
23043014Swollman	/* select timer0 and latch counter value */
2312742Swollman	outb(TIMER_MODE, TIMER_SEL0);
2322742Swollman	low = inb(TIMER_CNTR0);
233158421Swollman	high = inb(TIMER_CNTR0);
2342742Swollman	enable_intr();
23519878Swollman	return ((high << 8) | low);
23643014Swollman}
23743014Swollman
2382742Swollman#ifdef I586_CPU
2392742Swollmanstatic long long cycles_per_sec = 0;
24019878Swollman
24119878Swollman/*
2422742Swollman * Figure out how fast the cyclecounter runs.  This must be run with
2432742Swollman * clock interrupts disabled, but with the timer/counter programmed
244149514Swollman * and running.
245149514Swollman */
2462742Swollmanvoid
247149514Swollmancalibrate_cyclecounter(void)
248149514Swollman{
2492742Swollman	volatile long edx, eax, lasteax, lastedx;
2502742Swollman
25143543Swollman	__asm __volatile(".byte 0x0f, 0x31" : "=a"(lasteax), "=d"(lastedx) : );
25275267Swollman	DELAY(1000000);
25375267Swollman	__asm __volatile(".byte 0x0f, 0x31" : "=a"(eax), "=d"(edx) : );
2542742Swollman
2552742Swollman	/*
25643543Swollman	 * This assumes that you will never have a clock rate higher
2572742Swollman	 * than 4GHz, probably a good assumption.
2582742Swollman	 */
2592742Swollman	cycles_per_sec = (long long)edx + eax;
2602742Swollman	cycles_per_sec -= (long long)lastedx + lasteax;
26119878Swollman	pentium_mhz = ((long)cycles_per_sec + 500000) / 1000000; /* round up */
2622742Swollman}
26319878Swollman#endif
2642742Swollman
26519878Swollman/*
26643014Swollman * Wait "n" microseconds.
26743014Swollman * Relies on timer 1 counting down from (TIMER_FREQ / hz)
2682742Swollman * Note: timer had better have been programmed before this is first used!
2692742Swollman */
2702742Swollmanvoid
27175267SwollmanDELAY(int n)
27275267Swollman{
27375267Swollman	int prev_tick, tick, ticks_left, sec, usec;
27475267Swollman
2752742Swollman#ifdef DELAYDEBUG
2762742Swollman	int getit_calls = 1;
2772742Swollman	int n1;
2782742Swollman	static int state = 0;
27919878Swollman
2802742Swollman	if (state == 0) {
28119878Swollman		state = 1;
28219878Swollman		for (n1 = 1; n1 <= 10000000; n1 *= 10)
28319878Swollman			DELAY(n1);
2842742Swollman		state = 2;
28519878Swollman	}
28619878Swollman	if (state == 1)
28719878Swollman		printf("DELAY(%d)...", n);
2882742Swollman#endif
28914343Swollman	/*
29014343Swollman	 * Read the counter first, so that the rest of the setup overhead is
29175267Swollman	 * counted.  Guess the initial overhead is 20 usec (on most systems it
29275267Swollman	 * takes about 1.5 usec for each of the i/o's in getit().  The loop
29319878Swollman	 * takes about 6 usec on a 486/33 and 13 usec on a 386/20.  The
29475267Swollman	 * multiplications and divisions to scale the count take a while).
29575267Swollman	 */
29614343Swollman	prev_tick = getit(0, 0);
29714343Swollman	n -= 20;
29814343Swollman	/*
29914343Swollman	 * Calculate (n * (TIMER_FREQ / 1e6)) without using floating point
30019878Swollman	 * and without any avoidable overflows.
30119878Swollman	 */
30214343Swollman	sec = n / 1000000;
30319878Swollman	usec = n - sec * 1000000;
30419878Swollman	ticks_left = sec * TIMER_FREQ
30519878Swollman		     + usec * (TIMER_FREQ / 1000000)
30614343Swollman		     + usec * ((TIMER_FREQ % 1000000) / 1000) / 1000
30714343Swollman		     + usec * (TIMER_FREQ % 1000) / 1000000;
30814343Swollman
30914343Swollman	while (ticks_left > 0) {
31019878Swollman		tick = getit(0, 0);
31114343Swollman#ifdef DELAYDEBUG
31219878Swollman		++getit_calls;
31314343Swollman#endif
31458787Sru		if (tick > prev_tick)
31558787Sru			ticks_left -= prev_tick - (tick - timer0_divisor);
31658787Sru		else
31714343Swollman			ticks_left -= prev_tick - tick;
3182742Swollman		prev_tick = tick;
3192742Swollman	}
3202742Swollman#ifdef DELAYDEBUG
32119878Swollman	if (state == 1)
3222742Swollman		printf(" %d calls to getit() at %d usec each\n",
32319878Swollman		       getit_calls, (n + 5) / getit_calls);
32419878Swollman#endif
3252742Swollman}
3262742Swollman
3272742Swollman
32819878Swollmanstatic void
32919878Swollmansysbeepstop(chan)
33043014Swollman	void	*chan;
331158421Swollman{
33243014Swollman	outb(IO_PPI, inb(IO_PPI)&0xFC);	/* disable counter2 output to speaker */
3332742Swollman	release_timer2();
3342742Swollman	beeping = 0;
3352742Swollman}
3362742Swollman
3372742Swollman
3382742Swollmanint
3392742Swollmansysbeep(int pitch, int period)
3402742Swollman{
3412742Swollman
3422742Swollman	if (acquire_timer2(TIMER_SQWAVE|TIMER_16BIT))
343121098Swollman		return -1;
344121098Swollman	disable_intr();
345121098Swollman	outb(TIMER_CNTR2, pitch);
346121098Swollman	outb(TIMER_CNTR2, (pitch>>8));
347121098Swollman	enable_intr();
348121098Swollman	if (!beeping) {
349121098Swollman	outb(IO_PPI, inb(IO_PPI) | 3);	/* enable counter2 output to speaker */
350121098Swollman		beeping = period;
351121098Swollman		timeout(sysbeepstop, (void *)NULL, period);
352114173Swollman	}
353121098Swollman	return 0;
354114173Swollman}
355121098Swollman
3569908Swollman
357121098Swollman/*
358114173Swollman * RTC support routines
359121098Swollman */
360114173Swollmanstatic int
361121098Swollmanbcd2int(int bcd)
362169811Swollman{
363169811Swollman	return(bcd/16 *	10 + bcd%16);
364169811Swollman}
365169811Swollman
366169811Swollmanstatic int
367169811Swollmanint2bcd(int dez)
368169811Swollman{
369169811Swollman	return(dez/10 *	16 + dez%10);
3702742Swollman}
371114173Swollman
372121098Swollmanstatic void
3732742Swollmanwritertc(int port, int val)
374121098Swollman{
375121098Swollman	outb(IO_RTC, port);
3762742Swollman	outb(IO_RTC+1, val);
3778029Swollman}
37830711Swollman
37958787Srustatic int
38058787Srureadrtc(int port)
3812742Swollman{
38230711Swollman	return(bcd2int(rtcin(port)));
38358787Sru}
38458787Sru
38558787Sru
38630711Swollmanvoid
38730711Swollmanstartrtclock()
3882742Swollman{
3892742Swollman	int s;
3902742Swollman
3912742Swollman	/* initialize 8253 clock */
3922742Swollman	outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
3932742Swollman
39419878Swollman	/* Correct rounding will buy us a better precision in timekeeping */
39519878Swollman	outb (IO_TIMER1, TIMER_DIV(hz)%256);
39619878Swollman	outb (IO_TIMER1, TIMER_DIV(hz)/256);
3972742Swollman	timer0_divisor = hardclock_divisor = TIMER_DIV(hz);
3982742Swollman
3992742Swollman	/* initialize brain-dead battery powered clock */
4002742Swollman	outb (IO_RTC, RTC_STATUSA);
40119878Swollman	outb (IO_RTC+1, rtc_statusa);
40219878Swollman	outb (IO_RTC, RTC_STATUSB);
4032742Swollman	outb (IO_RTC+1, RTCSB_24HR);
40458787Sru
4059908Swollman	outb (IO_RTC, RTC_DIAG);
4069908Swollman	if (s = inb (IO_RTC+1))
40719878Swollman		printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
4089908Swollman	writertc(RTC_DIAG, 0);
4092742Swollman}
4102742Swollman
4112742Swollman
41286222Swollman/*
41319878Swollman * Initialize the time of day register,	based on the time base which is, e.g.
4142742Swollman * from	a filesystem.
4152742Swollman */
4162742Swollmanvoid
4172742Swollmaninittodr(base)
41858787Srutime_t	base;
41958787Sru{
4202742Swollman	unsigned long	sec, days;
42114343Swollman	int		yd;
42214343Swollman	int		year, month;
42314343Swollman	int		y, m, s;
42419878Swollman
42514343Swollman	s = splclock();
42614343Swollman	time.tv_sec  = base;
42714343Swollman	time.tv_usec = 0;
42814343Swollman	splx(s);
429149514Swollman
430196582Sedwin	/* Look	if we have a RTC present and the time is valid */
431196582Sedwin	if (rtcin(RTC_STATUSD) != RTCSD_PWR)
432196582Sedwin		goto wrong_time;
433196582Sedwin
434196582Sedwin	/* wait	for time update	to complete */
435196582Sedwin	/* If RTCSA_TUP	is zero, we have at least 244us	before next update */
436196582Sedwin	while (rtcin(RTC_STATUSA) & RTCSA_TUP);
437196582Sedwin
438196582Sedwin	days = 0;
439196582Sedwin	year = readrtc(RTC_YEAR) + readrtc(RTC_CENTURY)	* 100;
440196582Sedwin	if (year < 1970)
441196582Sedwin		goto wrong_time;
442196582Sedwin	month =	readrtc(RTC_MONTH);
443196582Sedwin	for (m = 1; m <	month; m++)
444196582Sedwin		days +=	daysinmonth[m-1];
445196582Sedwin	if ((month > 2)	&& LEAPYEAR(year))
446197000Sedwin		days ++;
447197000Sedwin	days +=	readrtc(RTC_DAY) - 1;
448197000Sedwin	yd = days;
449197000Sedwin	for (y = 1970; y < year; y++)
450197000Sedwin		days +=	DAYSPERYEAR + LEAPYEAR(y);
451197000Sedwin	sec = ((( days * 24 +
452197000Sedwin		  readrtc(RTC_HRS)) * 60 +
453197000Sedwin		  readrtc(RTC_MIN)) * 60 +
454197000Sedwin		  readrtc(RTC_SEC));
455197000Sedwin	/* sec now contains the	number of seconds, since Jan 1 1970,
456197000Sedwin	   in the local	time zone */
457197000Sedwin
458197000Sedwin	sec += tz.tz_minuteswest * 60;
459197000Sedwin
460198270Sedwin	s = splclock();
461198270Sedwin	time.tv_sec = sec;
462198270Sedwin	splx(s);
463198270Sedwin	return;
464198270Sedwin
465198270Sedwinwrong_time:
466198270Sedwin	printf("Invalid	time in	real time clock.\n");
467198270Sedwin	printf("Check and reset	the date immediately!\n");
468198270Sedwin}
469198270Sedwin
470198270Sedwin
471198270Sedwin/*
472198270Sedwin * Write system	time back to RTC
473198270Sedwin */
474198270Sedwinvoid resettodr()
475198270Sedwin{
476198270Sedwin	unsigned long	tm;
477198270Sedwin	int		y, m, fd, r, s;
478198270Sedwin
479198270Sedwin	s = splclock();
480198270Sedwin	tm = time.tv_sec;
481198270Sedwin	splx(s);
482198270Sedwin
483198270Sedwin/* First, disable clock	updates	*/
484198270Sedwin	writertc(RTC_STATUSB, RTCSB_HALT | RTCSB_24HR);
485198270Sedwin
486198270Sedwin	/* Calculate local time	to put in CMOS */
487198270Sedwin
488198270Sedwin	tm -= tz.tz_minuteswest * 60 + adjkerntz;
489198270Sedwin
49014343Swollman	writertc(RTC_SEC, int2bcd(tm%60)); tm /= 60;	/* Write back Seconds */
49114343Swollman	writertc(RTC_MIN, int2bcd(tm%60)); tm /= 60;	/* Write back Minutes */
49219878Swollman	writertc(RTC_HRS, int2bcd(tm%24)); tm /= 24;	/* Write back Hours   */
493197000Sedwin
494197000Sedwin	/* We have now the days	since 01-01-1970 in tm */
495197000Sedwin	writertc(RTC_WDAY, (tm+4)%7);			/* Write back Weekday */
49614343Swollman	for (y=1970;; y++)
4972742Swollman		if ((tm	- DAYSPERYEAR -	LEAPYEAR(y)) > tm)
4982742Swollman			break;
4992742Swollman		else
5002742Swollman			tm -= DAYSPERYEAR + LEAPYEAR(y);
50119878Swollman
5022742Swollman	/* Now we have the years in y and the day-of-the-year in tm */
5032742Swollman	writertc(RTC_YEAR, int2bcd(y%100));		/* Write back Year    */
5042742Swollman	writertc(RTC_CENTURY, int2bcd(y/100));		/* ... and Century    */
5052742Swollman	if (LEAPYEAR(y)	&& (tm >= 31+29))
50619878Swollman		tm--;					/* Subtract Feb-29 */
5072742Swollman	for (m=1;; m++)
5082742Swollman		if (tm - daysinmonth[m-1] > tm)
50958787Sru			break;
51075267Swollman		else
51175267Swollman			tm -= daysinmonth[m-1];
512114173Swollman
513114173Swollman	writertc(RTC_MONTH, int2bcd(m));		/* Write back Month   */
5142742Swollman	writertc(RTC_DAY, int2bcd(tm+1));		/* Write back Day     */
5152742Swollman
51658787Sru	/* enable time updates */
51758787Sru	writertc(RTC_STATUSB, RTCSB_24HR);
51858787Sru}
5192742Swollman
5202742Swollman
5212742Swollman#ifdef garbage
5222742Swollman/*
52319878Swollman * Initialze the time of day register, based on the time base which is, e.g.
5242742Swollman * from a filesystem.
52543014Swollman */
52643014Swollmantest_inittodr(time_t base)
52743014Swollman{
52843014Swollman
529171948Sedwin	outb(IO_RTC,9); /* year    */
530171948Sedwin	printf("%d ",bcd(inb(IO_RTC+1)));
531171948Sedwin	outb(IO_RTC,8); /* month   */
532171948Sedwin	printf("%d ",bcd(inb(IO_RTC+1)));
533171948Sedwin	outb(IO_RTC,7); /* day     */
534171948Sedwin	printf("%d ",bcd(inb(IO_RTC+1)));
535171948Sedwin	outb(IO_RTC,4); /* hour    */
536171948Sedwin	printf("%d ",bcd(inb(IO_RTC+1)));
537171948Sedwin	outb(IO_RTC,2); /* minutes */
53843014Swollman	printf("%d ",bcd(inb(IO_RTC+1)));
53943014Swollman	outb(IO_RTC,0); /* seconds */
540171948Sedwin	printf("%d\n",bcd(inb(IO_RTC+1)));
541171948Sedwin
542171948Sedwin	time.tv_sec = base;
54343014Swollman}
54443014Swollman#endif
54543014Swollman
54643014Swollman/*
54743014Swollman * Wire clock interrupt in.
54843014Swollman */
54943014Swollmanvoid
55043014Swollmanenablertclock()
55143014Swollman{
55243014Swollman	register_intr(/* irq */ 0, /* XXX id */ 0, /* flags */ 0, clkintr,
553149514Swollman		      HWI_MASK | SWI_MASK, /* unit */ 0);
554149514Swollman	INTREN(IRQ0);
555149514Swollman	register_intr(/* irq */ 8, /* XXX id */ 1, /* flags */ 0, rtcintr,
556149514Swollman		      SWI_CLOCK_MASK, /* unit */ 0);
557149514Swollman	INTREN(IRQ8);
558149514Swollman	outb(IO_RTC, RTC_STATUSB);
559149514Swollman	outb(IO_RTC+1, RTCSB_PINTR | RTCSB_24HR);
560149514Swollman}
561149514Swollman
562149514Swollmanvoid
563149514Swollmancpu_initclocks()
56443014Swollman{
565121098Swollman	stathz = RTC_NOPROFRATE;
566121098Swollman	profhz = RTC_PROFRATE;
56743014Swollman	enablertclock();
56843014Swollman}
56943014Swollman
57043014Swollmanvoid
57143014Swollmansetstatclockrate(int newhz)
57243014Swollman{
57343014Swollman	if(newhz == RTC_PROFRATE) {
57443014Swollman		rtc_statusa = RTCSA_DIVIDER | RTCSA_PROF;
57543014Swollman	} else {
57643014Swollman		rtc_statusa = RTCSA_DIVIDER | RTCSA_NOPROF;
57743014Swollman	}
57843014Swollman	outb(IO_RTC, RTC_STATUSA);
57943014Swollman	outb(IO_RTC+1, rtc_statusa);
5802742Swollman}
5812742Swollman