1 /* $NetBSD: clock.c,v 1.18 2018/09/03 16:29:27 riastradh 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.18 2018/09/03 16:29:27 riastradh 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 void hatTest(int testReason) 256 { 257 258 fiqReason |= testReason; 259 nHats++; 260 } 261 262 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 negligable. 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