1 /* $NetBSD: clock.c,v 1.6 2003/01/18 06:09:54 thorpej Exp $ */ 2 /* 3 * Copyright (c) 1998 Darrin B. Jewell 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. All advertising materials mentioning features or use of this software 15 * must display the following acknowledgement: 16 * This product includes software developed by Darrin B. Jewell 17 * 4. The name of the author may not be used to endorse or promote products 18 * derived from this software without specific prior written permission 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/kernel.h> 36 #include <sys/tty.h> 37 38 #include <machine/psl.h> 39 #include <machine/bus.h> 40 #include <machine/cpu.h> 41 42 #include <next68k/dev/clockreg.h> 43 #include <next68k/dev/intiovar.h> 44 45 #include <next68k/next68k/rtc.h> 46 #include <next68k/next68k/isr.h> 47 48 /* @@@ This is pretty bogus and will need fixing once 49 * things are working better. 50 * -- jewell@mit.edu 51 */ 52 53 /* 54 * Note that the value of delay_divisor is roughly 55 * 2048 / cpuspeed (where cpuspeed is in MHz) on 68020 56 * and 68030 systems. See clock.c for the delay 57 * calibration algorithm. 58 */ 59 int cpuspeed; /* relative cpu speed; XXX skewed on 68040 */ 60 int delay_divisor = 2048/25; /* delay constant */ 61 62 /* 63 * Calibrate the delay constant. 64 */ 65 void 66 next68k_calibrate_delay() 67 { 68 extern int delay_divisor; 69 70 /* @@@ write this once we know how to read 71 * a real time clock 72 */ 73 74 /* 75 * Sanity check the delay_divisor value. If we totally lost, 76 * assume a 25MHz CPU; 77 */ 78 if (delay_divisor == 0) 79 delay_divisor = 2048 / 25; 80 81 /* Calculate CPU speed. */ 82 cpuspeed = 2048 / delay_divisor; 83 } 84 85 #define SECDAY (24 * 60 * 60) 86 #define SECYR (SECDAY * 365) 87 88 /* 89 * Set up the system's time, given a `reasonable' time value. 90 */ 91 void 92 inittodr(base) 93 time_t base; 94 { 95 int badbase = 0; 96 97 if (base < 5*SECYR) { 98 printf("WARNING: preposterous time in file system"); 99 base = 6*SECYR + 186*SECDAY + SECDAY/2; 100 badbase = 1; 101 } 102 103 if ((time.tv_sec = getsecs()) == 0) { 104 printf("WARNING: bad date in battery clock"); 105 /* 106 * Believe the time in the file system for lack of 107 * anything better, resetting the clock. 108 */ 109 time.tv_sec = base; 110 if (!badbase) 111 resettodr(); 112 } else { 113 int deltat = time.tv_sec - base; 114 115 if (deltat < 0) 116 deltat = -deltat; 117 if (deltat < 2 * SECDAY) 118 return; 119 printf("WARNING: clock %s %d days\n", 120 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); 121 } 122 } 123 124 void 125 resettodr() 126 { 127 setsecs(time.tv_sec); 128 } 129 130 int clock_intr __P((void *)); 131 132 int 133 clock_intr(arg) 134 void *arg; 135 { 136 volatile struct timer_reg *timer; 137 int whilecount = 0; 138 139 if (!INTR_OCCURRED(NEXT_I_TIMER)) { 140 return(0); 141 } 142 143 do { 144 static int in_hardclock = 0; 145 int s; 146 147 timer = (volatile struct timer_reg *)IIOV(NEXT_P_TIMER); 148 timer->csr |= TIMER_REG_UPDATE; 149 150 if (! in_hardclock) { 151 in_hardclock = 1; 152 s = splclock (); 153 hardclock(arg); 154 splx(s); 155 in_hardclock = 0; 156 } 157 if (whilecount++ > 10) 158 panic ("whilecount"); 159 } while (INTR_OCCURRED(NEXT_I_TIMER)); 160 return(1); 161 } 162 163 /* 164 * Set up the real-time and statistics clocks. Leave stathz 0 only 165 * if no alternative timer is available. 166 * 167 * The frequencies of these clocks must be an even number of microseconds. 168 */ 169 void 170 cpu_initclocks() 171 { 172 int s, cnt; 173 volatile struct timer_reg *timer; 174 175 rtc_init(); 176 hz = 100; 177 s = splclock(); 178 timer = (volatile struct timer_reg *)IIOV(NEXT_P_TIMER); 179 cnt = 1000000/hz; /* usec timer */ 180 timer->csr = 0; 181 timer->msb = (cnt >> 8); 182 timer->lsb = cnt; 183 timer->csr = TIMER_REG_ENABLE|TIMER_REG_UPDATE; 184 isrlink_autovec(clock_intr, NULL, NEXT_I_IPL(NEXT_I_TIMER), 0, NULL); 185 INTR_ENABLE(NEXT_I_TIMER); 186 splx(s); 187 } 188 189 190 void 191 setstatclockrate(newhz) 192 int newhz; 193 { 194 195 /* XXX should we do something here? XXX */ 196 } 197 198 /* @@@ update this to use the usec timer 199 * Darrin B Jewell <jewell@mit.edu> Sun Feb 8 05:01:02 1998 200 */ 201 202 203 /* 204 * Return the best possible estimate of the time in the timeval 205 * to which tvp points. We do this by returning the current time 206 * plus the amount of time since the last clock interrupt (clock.c:clkread). 207 * 208 * Check that this time is no less than any previously-reported time, 209 * which could happen around the time of a clock adjustment. Just for fun, 210 * we guarantee that the time will be greater than the value obtained by a 211 * previous call. 212 */ 213 214 void 215 microtime(tvp) 216 register struct timeval *tvp; 217 { 218 int s = splhigh(); 219 static struct timeval lasttime; 220 221 *tvp = time; 222 tvp->tv_usec++; 223 while (tvp->tv_usec >= 1000000) { 224 tvp->tv_sec++; 225 tvp->tv_usec -= 1000000; 226 } 227 if (tvp->tv_sec == lasttime.tv_sec && 228 tvp->tv_usec <= lasttime.tv_usec && 229 (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { 230 tvp->tv_sec++; 231 tvp->tv_usec -= 1000000; 232 } 233 lasttime = *tvp; 234 splx(s); 235 } 236