Home | History | Annotate | Line # | Download | only in isa
clock.c revision 1.12
      1 /*	$NetBSD: clock.c,v 1.12 2006/09/12 17:07:14 gdamore Exp $	*/
      2 
      3 /*
      4  * Copyright 1997
      5  * Digital Equipment Corporation. All rights reserved.
      6  *
      7  * This software is furnished under license and may be used and
      8  * copied only in accordance with the following terms and conditions.
      9  * Subject to these conditions, you may download, copy, install,
     10  * use, modify and distribute this software in source and/or binary
     11  * form. No title or ownership is transferred hereby.
     12  *
     13  * 1) Any source code used, modified or distributed must reproduce
     14  *    and retain this copyright notice and list of conditions as
     15  *    they appear in the source file.
     16  *
     17  * 2) No right is granted to use any trade name, trademark, or logo of
     18  *    Digital Equipment Corporation. Neither the "Digital Equipment
     19  *    Corporation" name nor any trademark or logo of Digital Equipment
     20  *    Corporation may be used to endorse or promote products derived
     21  *    from this software without the prior written permission of
     22  *    Digital Equipment Corporation.
     23  *
     24  * 3) This software is provided "AS-IS" and any express or implied
     25  *    warranties, including but not limited to, any implied warranties
     26  *    of merchantability, fitness for a particular purpose, or
     27  *    non-infringement are disclaimed. In no event shall DIGITAL be
     28  *    liable for any damages whatsoever, and in particular, DIGITAL
     29  *    shall not be liable for special, indirect, consequential, or
     30  *    incidental damages or damages for lost profits, loss of
     31  *    revenue or loss of use, whether such damages arise in contract,
     32  *    negligence, tort, under statute, in equity, at law or otherwise,
     33  *    even if advised of the possibility of such damage.
     34  */
     35 
     36 /*-
     37  * Copyright (c) 1990 The Regents of the University of California.
     38  * All rights reserved.
     39  *
     40  * This code is derived from software contributed to Berkeley by
     41  * William Jolitz and Don Ahn.
     42  *
     43  * Redistribution and use in source and binary forms, with or without
     44  * modification, are permitted provided that the following conditions
     45  * are met:
     46  * 1. Redistributions of source code must retain the above copyright
     47  *    notice, this list of conditions and the following disclaimer.
     48  * 2. Redistributions in binary form must reproduce the above copyright
     49  *    notice, this list of conditions and the following disclaimer in the
     50  *    documentation and/or other materials provided with the distribution.
     51  * 3. Neither the name of the University nor the names of its contributors
     52  *    may be used to endorse or promote products derived from this software
     53  *    without specific prior written permission.
     54  *
     55  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     56  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     57  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     58  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     59  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     60  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     61  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     62  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     63  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     64  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     65  * SUCH DAMAGE.
     66  *
     67  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
     68  */
     69 /*-
     70  * Copyright (c) 1993, 1994 Charles M. Hannum.
     71  *
     72  * This code is derived from software contributed to Berkeley by
     73  * William Jolitz and Don Ahn.
     74  *
     75  * Redistribution and use in source and binary forms, with or without
     76  * modification, are permitted provided that the following conditions
     77  * are met:
     78  * 1. Redistributions of source code must retain the above copyright
     79  *    notice, this list of conditions and the following disclaimer.
     80  * 2. Redistributions in binary form must reproduce the above copyright
     81  *    notice, this list of conditions and the following disclaimer in the
     82  *    documentation and/or other materials provided with the distribution.
     83  * 3. All advertising materials mentioning features or use of this software
     84  *    must display the following acknowledgement:
     85  *	This product includes software developed by the University of
     86  *	California, Berkeley and its contributors.
     87  * 4. Neither the name of the University nor the names of its contributors
     88  *    may be used to endorse or promote products derived from this software
     89  *    without specific prior written permission.
     90  *
     91  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     92  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     93  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     94  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     95  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     96  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     97  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     98  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     99  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
    100  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
    101  * SUCH DAMAGE.
    102  *
    103  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
    104  */
    105 /*
    106  * Mach Operating System
    107  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
    108  * All Rights Reserved.
    109  *
    110  * Permission to use, copy, modify and distribute this software and its
    111  * documentation is hereby granted, provided that both the copyright
    112  * notice and this permission notice appear in all copies of the
    113  * software, derivative works or modified versions, and any portions
    114  * thereof, and that both notices appear in supporting documentation.
    115  *
    116  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
    117  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
    118  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
    119  *
    120  * Carnegie Mellon requests users of this software to return to
    121  *
    122  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
    123  *  School of Computer Science
    124  *  Carnegie Mellon University
    125  *  Pittsburgh PA 15213-3890
    126  *
    127  * any improvements or extensions that they make and grant Carnegie Mellon
    128  * the rights to redistribute these changes.
    129  */
    130 /*
    131   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
    132 
    133 		All Rights Reserved
    134 
    135 Permission to use, copy, modify, and distribute this software and
    136 its documentation for any purpose and without fee is hereby
    137 granted, provided that the above copyright notice appears in all
    138 copies and that both the copyright notice and this permission notice
    139 appear in supporting documentation, and that the name of Intel
    140 not be used in advertising or publicity pertaining to distribution
    141 of the software without specific, written prior permission.
    142 
    143 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
    144 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
    145 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
    146 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
    147 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
    148 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
    149 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
    150 */
    151 
    152 /*
    153  * Primitive clock interrupt routines.
    154  */
    155 
    156 #include <sys/cdefs.h>
    157 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.12 2006/09/12 17:07:14 gdamore Exp $");
    158 
    159 #include <sys/param.h>
    160 #include <sys/systm.h>
    161 #include <sys/time.h>
    162 #include <sys/kernel.h>
    163 #include <sys/device.h>
    164 
    165 #include <machine/cpu.h>
    166 #include <machine/intr.h>
    167 #include <machine/pio.h>
    168 #include <arm/cpufunc.h>
    169 
    170 #include <dev/isa/isareg.h>
    171 #include <dev/isa/isavar.h>
    172 #include <dev/ic/mc146818reg.h>
    173 #include <dev/ic/i8253reg.h>
    174 #include <shark/isa/nvram.h>
    175 #include <shark/isa/spkrreg.h>
    176 #include <shark/shark/hat.h>
    177 
    178 void	sysbeepstop(void *);
    179 void	sysbeep(int, int);
    180 void	rtcinit(void);
    181 int     timer_hz_to_count(int);
    182 
    183 static void findcpuspeed(void);
    184 static void init_isa_timer_tables(void);
    185 static void delayloop(int);
    186 static int  clockintr(void *);
    187 static int  gettick(void);
    188 
    189 void startrtclock(void);
    190 
    191 inline unsigned mc146818_read(void *, unsigned);
    192 inline void mc146818_write(void *, unsigned, unsigned);
    193 
    194 inline unsigned
    195 mc146818_read(void *sc, unsigned reg)
    196 {
    197 
    198 	outb(IO_RTC, reg);
    199 	return (inb(IO_RTC+1));
    200 }
    201 
    202 inline void
    203 mc146818_write(void *sc, unsigned reg, unsigned datum)
    204 {
    205 
    206 	outb(IO_RTC, reg);
    207 	outb(IO_RTC+1, datum);
    208 }
    209 
    210 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    211 
    212 /* number of timer ticks in a Musec = 2^20 usecs */
    213 #define TIMER_MUSECFREQ\
    214     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    215 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    216 
    217 /*
    218  * microtime() makes use of the following globals.
    219  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    220  * microsecond increment.
    221  *
    222  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    223  */
    224 
    225 u_short	isa_timer_msb_table[256];	/* timer->usec MSB */
    226 u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    227 
    228 /* 64 bit counts from timer 0 */
    229 struct count64 {
    230 	unsigned lo;   /* low 32 bits */
    231 	unsigned hi;   /* high 32 bits */
    232 };
    233 
    234 #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    235 
    236 struct count64 timer0count;
    237 struct count64 timer0_at_last_clockintr;
    238 unsigned       timer0last;
    239 
    240 /*#define TESTHAT*/
    241 #ifdef TESTHAT
    242 #define HATSTACKSIZE 1024
    243 #define HATHZ  50000
    244 #define HATHZ2 10000
    245 unsigned char hatStack[HATSTACKSIZE];
    246 
    247 unsigned testHatOn = 0;
    248 unsigned nHats = 0;
    249 unsigned nHatWedges = 0;
    250 unsigned fiqReason = 0;
    251 unsigned hatCount = 0;
    252 unsigned hatCount2 = 0;
    253 
    254 void hatTest(int testReason)
    255 {
    256 
    257 	fiqReason |= testReason;
    258 	nHats++;
    259 }
    260 
    261 void hatWedge(int nFIQs)
    262 {
    263 
    264 	printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    265 	nHatWedges++;
    266 }
    267 #endif
    268 
    269 void
    270 startrtclock(void)
    271 {
    272 
    273 	findcpuspeed();		/* use the clock (while it's free) to
    274 				   find the CPU speed */
    275 
    276 	init_isa_timer_tables();
    277 
    278 	timer0count.lo = 0;
    279 	timer0count.hi = 0;
    280 	timer0_at_last_clockintr.lo = 0;
    281 	timer0_at_last_clockintr.hi = 0;
    282 	timer0last     = 0;
    283 
    284 	/* initialize 8253 clock */
    285 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    286 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    287 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    288 
    289 #ifdef TESTHAT
    290 	hatCount = timer_hz_to_count(HATHZ);
    291 	hatCount2 = timer_hz_to_count(HATHZ2);
    292 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    293 #endif
    294 }
    295 
    296 static void
    297 init_isa_timer_tables(void)
    298 {
    299 	int s;
    300 	u_long t, msbmillion, quotient, remainder;
    301 
    302 	for (s = 0; s < 256; s++) {
    303 	        /* LSB table is easy, just divide and round */
    304 		t = ((u_long) s * 1000000 * 2) / TIMER_FREQ;
    305 		isa_timer_lsb_table[s] = (u_short) ((t / 2) + (t & 0x1));
    306 
    307 		msbmillion = s * 1000000;
    308 		quotient = msbmillion / TIMER_FREQ;
    309 		remainder = msbmillion % TIMER_FREQ;
    310 		t = (remainder * 256 * 2) / TIMER_FREQ;
    311 		isa_timer_msb_table[s] =
    312 		  (u_short)((t / 2) + (t & 1) + (quotient * 256));
    313 
    314 #ifdef DIAGNOSTIC
    315 		if ((s > 0) &&
    316 		    (isa_timer_msb_table[s] <
    317 		     (isa_timer_msb_table[s - 1] + isa_timer_lsb_table[0xFF])))
    318 		  panic ("time tables not monotonic %d: %d < (%d + %d) = %d\n",
    319 			 s, isa_timer_msb_table[s],
    320 			 isa_timer_msb_table[s - 1],
    321 			 isa_timer_lsb_table[0xFF],
    322 			 isa_timer_msb_table[s - 1] +
    323 			 isa_timer_lsb_table[0xFF]);
    324 #endif
    325 	} /* END for */
    326 }
    327 
    328 int
    329 timer_hz_to_count(int timer_hz)
    330 {
    331 	u_long tval;
    332 
    333 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    334 	tval = (tval / 2) + (tval & 0x1);
    335 
    336 	return (int)tval;
    337 }
    338 
    339 void gettimer0count(struct count64 *);
    340 
    341 /* must be called at SPL_CLOCK or higher */
    342 void gettimer0count(struct count64 *pcount)
    343 {
    344 	unsigned current, ticks, oldlo;
    345 
    346 	/*
    347 	 * Latch the current value of the timer and then read it.
    348 	 * This guarantees an atomic reading of the time.
    349 	 */
    350 
    351 	current = gettick();
    352 
    353 	if (timer0last >= current)
    354 		ticks = timer0last - current;
    355 	else
    356 		ticks = timer0last + (TIMER0_ROLLOVER - current);
    357 
    358 	timer0last = current;
    359 
    360 	oldlo = timer0count.lo;
    361 
    362 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    363 		timer0count.hi++;
    364 
    365 	*pcount = timer0count;
    366 }
    367 
    368 static int
    369 clockintr(void *arg)
    370 {
    371 	struct clockframe *frame = arg;		/* not strictly necessary */
    372 	extern void isa_specific_eoi(int irq);
    373 #ifdef TESTHAT
    374 	static int ticks = 0;
    375 #endif
    376 	static int hatUnwedgeCtr = 0;
    377 
    378 	gettimer0count(&timer0_at_last_clockintr);
    379 
    380 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    381 
    382 	/* check to see if the high-availability timer needs to be unwedged */
    383 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    384 		hatUnwedgeCtr = 0;
    385 		hatUnwedge();
    386 	}
    387 
    388 #ifdef TESTHAT
    389 	++ticks;
    390 
    391 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    392 		if (testHatOn == 1) {
    393 			hatClkAdjust(hatCount2);
    394 			testHatOn = 2;
    395 		} else {
    396 			testHatOn = 0;
    397 			hatClkOff();
    398 			printf("hat off status: %d %d %x\n", nHats,
    399 			    nHatWedges, fiqReason);
    400 		}
    401 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    402 		printf("hat on status: %d %d %x\n",
    403 		    nHats, nHatWedges, fiqReason);
    404 		testHatOn = 1;
    405 		nHats = 0;
    406 		fiqReason = 0;
    407 		hatClkOn(hatCount, hatTest, 0xfeedface,
    408 		    hatStack + HATSTACKSIZE - sizeof(unsigned),
    409 		    hatWedge);
    410 	}
    411 #endif
    412 	hardclock(frame);
    413 	return(0);
    414 }
    415 
    416 static int
    417 gettick(void)
    418 {
    419 	u_char lo, hi;
    420 	u_int savedints;
    421 
    422 	/* Don't want someone screwing with the counter while we're here. */
    423 	savedints = disable_interrupts(I32_bit);
    424 	/* Select counter 0 and latch it. */
    425 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    426 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    427 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    428 	restore_interrupts(savedints);
    429 	return ((hi << 8) | lo);
    430 }
    431 
    432 /* modifications from i386 to shark isa version:
    433    - removed hardcoded "n -=" values that approximated the time to
    434      calculate delay ticks
    435    - made the time to calculate delay ticks almost negligable. 4 multiplies
    436      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    437      as opposed to 4 multiplies plus a bunch of divides.
    438    - removed i386 assembly language hack
    439    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    440      of magnitude low
    441    - put code in delay() to use delayloop() for short delays
    442    - microtime no longer in assembly language
    443 */
    444 
    445 /*
    446  * Wait "n" microseconds.
    447  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    448  * Note: timer had better have been programmed before this is first used!
    449  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    450  * wave' mode counts at 2:1).
    451  */
    452 void
    453 delay(unsigned n)
    454 {
    455 	int ticks, otick;
    456 	int nticks;
    457 
    458 	if (n < 100) {
    459 		/* it can take a long time (1 usec or longer) just for
    460 		   1 ISA read, so it's best not to use the timer for
    461 		   short delays */
    462 		delayloop((n * count1024usec) >> 10);
    463 		return;
    464 	}
    465 
    466 	/*
    467 	 * Read the counter first, so that the rest of the setup overhead is
    468 	 * counted.
    469 	 */
    470 	otick = gettick();
    471 
    472 	/*
    473 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    474 	 * without any avoidable overflows.
    475 	 */
    476 	{
    477 	        /* a Musec = 2^20 usec */
    478 		int Musec = n >> 20,
    479 		    usec = n & ((1 << 20) - 1);
    480 		nticks
    481 		  = (Musec * TIMER_MUSECFREQ) +
    482 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    483 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    484 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    485 	}
    486 
    487 	while (nticks > 0) {
    488 		ticks = gettick();
    489 		if (ticks > otick)
    490 			nticks -= TIMER0_ROLLOVER - (ticks - otick);
    491 		else
    492 			nticks -= otick - ticks;
    493 		otick = ticks;
    494 	}
    495 
    496 }
    497 
    498 void
    499 sysbeepstop(void *arg)
    500 {
    501 }
    502 
    503 void
    504 sysbeep(int pitch, int period)
    505 {
    506 }
    507 
    508 #define FIRST_GUESS   0x2000
    509 
    510 static void
    511 findcpuspeed(void)
    512 {
    513 	int ticks;
    514 	unsigned int guess = FIRST_GUESS;
    515 
    516 	while (1) { /* loop until accurate enough */
    517 		/* Put counter in count down mode */
    518 		outb(IO_TIMER1 + TIMER_MODE,
    519 		    TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    520 		outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    521 		outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    522 		delayloop(guess);
    523 
    524 		/* Read the value left in the counter */
    525 		/*
    526 		 * Formula for delaycount is:
    527 		 *  (loopcount * timer clock speed) / (counter ticks * 1000)
    528 		 */
    529 		ticks = 0xFFFF - gettick();
    530 		if (ticks == 0) ticks = 1; /* just in case */
    531 		if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    532 			guess *= max(2, (TIMER_MUSECDIV(1024) / ticks));
    533 			continue;
    534 		}
    535 		count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    536 		return;
    537 	}
    538 }
    539 
    540 static void
    541 delayloop(int counts)
    542 {
    543 	while (counts--)
    544 		__insn_barrier();
    545 }
    546 
    547 void
    548 cpu_initclocks(void)
    549 {
    550         unsigned hzval;
    551 
    552 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    553 
    554 	/* install RTC interrupt handler */
    555 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    556 				 clockintr, 0);
    557 
    558 	/* code for values of hz that don't divide 1000000 exactly */
    559         tickfix = 1000000 - (hz * tick);
    560         if (tickfix) {
    561                 int ftp;
    562 
    563                 ftp = min(ffs(tickfix), ffs(hz));
    564                 tickfix >>= (ftp - 1);
    565                 tickfixinterval = hz >> (ftp - 1);
    566         }
    567 
    568 	/* set  up periodic interrupt @ hz
    569 	   this is the subset of hz values in kern_clock.c that are
    570 	   supported by the ISA RTC */
    571 	switch (hz) {
    572 	case 64:
    573 		hzval = MC_RATE_64_Hz;
    574 		break;
    575 	case 128:
    576 		hzval = MC_RATE_128_Hz;
    577 		break;
    578 	case 256:
    579 		hzval = MC_RATE_256_Hz;
    580 		break;
    581 	case 1024:
    582 		hzval = MC_RATE_1024_Hz;
    583 		break;
    584 	default:
    585 		panic("cannot configure hz = %d", hz);
    586         }
    587 
    588 	rtcinit(); /* make sure basics are done by now */
    589 
    590 	/* blast values to set up clock interrupt */
    591 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    592 	/* enable periodic interrupt */
    593 	mc146818_write(NULL, MC_REGB,
    594 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    595 }
    596 
    597 void
    598 rtcinit(void)
    599 {
    600 	static int first_rtcopen_ever = 1;
    601 
    602 	if (!first_rtcopen_ever)
    603 		return;
    604 	first_rtcopen_ever = 0;
    605 
    606 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    607 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    608 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    609 }
    610 
    611 void
    612 setstatclockrate(int arg)
    613 {
    614 }
    615 
    616 /*
    617  * void microtime(struct timeval *tvp)
    618  *
    619  * Fill in the specified timeval struct with the current time
    620  * accurate to the microsecond.
    621  */
    622 
    623 void
    624 microtime(struct timeval *tvp)
    625 {
    626         int s;
    627 	unsigned lsb, msb;
    628 	int tm;
    629 	static struct timeval oldtv;
    630 	struct count64 timer0current;
    631 	int ticks;
    632 
    633 	s = splstatclock();
    634 
    635 	gettimer0count(&timer0current);
    636 
    637 	tm = time.tv_usec;
    638 
    639 	/* unsigned arithmetic should take care of overflow */
    640 	/* with a >= 32 Hz clock, ticks will always be < 0x7FFF */
    641 	ticks = (int)((unsigned)
    642 		      (timer0current.lo - timer0_at_last_clockintr.lo));
    643 
    644 #ifdef DIAGNOSTIC
    645 	if ((ticks < 0) || (ticks > 0xffff))
    646 		printf("microtime bug: ticks = %x\n", ticks);
    647 #endif
    648 
    649 	while (ticks > 0) {
    650 
    651 		if (ticks < 0xffff) {
    652 			msb = (ticks >> 8) & 0xFF;
    653 			lsb = ticks & 0xFF;
    654 		} else {
    655 			msb = 0xff;
    656 			lsb = 0xff;
    657 		}
    658 
    659 		/* see comments above */
    660 		tm  += isa_timer_msb_table[msb] + isa_timer_lsb_table[lsb];
    661 
    662 		/* for a 64 Hz RTC, ticks will never overflow table */
    663 		/* microtime will be less accurate if the RTC is < 36 Hz */
    664 		ticks -= 0xffff;
    665 	}
    666 
    667 	tvp->tv_sec = time.tv_sec;
    668 	if (tm >= 1000000) {
    669 		tvp->tv_sec += 1;
    670 		tm -= 1000000;
    671 	}
    672 
    673 	tvp->tv_usec = tm;
    674 
    675 	/* Make sure the time has advanced. */
    676 
    677 	if (tvp->tv_sec == oldtv.tv_sec &&
    678 	    tvp->tv_usec <= oldtv.tv_usec) {
    679 		tvp->tv_usec = oldtv.tv_usec + 1;
    680 		if (tvp->tv_usec >= 1000000) {
    681 			tvp->tv_usec -= 1000000;
    682 			++tvp->tv_sec;
    683 		}
    684 	}
    685 
    686 	oldtv = *tvp;
    687 	(void)splx(s);
    688 }
    689 
    690 /* End of clock.c */
    691