Home | History | Annotate | Line # | Download | only in isa
      1 /*	$NetBSD: clock.c,v 1.20 2023/12/09 00:02:10 andvar 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.20 2023/12/09 00:02:10 andvar Exp $");
    158 
    159 #include <sys/param.h>
    160 #include <sys/systm.h>
    161 #include <sys/time.h>
    162 #include <sys/timetc.h>
    163 #include <sys/kernel.h>
    164 #include <sys/device.h>
    165 
    166 #include <machine/cpu.h>
    167 #include <machine/intr.h>
    168 #include <machine/irqhandler.h>
    169 #include <machine/pio.h>
    170 #include <arm/cpufunc.h>
    171 
    172 #include <dev/isa/isareg.h>
    173 #include <dev/isa/isavar.h>
    174 #include <dev/ic/mc146818reg.h>
    175 #include <dev/ic/i8253reg.h>
    176 #include <shark/isa/nvram.h>
    177 #include <shark/isa/spkrreg.h>
    178 #include <shark/shark/hat.h>
    179 
    180 void	sysbeepstop(void *);
    181 void	sysbeep(int, int);
    182 void	rtcinit(void);
    183 int     timer_hz_to_count(int);
    184 
    185 static void findcpuspeed(void);
    186 static void delayloop(int);
    187 static int  clockintr(void *);
    188 static int  gettick(void);
    189 static void tc_init_i8253(void);
    190 
    191 void startrtclock(void);
    192 
    193 inline unsigned mc146818_read(void *, unsigned);
    194 inline void mc146818_write(void *, unsigned, unsigned);
    195 
    196 inline unsigned
    197 mc146818_read(void *sc, unsigned reg)
    198 {
    199 
    200 	outb(IO_RTC, reg);
    201 	return (inb(IO_RTC+1));
    202 }
    203 
    204 inline void
    205 mc146818_write(void *sc, unsigned reg, unsigned datum)
    206 {
    207 
    208 	outb(IO_RTC, reg);
    209 	outb(IO_RTC+1, datum);
    210 }
    211 
    212 unsigned int count1024usec; /* calibrated loop variable (1024 microseconds) */
    213 
    214 /* number of timer ticks in a Musec = 2^20 usecs */
    215 #define TIMER_MUSECFREQ\
    216     (((((((TIMER_FREQ) * 1024) + 999) / 1000) * 1024) + 999) / 1000)
    217 #define TIMER_MUSECDIV(x) ((TIMER_MUSECFREQ+(x)/2)/(x))
    218 
    219 /*
    220  * microtime() makes use of the following globals.
    221  * timer_msb_table[] and timer_lsb_table[] are used to compute the
    222  * microsecond increment.
    223  *
    224  * time.tv_usec += isa_timer_msb_table[cnt_msb] + isa_timer_lsb_table[cnt_lsb];
    225  */
    226 
    227 u_short	isa_timer_lsb_table[256];	/* timer->usec conversion for LSB */
    228 
    229 /* 64 bit counts from timer 0 */
    230 struct count64 {
    231 	unsigned lo;   /* low 32 bits */
    232 	unsigned hi;   /* high 32 bits */
    233 };
    234 
    235 #define TIMER0_ROLLOVER  0xFFFF  /* maximum rollover for 8254 counter */
    236 
    237 struct count64 timer0count;
    238 struct count64 timer0_at_last_clockintr;
    239 unsigned       timer0last;
    240 
    241 /*#define TESTHAT*/
    242 #ifdef TESTHAT
    243 #define HATSTACKSIZE 1024
    244 #define HATHZ  50000
    245 #define HATHZ2 10000
    246 unsigned char hatStack[HATSTACKSIZE];
    247 
    248 unsigned testHatOn = 0;
    249 unsigned nHats = 0;
    250 unsigned nHatWedges = 0;
    251 unsigned fiqReason = 0;
    252 unsigned hatCount = 0;
    253 unsigned hatCount2 = 0;
    254 
    255 static void hatTest(int testReason)
    256 {
    257 
    258 	fiqReason |= testReason;
    259 	nHats++;
    260 }
    261 
    262 static void hatWedge(int nFIQs)
    263 {
    264 
    265 	printf("Unwedging the HAT.  fiqs_happened = %d\n", nFIQs);
    266 	nHatWedges++;
    267 }
    268 #endif
    269 
    270 void
    271 startrtclock(void)
    272 {
    273 
    274 	findcpuspeed();		/* use the clock (while it's free) to
    275 				   find the CPU speed */
    276 
    277 	timer0count.lo = 0;
    278 	timer0count.hi = 0;
    279 	timer0_at_last_clockintr.lo = 0;
    280 	timer0_at_last_clockintr.hi = 0;
    281 	timer0last     = 0;
    282 
    283 	/* initialize 8253 clock */
    284 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
    285 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER % 256);
    286 	outb(IO_TIMER1 + TIMER_CNTR0, TIMER0_ROLLOVER / 256);
    287 
    288 #ifdef TESTHAT
    289 	hatCount = timer_hz_to_count(HATHZ);
    290 	hatCount2 = timer_hz_to_count(HATHZ2);
    291 	printf("HAT test on @ %d Hz = %d ticks\n", HATHZ, hatCount);
    292 #endif
    293 }
    294 
    295 int
    296 timer_hz_to_count(int timer_hz)
    297 {
    298 	u_long tval;
    299 
    300 	tval = (TIMER_FREQ * 2) / (u_long) timer_hz;
    301 	tval = (tval / 2) + (tval & 0x1);
    302 
    303 	return (int)tval;
    304 }
    305 
    306 void gettimer0count(struct count64 *);
    307 
    308 /* must be called at SPL_CLOCK or higher */
    309 void gettimer0count(struct count64 *pcount)
    310 {
    311 	unsigned current, ticks, oldlo;
    312 
    313 	/*
    314 	 * Latch the current value of the timer and then read it.
    315 	 * This guarantees an atomic reading of the time.
    316 	 */
    317 
    318 	current = gettick();
    319 
    320 	if (timer0last >= current)
    321 		ticks = timer0last - current;
    322 	else
    323 		ticks = timer0last + (TIMER0_ROLLOVER - current);
    324 
    325 	timer0last = current;
    326 
    327 	oldlo = timer0count.lo;
    328 
    329 	if (oldlo > (timer0count.lo = oldlo + ticks)) /* carry? */
    330 		timer0count.hi++;
    331 
    332 	*pcount = timer0count;
    333 }
    334 
    335 static int
    336 clockintr(void *arg)
    337 {
    338 	struct clockframe *frame = arg;		/* not strictly necessary */
    339 	extern void isa_specific_eoi(int irq);
    340 #ifdef TESTHAT
    341 	static int ticks = 0;
    342 #endif
    343 	static int hatUnwedgeCtr = 0;
    344 
    345 	gettimer0count(&timer0_at_last_clockintr);
    346 
    347 	mc146818_read(NULL, MC_REGC); /* clear the clock interrupt */
    348 
    349 	/* check to see if the high-availability timer needs to be unwedged */
    350 	if (++hatUnwedgeCtr >= (hz / HAT_MIN_FREQ)) {
    351 		hatUnwedgeCtr = 0;
    352 		hatUnwedge();
    353 	}
    354 
    355 #ifdef TESTHAT
    356 	++ticks;
    357 
    358 	if (testHatOn && ((ticks & 0x3f) == 0)) {
    359 		if (testHatOn == 1) {
    360 			hatClkAdjust(hatCount2);
    361 			testHatOn = 2;
    362 		} else {
    363 			testHatOn = 0;
    364 			hatClkOff();
    365 			printf("hat off status: %d %d %x\n", nHats,
    366 			    nHatWedges, fiqReason);
    367 		}
    368 	} else if (!testHatOn && (ticks & 0x1ff) == 0) {
    369 		printf("hat on status: %d %d %x\n",
    370 		    nHats, nHatWedges, fiqReason);
    371 		testHatOn = 1;
    372 		nHats = 0;
    373 		fiqReason = 0;
    374 		hatClkOn(hatCount, hatTest, 0xfeedface,
    375 		    hatStack + HATSTACKSIZE - sizeof(unsigned),
    376 		    hatWedge);
    377 	}
    378 #endif
    379 	hardclock(frame);
    380 	return(1);
    381 }
    382 
    383 static int
    384 gettick(void)
    385 {
    386 	u_char lo, hi;
    387 	u_int savedints;
    388 
    389 	/* Don't want someone screwing with the counter while we're here. */
    390 	savedints = disable_interrupts(I32_bit);
    391 	/* Select counter 0 and latch it. */
    392 	outb(IO_TIMER1 + TIMER_MODE, TIMER_SEL0 | TIMER_LATCH);
    393 	lo = inb(IO_TIMER1 + TIMER_CNTR0);
    394 	hi = inb(IO_TIMER1 + TIMER_CNTR0);
    395 	restore_interrupts(savedints);
    396 	return ((hi << 8) | lo);
    397 }
    398 
    399 /* modifications from i386 to shark isa version:
    400    - removed hardcoded "n -=" values that approximated the time to
    401      calculate delay ticks
    402    - made the time to calculate delay ticks almost negligible. 4 multiplies
    403      = maximum of 12 cycles = 75ns on a slow SA-110, plus a bunch of shifts;
    404      as opposed to 4 multiplies plus a bunch of divides.
    405    - removed i386 assembly language hack
    406    - put code in findcpuspeed that works even if FIRST_GUESS is orders
    407      of magnitude low
    408    - put code in delay() to use delayloop() for short delays
    409    - microtime no longer in assembly language
    410 */
    411 
    412 /*
    413  * Wait "n" microseconds.
    414  * Relies on timer 1 counting down from (TIMER_FREQ / hz) at TIMER_FREQ Hz.
    415  * Note: timer had better have been programmed before this is first used!
    416  * (Note that we use `rate generator' mode, which counts at 1:1; `square
    417  * wave' mode counts at 2:1).
    418  */
    419 void
    420 delay(unsigned n)
    421 {
    422 	int ticks, otick;
    423 	int nticks;
    424 
    425 	if (n < 100) {
    426 		/* it can take a long time (1 usec or longer) just for
    427 		   1 ISA read, so it's best not to use the timer for
    428 		   short delays */
    429 		delayloop((n * count1024usec) >> 10);
    430 		return;
    431 	}
    432 
    433 	/*
    434 	 * Read the counter first, so that the rest of the setup overhead is
    435 	 * counted.
    436 	 */
    437 	otick = gettick();
    438 
    439 	/*
    440 	 * Calculate ((n * TIMER_FREQ) / 1e6) without using floating point and
    441 	 * without any avoidable overflows.
    442 	 */
    443 	{
    444 	        /* a Musec = 2^20 usec */
    445 		int Musec = n >> 20,
    446 		    usec = n & ((1 << 20) - 1);
    447 		nticks
    448 		  = (Musec * TIMER_MUSECFREQ) +
    449 		    (usec * (TIMER_MUSECFREQ >> 20)) +
    450 		    ((usec * ((TIMER_MUSECFREQ & ((1 <<20) - 1)) >>10)) >>10) +
    451 		    ((usec * (TIMER_MUSECFREQ & ((1 << 10) - 1))) >> 20);
    452 	}
    453 
    454 	while (nticks > 0) {
    455 		ticks = gettick();
    456 		if (ticks > otick)
    457 			nticks -= TIMER0_ROLLOVER - (ticks - otick);
    458 		else
    459 			nticks -= otick - ticks;
    460 		otick = ticks;
    461 	}
    462 
    463 }
    464 
    465 void
    466 sysbeepstop(void *arg)
    467 {
    468 }
    469 
    470 void
    471 sysbeep(int pitch, int period)
    472 {
    473 }
    474 
    475 #define FIRST_GUESS   0x2000
    476 
    477 static void
    478 findcpuspeed(void)
    479 {
    480 	int ticks;
    481 	unsigned int guess = FIRST_GUESS;
    482 
    483 	while (1) { /* loop until accurate enough */
    484 		/* Put counter in count down mode */
    485 		outb(IO_TIMER1 + TIMER_MODE,
    486 		    TIMER_SEL0 | TIMER_16BIT | TIMER_RATEGEN);
    487 		outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    488 		outb(IO_TIMER1 + TIMER_CNTR0, 0xff);
    489 		delayloop(guess);
    490 
    491 		/* Read the value left in the counter */
    492 		/*
    493 		 * Formula for delaycount is:
    494 		 *  (loopcount * timer clock speed) / (counter ticks * 1000)
    495 		 */
    496 		ticks = 0xFFFF - gettick();
    497 		if (ticks == 0) ticks = 1; /* just in case */
    498 		if (ticks < (TIMER_MUSECDIV(1024))) { /* not accurate enough */
    499 			guess *= uimax(2, (TIMER_MUSECDIV(1024) / ticks));
    500 			continue;
    501 		}
    502 		count1024usec = (guess * (TIMER_MUSECDIV(1024))) / ticks;
    503 		return;
    504 	}
    505 }
    506 
    507 static void
    508 delayloop(int counts)
    509 {
    510 	while (counts--)
    511 		__insn_barrier();
    512 }
    513 
    514 void
    515 cpu_initclocks(void)
    516 {
    517         unsigned hzval;
    518 
    519 	printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
    520 
    521 	/* install RTC interrupt handler */
    522 	(void)isa_intr_establish(NULL, IRQ_RTC, IST_LEVEL, IPL_CLOCK,
    523 				 clockintr, 0);
    524 
    525 	/* set  up periodic interrupt @ hz
    526 	   this is the subset of hz values in kern_clock.c that are
    527 	   supported by the ISA RTC */
    528 	switch (hz) {
    529 	case 64:
    530 		hzval = MC_RATE_64_Hz;
    531 		break;
    532 	case 128:
    533 		hzval = MC_RATE_128_Hz;
    534 		break;
    535 	case 256:
    536 		hzval = MC_RATE_256_Hz;
    537 		break;
    538 	case 1024:
    539 		hzval = MC_RATE_1024_Hz;
    540 		break;
    541 	default:
    542 		panic("cannot configure hz = %d", hz);
    543         }
    544 
    545 	rtcinit(); /* make sure basics are done by now */
    546 
    547 	/* blast values to set up clock interrupt */
    548 	mc146818_write(NULL, MC_REGA, MC_BASE_32_KHz | hzval);
    549 	/* enable periodic interrupt */
    550 	mc146818_write(NULL, MC_REGB,
    551 		       mc146818_read(NULL, MC_REGB) | MC_REGB_PIE);
    552 
    553 	tc_init_i8253();
    554 }
    555 
    556 void
    557 rtcinit(void)
    558 {
    559 	static int first_rtcopen_ever = 1;
    560 
    561 	if (!first_rtcopen_ever)
    562 		return;
    563 	first_rtcopen_ever = 0;
    564 
    565 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
    566 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
    567 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
    568 }
    569 
    570 void
    571 setstatclockrate(int arg)
    572 {
    573 }
    574 
    575 static uint32_t
    576 i8253_get_timecount(struct timecounter *tc)
    577 {
    578 	return (TIMER0_ROLLOVER - gettick());
    579 }
    580 
    581 void
    582 tc_init_i8253(void)
    583 {
    584 	static struct timecounter i8253_tc = {
    585 		.tc_get_timecount = i8253_get_timecount,
    586 		.tc_counter_mask = TIMER0_ROLLOVER,
    587 		.tc_frequency = TIMER_FREQ,
    588 		.tc_name = "i8253",
    589 		.tc_quality = 100
    590 	};
    591 
    592 	tc_init(&i8253_tc);
    593 }
    594 
    595 /* End of clock.c */
    596