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