1 /* 2 * Copyright (c) 1988 University of Utah. 3 * Copyright (c) 1982, 1990, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * This code is derived from software contributed to Berkeley by 7 * the Systems Programming Group of the University of Utah Computer 8 * Science Department. 9 * 10 * %sccs.include.redist.c% 11 * 12 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 13 * 14 * @(#)clock.c 8.3 (Berkeley) 01/09/95 15 */ 16 17 /* 18 * HPs use the MC6840 PTM with the following arrangement: 19 * Timers 1 and 3 are externally driver from a 25Mhz source. 20 * Output from timer 3 is tied to the input of timer 2. 21 * The latter makes it possible to use timers 3 and 2 together to get 22 * a 32-bit countdown timer. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/kernel.h> 27 #include <hp/dev/hilreg.h> 28 #include <hp300/hp300/clockreg.h> 29 30 #include <machine/psl.h> 31 #include <machine/cpu.h> 32 33 #ifdef GPROF 34 #include <sys/gmon.h> 35 #endif 36 37 int clkstd[1]; 38 39 static int clkint; /* clock interval, as loaded */ 40 /* 41 * Statistics clock interval and variance, in usec. Variance must be a 42 * power of two. Since this gives us an even number, not an odd number, 43 * we discard one case and compensate. That is, a variance of 1024 would 44 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 45 * This is symmetric about the point 512, or statvar/2, and thus averages 46 * to that value (assuming uniform random numbers). 47 */ 48 static int statvar = 1024 / 4; /* {stat,prof}clock variance */ 49 static int statmin; /* statclock interval - variance/2 */ 50 static int profmin; /* profclock interval - variance/2 */ 51 static int timer3min; /* current, from above choices */ 52 static int statprev; /* previous value in stat timer */ 53 54 static int month_days[12] = { 55 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 56 }; 57 struct bbc_tm *gmt_to_bbc(); 58 u_char bbc_registers[13]; 59 u_char write_bbc_reg(), read_bbc_reg(); 60 struct hil_dev *bbcaddr = NULL; 61 62 /* 63 * Machine-dependent clock routines. 64 * 65 * A note on the real-time clock: 66 * We actually load the clock with interval-1 instead of interval. 67 * This is because the counter decrements to zero after N+1 enabled clock 68 * periods where N is the value loaded into the counter. 69 * 70 * The frequencies of the HP300 clocks must be a multiple of four 71 * microseconds (since the clock counts in 4 us units). 72 */ 73 #define COUNTS_PER_SEC (1000000 / CLK_RESOLUTION) 74 75 /* 76 * Set up the real-time and statistics clocks. Leave stathz 0 only if 77 * no alternative timer is available. 78 * 79 */ 80 cpu_initclocks() 81 { 82 register volatile struct clkreg *clk; 83 register int intvl, statint, profint, minint; 84 85 clkstd[0] = IIOV(0x5F8000); /* XXX grot */ 86 clk = (volatile struct clkreg *)clkstd[0]; 87 88 if (COUNTS_PER_SEC % hz) { 89 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 90 hz = 100; 91 } 92 /* 93 * Clock has several counters, so we can always use separate 94 * statclock. 95 */ 96 if (stathz == 0) /* XXX should be set in param.c */ 97 stathz = hz; 98 else if (COUNTS_PER_SEC % stathz) { 99 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 100 stathz = 100; 101 } 102 if (profhz == 0) /* XXX should be set in param.c */ 103 profhz = stathz * 5; 104 else if (profhz < stathz || COUNTS_PER_SEC % profhz) { 105 printf("cannot get %d Hz profclock; using %d Hz\n", 106 profhz, stathz); 107 profhz = stathz; 108 } 109 110 intvl = COUNTS_PER_SEC / hz; 111 statint = COUNTS_PER_SEC / stathz; 112 profint = COUNTS_PER_SEC / profhz; 113 minint = statint / 2 + 100; 114 while (statvar > minint) 115 statvar >>= 1; 116 117 tick = intvl * CLK_RESOLUTION; 118 119 /* adjust interval counts, per note above */ 120 intvl--; 121 statint--; 122 profint--; 123 124 /* calculate base reload values */ 125 clkint = intvl; 126 statmin = statint - (statvar >> 1); 127 profmin = profint - (statvar >> 1); 128 timer3min = statmin; 129 statprev = statint; 130 131 /* finally, load hardware */ 132 clk->clk_cr2 = CLK_CR1; 133 clk->clk_cr1 = CLK_RESET; 134 asm volatile(" movpw %0,%1@(5)" : : "d" (intvl), "a" (clk)); 135 asm volatile(" movpw %0,%1@(9)" : : "d" (0), "a" (clk)); 136 asm volatile(" movpw %0,%1@(13)" : : "d" (statint), "a" (clk)); 137 clk->clk_cr2 = CLK_CR1; 138 clk->clk_cr1 = CLK_IENAB; 139 clk->clk_cr2 = CLK_CR3; 140 clk->clk_cr3 = CLK_IENAB; 141 } 142 143 /* 144 * We assume newhz is either stathz or profhz, and that neither will 145 * change after being set up above. Could recalculate intervals here 146 * but that would be a drag. 147 */ 148 void 149 setstatclockrate(newhz) 150 int newhz; 151 { 152 153 if (newhz == stathz) 154 timer3min = statmin; 155 else 156 timer3min = profmin; 157 } 158 159 /* 160 * Statistics/profiling clock interrupt. Compute a new interval. 161 * Interrupt has already been cleared. 162 * 163 * DO THIS INLINE IN locore.s? 164 */ 165 void 166 statintr(fp) 167 struct clockframe *fp; 168 { 169 register volatile struct clkreg *clk; 170 register int newint, r, var; 171 172 clk = (volatile struct clkreg *)clkstd[0]; 173 var = statvar; 174 do { 175 r = random() & (var - 1); 176 } while (r == 0); 177 newint = timer3min + r; 178 179 /* 180 * The timer was automatically reloaded with the previous latch 181 * value at the time of the interrupt. Compensate now for the 182 * amount of time that has run off since then (minimum of 2-12 183 * timer ticks depending on CPU type) plus one tick roundoff. 184 * This should keep us closer to the mean. 185 */ 186 asm volatile(" clrl %0; movpw %1@(13),%0" : "=d" (r) : "a" (clk)); 187 newint -= (statprev - r + 1); 188 189 asm volatile(" movpw %0,%1@(13)" : : "d" (newint), "a" (clk)); 190 statprev = newint; 191 statclock(fp); 192 } 193 194 /* 195 * Return the best possible estimate of the current time. 196 */ 197 void 198 microtime(tvp) 199 register struct timeval *tvp; 200 { 201 register volatile struct clkreg *clk; 202 register int s, u, t, u2, s2; 203 204 /* 205 * Read registers from slowest-changing to fastest-changing, 206 * then re-read out to slowest. If the values read before the 207 * innermost match those read after, the innermost value is 208 * consistent with the outer values. If not, it may not be and 209 * we must retry. Typically this loop runs only once; occasionally 210 * it runs twice, and only rarely does it run longer. 211 * 212 * (Using this loop avoids the need to block interrupts.) 213 */ 214 clk = (volatile struct clkreg *)clkstd[0]; 215 do { 216 s = time.tv_sec; 217 u = time.tv_usec; 218 asm volatile (" clrl %0; movpw %1@(5),%0" 219 : "=d" (t) : "a" (clk)); 220 u2 = time.tv_usec; 221 s2 = time.tv_sec; 222 } while (u != u2 || s != s2); 223 224 u += (clkint - t) * CLK_RESOLUTION; 225 if (u >= 1000000) { /* normalize */ 226 s++; 227 u -= 1000000; 228 } 229 tvp->tv_sec = s; 230 tvp->tv_usec = u; 231 } 232 233 /* 234 * Initialize the time of day register, based on the time base which is, e.g. 235 * from a filesystem. 236 */ 237 inittodr(base) 238 time_t base; 239 { 240 u_long timbuf = base; /* assume no battery clock exists */ 241 static int bbcinited = 0; 242 243 /* XXX */ 244 if (!bbcinited) { 245 if (badbaddr(&BBCADDR->hil_stat)) 246 printf("WARNING: no battery clock\n"); 247 else 248 bbcaddr = BBCADDR; 249 bbcinited = 1; 250 } 251 252 /* 253 * bbc_to_gmt converts and stores the gmt in timbuf. 254 * If an error is detected in bbc_to_gmt, or if the filesystem 255 * time is more recent than the gmt time in the clock, 256 * then use the filesystem time and warn the user. 257 */ 258 if (!bbc_to_gmt(&timbuf) || timbuf < base) { 259 printf("WARNING: bad date in battery clock\n"); 260 timbuf = base; 261 } 262 if (base < 5*SECYR) { 263 printf("WARNING: preposterous time in file system"); 264 timbuf = 6*SECYR + 186*SECDAY + SECDAY/2; 265 printf(" -- CHECK AND RESET THE DATE!\n"); 266 } 267 268 /* Battery clock does not store usec's, so forget about it. */ 269 time.tv_sec = timbuf; 270 } 271 272 /* 273 * Restore the time of day hardware after a time change. 274 */ 275 resettodr() 276 { 277 register int i; 278 register struct bbc_tm *tmptr; 279 280 tmptr = gmt_to_bbc(time.tv_sec); 281 282 decimal_to_bbc(0, 1, tmptr->tm_sec); 283 decimal_to_bbc(2, 3, tmptr->tm_min); 284 decimal_to_bbc(4, 5, tmptr->tm_hour); 285 decimal_to_bbc(7, 8, tmptr->tm_mday); 286 decimal_to_bbc(9, 10, tmptr->tm_mon); 287 decimal_to_bbc(11, 12, tmptr->tm_year); 288 289 /* Some bogusness to deal with seemingly broken hardware. Nonsense */ 290 bbc_registers[5] = ((tmptr->tm_hour / 10) & 0x03) + 8; 291 292 write_bbc_reg(15, 13); /* reset prescalar */ 293 294 for (i = 0; i <= NUM_BBC_REGS; i++) 295 if (bbc_registers[i] != write_bbc_reg(i, bbc_registers[i])) { 296 printf("Cannot set battery backed clock\n"); 297 break; 298 } 299 } 300 301 struct bbc_tm * 302 gmt_to_bbc(tim) 303 long tim; 304 { 305 register int i; 306 register long hms, day; 307 static struct bbc_tm rt; 308 309 day = tim / SECDAY; 310 hms = tim % SECDAY; 311 312 /* Hours, minutes, seconds are easy */ 313 rt.tm_hour = hms / 3600; 314 rt.tm_min = (hms % 3600) / 60; 315 rt.tm_sec = (hms % 3600) % 60; 316 317 /* Number of years in days */ 318 for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 319 day -= days_in_year(i); 320 rt.tm_year = i; 321 322 /* Number of months in days left */ 323 if (leapyear(rt.tm_year)) 324 days_in_month(FEBRUARY) = 29; 325 for (i = 1; day >= days_in_month(i); i++) 326 day -= days_in_month(i); 327 days_in_month(FEBRUARY) = 28; 328 rt.tm_mon = i; 329 330 /* Days are what is left over (+1) from all that. */ 331 rt.tm_mday = day + 1; 332 333 return(&rt); 334 } 335 336 bbc_to_gmt(timbuf) 337 u_long *timbuf; 338 { 339 register int i; 340 register u_long tmp; 341 int year, month, day, hour, min, sec; 342 343 read_bbc(); 344 345 sec = bbc_to_decimal(1, 0); 346 min = bbc_to_decimal(3, 2); 347 348 /* 349 * Hours are different for some reason. Makes no sense really. 350 */ 351 hour = ((bbc_registers[5] & 0x03) * 10) + bbc_registers[4]; 352 day = bbc_to_decimal(8, 7); 353 month = bbc_to_decimal(10, 9); 354 year = bbc_to_decimal(12, 11) + 1900; 355 356 range_test(hour, 0, 23); 357 range_test(day, 1, 31); 358 range_test(month, 1, 12); 359 range_test(year, STARTOFTIME, 2000); 360 361 tmp = 0; 362 363 for (i = STARTOFTIME; i < year; i++) 364 tmp += days_in_year(i); 365 if (leapyear(year) && month > FEBRUARY) 366 tmp++; 367 368 for (i = 1; i < month; i++) 369 tmp += days_in_month(i); 370 371 tmp += (day - 1); 372 tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 373 374 *timbuf = tmp; 375 return(1); 376 } 377 378 read_bbc() 379 { 380 register int i, read_okay; 381 382 read_okay = 0; 383 while (!read_okay) { 384 read_okay = 1; 385 for (i = 0; i <= NUM_BBC_REGS; i++) 386 bbc_registers[i] = read_bbc_reg(i); 387 for (i = 0; i <= NUM_BBC_REGS; i++) 388 if (bbc_registers[i] != read_bbc_reg(i)) 389 read_okay = 0; 390 } 391 } 392 393 u_char 394 read_bbc_reg(reg) 395 int reg; 396 { 397 u_char data = reg; 398 399 if (bbcaddr) { 400 send_hil_cmd(bbcaddr, BBC_SET_REG, &data, 1, NULL); 401 send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &data); 402 } 403 return(data); 404 } 405 406 u_char 407 write_bbc_reg(reg, data) 408 int reg; 409 u_int data; 410 { 411 u_char tmp; 412 413 tmp = (u_char) ((data << HIL_SSHIFT) | reg); 414 415 if (bbcaddr) { 416 send_hil_cmd(bbcaddr, BBC_SET_REG, &tmp, 1, NULL); 417 send_hil_cmd(bbcaddr, BBC_WRITE_REG, NULL, 0, NULL); 418 send_hil_cmd(bbcaddr, BBC_READ_REG, NULL, 0, &tmp); 419 } 420 return(tmp); 421 } 422