/* $OpenBSD: clock.c,v 1.24 2007/07/14 19:06:48 miod Exp $ */ /* $NetBSD: clock.c,v 1.39 1999/11/05 19:14:56 scottr Exp $ */ /* * Copyright (c) 1988 University of Utah. * Copyright (c) 1982, 1990 The Regents of the University of California. * All rights reserved. * * This code is derived from software contributed to Berkeley by * the Systems Programming Group of the University of Utah Computer * Science Department. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /*- * Copyright (C) 1993 Allen K. Briggs, Chris P. Caputo, * Michael L. Finch, Bradley A. Grantham, and * Lawrence A. Kesteloot * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Alice Group. * 4. The names of the Alice Group or any of its members may not be used * to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ /* * * from: Utah $Hdr: clock.c 1.18 91/01/21$ * * @(#)clock.c 7.6 (Berkeley) 5/7/91 */ /* * Mac II machine-dependent clock routines. */ #include #include #include #include #include #include #include #include #include #include #include #ifdef DEBUG int clock_debug = 0; #endif int rtclock_intr(void *); u_int clk_interval; u_int8_t clk_inth, clk_intl; #define DIFF19041970 2082844800 /* * The Macintosh timers decrement once every 1.2766 microseconds. * MGFH2, p. 180 */ #define CLK_RATE 12766 /* * Start the real-time clock; i.e. set timer latches and boot timer. * * We use VIA1 timer 1. */ void startrtclock() { #ifndef HZ /* * By default, if HZ is not specified, use 60 Hz, unless we are * using A/UX style interrupts. We then need to readjust values * based on a 100Hz value in param.c. */ if (mac68k_machine.aux_interrupts == 0) { #define HZ_60 60 hz = HZ_60; tick = 1000000 / HZ_60; tickadj = 240000 / (60 * HZ_60);/* can adjust 240ms in 60s */ } #endif /* * Calculate clocks needed to hit hz ticks/sec. * * The VIA clock speed is 1.2766us, so the timer value needed is: * * 1 1,000,000us 1 * CLK_INTERVAL = -------- * ----------- * ------ e 1.2766us 1s hz * * While it may be tempting to simplify the following further, * we can run into integer overflow problems. * Also note: do *not* define HZ to be less than 12; overflow * will occur, yielding invalid results. */ clk_interval = ((100000000UL / hz) * 100) / 12766; clk_inth = ((clk_interval >> 8) & 0xff); clk_intl = (clk_interval & 0xff); /* be certain clock interrupts are off */ via_reg(VIA1, vIER) = V1IF_T1; /* set timer latch */ via_reg(VIA1, vACR) |= ACR_T1LATCH; /* set VIA timer 1 latch to ``hz'' Hz */ via_reg(VIA1, vT1L) = clk_intl; via_reg(VIA1, vT1LH) = clk_inth; /* set VIA timer 1 counter started for ``hz'' Hz */ via_reg(VIA1, vT1C) = clk_intl; via_reg(VIA1, vT1CH) = clk_inth; } void cpu_initclocks() { tickfix = 1000000 - (hz * tick); if (tickfix != 0) { int ftp; ftp = min(ffs(tickfix), ffs(hz)); tickfix >>= (ftp - 1); tickfixinterval = hz >> (ftp - 1); } /* clear then enable clock interrupt. */ via_reg(VIA1, vIFR) |= V1IF_T1; via_reg(VIA1, vIER) = 0x80 | V1IF_T1; } void setstatclockrate(rateinhz) int rateinhz; { } /* * Returns number of usec since last clock tick/interrupt. * * Check high byte twice to prevent missing a roll-over. * (race condition?) */ u_long clkread() { int high, high2, low; high = via_reg(VIA1, vT1CH); low = via_reg(VIA1, vT1C); high2 = via_reg(VIA1, vT1CH); if (high != high2) high = high2; /* return count left in timer / 1.27 */ return ((clk_interval - (high << 8) - low) * 10000 / CLK_RATE); } static u_long ugmt_2_pramt(u_long); static u_long pramt_2_ugmt(u_long); /* * Convert GMT to Mac PRAM time, using rtc_offset * GMT bias adjustment is done elsewhere. */ static u_long ugmt_2_pramt(t) u_long t; { /* don't know how to open a file properly. */ /* assume compiled timezone is correct. */ return (t + DIFF19041970 - 60 * tz.tz_minuteswest); } /* * Convert a Mac PRAM time value to GMT, using rtc_offset * GMT bias adjustment is done elsewhere. */ static u_long pramt_2_ugmt(t) u_long t; { return (t - DIFF19041970 + 60 * tz.tz_minuteswest); } /* * Time from the booter. */ u_long macos_boottime; /* * Bias in minutes east from GMT (also from booter). */ long macos_gmtbias; /* * Flag for whether or not we can trust the PRAM. If we don't * trust it, we don't write to it, and we take the MacOS value * that is passed from the booter (which will only be a second * or two off by now). */ int mac68k_trust_pram = 1; /* * Set global GMT time register, using a file system time base for comparison * and sanity checking. */ void inittodr(base) time_t base; { u_long timbuf; timbuf = pram_readtime(); if (timbuf == 0) { /* We don't know how to access PRAM on this hardware. */ timbuf = macos_boottime; mac68k_trust_pram = 0; } else { timbuf = pramt_2_ugmt(pram_readtime()); if ((timbuf - (macos_boottime + 60 * tz.tz_minuteswest)) > 10 * 60) { #ifdef DIAGNOSTIC printf("PRAM time does not appear" " to have been read correctly.\n"); printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n", timbuf, macos_boottime + 60 * tz.tz_minuteswest); #endif timbuf = macos_boottime; mac68k_trust_pram = 0; } #ifdef DEBUG else printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n", timbuf, macos_boottime); #endif } /* * GMT bias is passed in from Booter * To get GMT, *subtract* GMTBIAS from *our* time * (gmtbias is in minutes, mult by 60) */ timbuf -= macos_gmtbias * 60; if (base < 5 * SECYR) { printf("WARNING: file system time earlier than 1975\n"); printf(" -- CHECK AND RESET THE DATE!\n"); base = 36 * SECYR; /* Last update here in 2006... */ } if (timbuf < base) { printf( "WARNING: Battery clock has earlier time than UNIX fs.\n"); timbuf = base; } time.tv_sec = timbuf; time.tv_usec = 0; } /* * Set battery backed clock to a new time, presumably after someone has * changed system time. */ void resettodr() { if (mac68k_trust_pram) /* * GMT bias is passed in from the Booter. * To get *our* time, add GMTBIAS to GMT. * (gmtbias is in minutes, multiply by 60). */ pram_settime(ugmt_2_pramt(time.tv_sec + macos_gmtbias * 60)); } #define DELAY_CALIBRATE (0xffffff << 7) /* Large value for calibration */ u_int delay_factor = DELAY_CALIBRATE; volatile int delay_flag = 1; int _delay(u_int); static int delay_timer1_irq(void *); static int delay_timer1_irq(dummy) void *dummy; { delay_flag = 0; return (1); } /* * Calibrate delay_factor with VIA1 timer T1. */ void mac68k_calibrate_delay() { u_int sum, n; /* Disable VIA1 timer 1 interrupts and set up service routine */ via_reg(VIA1, vIER) = V1IF_T1; via1_register_irq(VIA1_T1, delay_timer1_irq, NULL, NULL); /* Set the timer for one-shot mode, then clear and enable interrupts */ via_reg(VIA1, vACR) &= ~ACR_T1LATCH; via_reg(VIA1, vIFR) = V1IF_T1; /* (this is needed for IIsi) */ via_reg(VIA1, vIER) = 0x80 | V1IF_T1; #ifdef DEBUG if (clock_debug) printf("mac68k_calibrate_delay(): entering timing loop\n"); #endif (void)_spl(IPLTOPSL(mac68k_machine.via1_ipl) - 1); for (sum = 0, n = 8; n > 0; n--) { delay_flag = 1; via_reg(VIA1, vT1C) = 0; /* 1024 clock ticks */ via_reg(VIA1, vT1CH) = 4; /* (approx 1.3 msec) */ sum += ((delay_factor >> 7) - _delay(1)); } (void)splhigh(); /* Disable timer interrupts and reset service routine */ via_reg(VIA1, vIER) = V1IF_T1; via1_register_irq(VIA1_T1, rtclock_intr, NULL, NULL); /* * If this weren't integer math, the following would look * a lot prettier. It should really be something like * this: * delay_factor = ((sum / 8) / (1024 * 1.2766)) * 128; * That is, average the sum, divide by the number of usec, * and multiply by a scale factor of 128. * * We can accomplish the same thing by simplifying and using * shifts, being careful to avoid as much loss of precision * as possible. (If the sum exceeds UINT_MAX/10000, we need * to rearrange the calculation slightly to do this.) */ if (sum > (UINT_MAX / 10000)) /* This is a _fast_ machine! */ delay_factor = (((sum >> 3) * 10000) / CLK_RATE) >> 3; else delay_factor = (((sum * 10000) >> 3) / CLK_RATE) >> 3; /* Reset the delay_flag for normal use */ delay_flag = 1; #ifdef DEBUG if (clock_debug) printf("mac68k_calibrate_delay(): delay_factor calibrated\n"); #endif }