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