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