1 /* $NetBSD: clock.c,v 1.39 1999/11/05 19:14:56 scottr Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 */ 40 /*- 41 * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, 42 * Michael L. Finch, Bradley A. Grantham, and 43 * Lawrence A. Kesteloot 44 * All rights reserved. 45 * 46 * Redistribution and use in source and binary forms, with or without 47 * modification, are permitted provided that the following conditions 48 * are met: 49 * 1. Redistributions of source code must retain the above copyright 50 * notice, this list of conditions and the following disclaimer. 51 * 2. Redistributions in binary form must reproduce the above copyright 52 * notice, this list of conditions and the following disclaimer in the 53 * documentation and/or other materials provided with the distribution. 54 * 3. All advertising materials mentioning features or use of this software 55 * must display the following acknowledgement: 56 * This product includes software developed by the Alice Group. 57 * 4. The names of the Alice Group or any of its members may not be used 58 * to endorse or promote products derived from this software without 59 * specific prior written permission. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR 62 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 63 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 64 * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, 65 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 66 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 67 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 68 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 69 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 70 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 71 * 72 */ 73 /* 74 * 75 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 76 * 77 * @(#)clock.c 7.6 (Berkeley) 5/7/91 78 */ 79 80 #include <sys/param.h> 81 #include <sys/device.h> 82 #include <sys/kernel.h> 83 #include <sys/systm.h> 84 85 #include <machine/autoconf.h> 86 #include <machine/psl.h> 87 #include <machine/cpu.h> 88 #include <machine/limits.h> 89 90 #if defined(GPROF) && defined(PROFTIMER) 91 #include <sys/gprof.h> 92 #endif 93 94 #include <mac68k/mac68k/pram.h> 95 #include <mac68k/mac68k/clockreg.h> 96 #include <machine/viareg.h> 97 98 #ifdef DEBUG 99 int clock_debug = 0; 100 #endif 101 102 void rtclock_intr __P((void)); 103 104 #define DIFF19041970 2082844800 105 #define DIFF19701990 630720000 106 #define DIFF19702010 1261440000 107 108 /* 109 * Mac II machine-dependent clock routines. 110 */ 111 112 /* 113 * Start the real-time clock; i.e. set timer latches and boot timer. 114 * 115 * We use VIA1 timer 1. 116 */ 117 void 118 startrtclock() 119 { 120 /* 121 * BARF MF startrt clock is called twice in init_main, configure, 122 * the reason why is doced in configure 123 */ 124 /* be certain clock interrupts are off */ 125 via_reg(VIA1, vIER) = V1IF_T1; 126 127 /* set timer latch */ 128 via_reg(VIA1, vACR) |= ACR_T1LATCH; 129 130 /* set VIA timer 1 latch to 60 Hz (100 Hz) */ 131 via_reg(VIA1, vT1L) = CLK_INTL; 132 via_reg(VIA1, vT1LH) = CLK_INTH; 133 134 /* set VIA timer 1 counter started for 60(100) Hz */ 135 via_reg(VIA1, vT1C) = CLK_INTL; 136 via_reg(VIA1, vT1CH) = CLK_INTH; 137 } 138 139 void 140 enablertclock() 141 { 142 /* clear then enable clock interrupt. */ 143 via_reg(VIA1, vIFR) |= V1IF_T1; 144 via_reg(VIA1, vIER) = 0x80 | V1IF_T1; 145 } 146 147 void 148 cpu_initclocks() 149 { 150 enablertclock(); 151 } 152 153 void 154 setstatclockrate(rateinhz) 155 int rateinhz; 156 { 157 } 158 159 void 160 disablertclock() 161 { 162 /* disable clock interrupt */ 163 via_reg(VIA1, vIER) = V1IF_T1; 164 } 165 166 /* 167 * Returns number of usec since last clock tick/interrupt. 168 * 169 * Check high byte twice to prevent missing a roll-over. 170 * (race condition?) 171 */ 172 u_long 173 clkread() 174 { 175 int high, high2, low; 176 177 high = via_reg(VIA1, vT1CH); 178 low = via_reg(VIA1, vT1C); 179 180 high2 = via_reg(VIA1, vT1CH); 181 if (high != high2) 182 high = high2; 183 184 /* return count left in timer / 1.27 */ 185 /* return((CLK_INTERVAL - (high << 8) - low) / CLK_SPEED); */ 186 return ((CLK_INTERVAL - (high << 8) - low) * 10000 / 12700); 187 } 188 189 190 #ifdef PROFTIMER 191 /* 192 * Here, we have implemented code that causes VIA2's timer to count 193 * the profiling clock. Following the HP300's lead, this reduces 194 * the impact on other tasks, since locore turns off the profiling clock 195 * on context switches. If need be, the profiling clock's resolution can 196 * be cranked higher than the real-time clock's resolution, to prevent 197 * aliasing and allow higher accuracy. 198 */ 199 int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ 200 int profinthigh; 201 int profintlow; 202 int profscale = 0; /* Scale factor from sys clock to prof clock */ 203 char profon = 0; /* Is profiling clock on? */ 204 205 /* profon values - do not change, locore.s assumes these values */ 206 #define PRF_NONE 0x00 207 #define PRF_USER 0x01 208 #define PRF_KERNEL 0x80 209 210 void 211 initprofclock() 212 { 213 /* profile interval must be even divisor of system clock interval */ 214 if (profint > CLK_INTERVAL) 215 profint = CLK_INTERVAL; 216 else 217 if (CLK_INTERVAL % profint != 0) 218 /* try to intelligently fix clock interval */ 219 profint = CLK_INTERVAL / (CLK_INTERVAL / profint); 220 221 profscale = CLK_INTERVAL / profint; 222 223 profinthigh = profint >> 8; 224 profintlow = profint & 0xff; 225 } 226 227 void 228 startprofclock() 229 { 230 via_reg(VIA2, vT1L) = (profint - 1) & 0xff; 231 via_reg(VIA2, vT1LH) = (profint - 1) >> 8; 232 via_reg(VIA2, vACR) |= ACR_T1LATCH; 233 via_reg(VIA2, vT1C) = (profint - 1) & 0xff; 234 via_reg(VIA2, vT1CH) = (profint - 1) >> 8; 235 } 236 237 void 238 stopprofclock() 239 { 240 via_reg(VIA2, vT1L) = 0; 241 via_reg(VIA2, vT1LH) = 0; 242 via_reg(VIA2, vT1C) = 0; 243 via_reg(VIA2, vT1CH) = 0; 244 } 245 246 #ifdef GPROF 247 /* 248 * BARF: we should check this: 249 * 250 * profclock() is expanded in line in lev6intr() unless profiling kernel. 251 * Assumes it is called with clock interrupts blocked. 252 */ 253 void 254 profclock(pclk) 255 clockframe *pclk; 256 { 257 /* 258 * Came from user mode. 259 * If this process is being profiled record the tick. 260 */ 261 if (USERMODE(pclk->ps)) { 262 if (p->p_stats.p_prof.pr_scale) 263 addupc_task(&curproc, pclk->pc, 1); 264 } 265 /* 266 * Came from kernel (supervisor) mode. 267 * If we are profiling the kernel, record the tick. 268 */ 269 else 270 if (profiling < 2) { 271 int s = pclk->pc - s_lowpc; 272 273 if (s < s_textsize) 274 kcount[s / (HISTFRACTION * sizeof(*kcount))]++; 275 } 276 /* 277 * Kernel profiling was on but has been disabled. 278 * Mark as no longer profiling kernel and if all profiling done, 279 * disable the clock. 280 */ 281 if (profiling && (profon & PRF_KERNEL)) { 282 profon &= ~PRF_KERNEL; 283 if (profon == PRF_NONE) 284 stopprofclock(); 285 } 286 } 287 #endif 288 #endif 289 290 static u_long ugmt_2_pramt __P((u_long)); 291 static u_long pramt_2_ugmt __P((u_long)); 292 293 /* 294 * Convert GMT to Mac PRAM time, using rtc_offset 295 * GMT bias adjustment is done elsewhere. 296 */ 297 static u_long 298 ugmt_2_pramt(t) 299 u_long t; 300 { 301 /* don't know how to open a file properly. */ 302 /* assume compiled timezone is correct. */ 303 304 return (t = t + DIFF19041970 - 60 * rtc_offset); 305 } 306 307 /* 308 * Convert a Mac PRAM time value to GMT, using rtc_offset 309 * GMT bias adjustment is done elsewhere. 310 */ 311 static u_long 312 pramt_2_ugmt(t) 313 u_long t; 314 { 315 return (t = t - DIFF19041970 + 60 * rtc_offset); 316 } 317 318 /* 319 * Time from the booter. 320 */ 321 u_long macos_boottime; 322 323 /* 324 * Bias in minutes east from GMT (also from booter). 325 */ 326 long macos_gmtbias; 327 328 /* 329 * Flag for whether or not we can trust the PRAM. If we don't 330 * trust it, we don't write to it, and we take the MacOS value 331 * that is passed from the booter (which will only be a second 332 * or two off by now). 333 */ 334 int mac68k_trust_pram = 1; 335 336 /* 337 * Set global GMT time register, using a file system time base for comparison 338 * and sanity checking. 339 */ 340 void 341 inittodr(base) 342 time_t base; 343 { 344 u_long timbuf; 345 346 timbuf = pramt_2_ugmt(pram_readtime()); 347 if ((timbuf - (macos_boottime + 60 * rtc_offset)) > 10 * 60) { 348 #if DIAGNOSTIC 349 printf( 350 "PRAM time does not appear to have been read correctly.\n"); 351 printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n", 352 timbuf, macos_boottime + 60 * rtc_offset); 353 #endif 354 timbuf = macos_boottime; 355 mac68k_trust_pram = 0; 356 } 357 #ifdef DIAGNOSTIC 358 else 359 printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n", 360 timbuf, macos_boottime); 361 #endif 362 363 /* 364 * GMT bias is passed in from Booter 365 * To get GMT, *subtract* GMTBIAS from *our* time 366 * (gmtbias is in minutes, mult by 60) 367 */ 368 timbuf -= macos_gmtbias * 60; 369 370 if (base < 5 * SECYR) { 371 printf("WARNING: file system time earlier than 1975\n"); 372 printf(" -- CHECK AND RESET THE DATE!\n"); 373 base = 21 * SECYR; /* 1991 is our sane date */ 374 } 375 /* 376 * Check sanity against the year 2010. Let's hope NetBSD/mac68k 377 * doesn't run that long! 378 */ 379 if (base > 40 * SECYR) { 380 printf("WARNING: file system time later than 2010\n"); 381 printf(" -- CHECK AND RESET THE DATE!\n"); 382 base = 21 * SECYR; /* 1991 is our sane date */ 383 } 384 if (timbuf < base) { 385 printf( 386 "WARNING: Battery clock has earlier time than UNIX fs.\n"); 387 if (((u_long) base) < (40 * SECYR)) 388 timbuf = base; 389 } 390 time.tv_sec = timbuf; 391 time.tv_usec = 0; 392 } 393 394 /* 395 * Set battery backed clock to a new time, presumably after someone has 396 * changed system time. 397 */ 398 void 399 resettodr() 400 { 401 if (mac68k_trust_pram) 402 /* 403 * GMT bias is passed in from the Booter. 404 * To get *our* time, add GMTBIAS to GMT. 405 * (gmtbias is in minutes, multiply by 60). 406 */ 407 pram_settime(ugmt_2_pramt(time.tv_sec + macos_gmtbias * 60)); 408 #ifdef DEBUG 409 else if (clock_debug) 410 printf("NetBSD/mac68k does not trust itself to try and write " 411 "to the PRAM on this system.\n"); 412 #endif 413 } 414 415 416 /* 417 * The Macintosh timers decrement once every 1.2766 microseconds. 418 * MGFH2, p. 180 419 */ 420 #define CLK_RATE 12766 421 422 #define DELAY_CALIBRATE (0xffffff << 7) /* Large value for calibration */ 423 424 u_int delay_factor = DELAY_CALIBRATE; 425 volatile int delay_flag = 1; 426 427 int _delay __P((u_int)); 428 static void delay_timer1_irq __P((void *)); 429 430 static void 431 delay_timer1_irq(dummy) 432 void *dummy; 433 { 434 delay_flag = 0; 435 } 436 437 /* 438 * Calibrate delay_factor with VIA1 timer T1. 439 */ 440 void 441 mac68k_calibrate_delay() 442 { 443 u_int sum, n; 444 445 (void)spl0(); 446 447 /* Disable VIA1 timer 1 interrupts and set up service routine */ 448 via_reg(VIA1, vIER) = V1IF_T1; 449 via1_register_irq(VIA1_T1, delay_timer1_irq, NULL); 450 451 /* Set the timer for one-shot mode, then clear and enable interrupts */ 452 via_reg(VIA1, vACR) &= ~ACR_T1LATCH; 453 via_reg(VIA1, vIFR) = V1IF_T1; /* (this is needed for IIsi) */ 454 via_reg(VIA1, vIER) = 0x80 | V1IF_T1; 455 456 #ifdef DEBUG 457 if (clock_debug) 458 printf("mac68k_calibrate_delay(): entering timing loop\n"); 459 #endif 460 461 for (sum = 0, n = 8; n > 0; n--) { 462 delay_flag = 1; 463 via_reg(VIA1, vT1C) = 0; /* 1024 clock ticks */ 464 via_reg(VIA1, vT1CH) = 4; /* (approx 1.3 msec) */ 465 sum += ((delay_factor >> 7) - _delay(1)); 466 } 467 468 /* Disable timer interrupts and reset service routine */ 469 via_reg(VIA1, vIER) = V1IF_T1; 470 via1_register_irq(VIA1_T1, (void (*)(void *))rtclock_intr, NULL); 471 472 /* 473 * If this weren't integer math, the following would look 474 * a lot prettier. It should really be something like 475 * this: 476 * delay_factor = ((sum / 8) / (1024 * 1.2766)) * 128; 477 * That is, average the sum, divide by the number of usec, 478 * and multiply by a scale factor of 128. 479 * 480 * We can accomplish the same thing by simplifying and using 481 * shifts, being careful to avoid as much loss of precision 482 * as possible. (If the sum exceeds UINT_MAX/10000, we need 483 * to rearrange the calculation slightly to do this.) 484 */ 485 if (sum > (UINT_MAX / 10000)) /* This is a _fast_ machine! */ 486 delay_factor = (((sum >> 3) * 10000) / CLK_RATE) >> 3; 487 else 488 delay_factor = (((sum * 10000) >> 3) / CLK_RATE) >> 3; 489 490 /* Reset the delay_flag for normal use */ 491 delay_flag = 1; 492 493 #ifdef DEBUG 494 if (clock_debug) 495 printf("mac68k_calibrate_delay(): delay_factor calibrated\n"); 496 #endif 497 498 (void)splhigh(); 499 } 500