1 /* $NetBSD: clock.c,v 1.42 2008/11/04 16:43:47 abs Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1990 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * the Systems Programming Group of the University of Utah Computer 9 * Science Department. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 36 * 37 * @(#)clock.c 7.6 (Berkeley) 5/7/91 38 */ 39 /* 40 * Copyright (c) 1988 University of Utah. 41 * 42 * This code is derived from software contributed to Berkeley by 43 * the Systems Programming Group of the University of Utah Computer 44 * Science Department. 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 University of 57 * California, Berkeley and its contributors. 58 * 4. Neither the name of the University nor the names of its contributors 59 * may be used to endorse or promote products derived from this software 60 * without specific prior written permission. 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 63 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 64 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 65 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 66 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 67 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 68 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 69 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 70 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 * 74 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 75 * 76 * @(#)clock.c 7.6 (Berkeley) 5/7/91 77 */ 78 79 #include <sys/cdefs.h> 80 __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.42 2008/11/04 16:43:47 abs Exp $"); 81 82 #include <sys/param.h> 83 #include <sys/kernel.h> 84 #include <sys/systm.h> 85 #include <sys/device.h> 86 #include <sys/uio.h> 87 #include <sys/conf.h> 88 #include <sys/proc.h> 89 #include <sys/event.h> 90 #include <sys/timetc.h> 91 92 #include <dev/clock_subr.h> 93 94 #include <machine/psl.h> 95 #include <machine/cpu.h> 96 #include <machine/iomap.h> 97 #include <machine/mfp.h> 98 #include <atari/dev/clockreg.h> 99 #include <atari/atari/device.h> 100 101 #if defined(GPROF) && defined(PROFTIMER) 102 #include <machine/profile.h> 103 #endif 104 105 static int atari_rtc_get(todr_chip_handle_t, struct clock_ymdhms *); 106 static int atari_rtc_set(todr_chip_handle_t, struct clock_ymdhms *); 107 108 /* 109 * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider 110 * of 200. Therefore the timer runs at an effective rate of: 111 * 2457600/200 = 12288Hz. 112 */ 113 #define CLOCK_HZ 12288 114 115 static u_int clk_getcounter(struct timecounter *); 116 117 static struct timecounter clk_timecounter = { 118 clk_getcounter, /* get_timecount */ 119 0, /* no poll_pps */ 120 ~0u, /* counter_mask */ 121 CLOCK_HZ, /* frequency */ 122 "clock", /* name, overriden later */ 123 100, /* quality */ 124 NULL, /* prev */ 125 NULL, /* next */ 126 }; 127 128 /* 129 * Machine-dependent clock routines. 130 * 131 * Inittodr initializes the time of day hardware which provides 132 * date functions. 133 * 134 * Resettodr restores the time of day hardware after a time change. 135 */ 136 137 struct clock_softc { 138 struct device sc_dev; 139 int sc_flags; 140 }; 141 142 /* 143 * 'sc_flags' state info. Only used by the rtc-device functions. 144 */ 145 #define RTC_OPEN 1 146 147 dev_type_open(rtcopen); 148 dev_type_close(rtcclose); 149 dev_type_read(rtcread); 150 dev_type_write(rtcwrite); 151 152 static void clockattach __P((struct device *, struct device *, void *)); 153 static int clockmatch __P((struct device *, struct cfdata *, void *)); 154 155 CFATTACH_DECL(clock, sizeof(struct clock_softc), 156 clockmatch, clockattach, NULL, NULL); 157 158 extern struct cfdriver clock_cd; 159 160 const struct cdevsw rtc_cdevsw = { 161 rtcopen, rtcclose, rtcread, rtcwrite, noioctl, 162 nostop, notty, nopoll, nommap, nokqfilter, 163 }; 164 165 void statintr __P((struct clockframe)); 166 167 static int twodigits __P((char *, int)); 168 169 static int divisor; /* Systemclock divisor */ 170 171 /* 172 * Statistics and profile clock intervals and variances. Variance must 173 * be a power of 2. Since this gives us an even number, not an odd number, 174 * we discard one case and compensate. That is, a variance of 64 would 175 * give us offsets in [0..63]. Instead, we take offsets in [1..63]. 176 * This is symmetric around the point 32, or statvar/2, and thus averages 177 * to that value (assuming uniform random numbers). 178 */ 179 #ifdef STATCLOCK 180 static int statvar = 32; /* {stat,prof}clock variance */ 181 static int statmin; /* statclock divisor - variance/2 */ 182 static int profmin; /* profclock divisor - variance/2 */ 183 static int clk2min; /* current, from above choices */ 184 #endif 185 186 int 187 clockmatch(pdp, cfp, auxp) 188 struct device *pdp; 189 struct cfdata *cfp; 190 void *auxp; 191 { 192 if (!atari_realconfig) { 193 /* 194 * Initialize Timer-B in the ST-MFP. This timer is used by 195 * the 'delay' function below. This timer is setup to be 196 * continueously counting from 255 back to zero at a 197 * frequency of 614400Hz. We do this *early* in the 198 * initialisation process. 199 */ 200 MFP->mf_tbcr = 0; /* Stop timer */ 201 MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */ 202 MFP->mf_tbdr = 0; 203 MFP->mf_tbcr = T_Q004; /* Start timer */ 204 205 return 0; 206 } 207 if(!strcmp("clock", auxp)) 208 return(1); 209 return(0); 210 } 211 212 /* 213 * Start the real-time clock. 214 */ 215 void clockattach(pdp, dp, auxp) 216 struct device *pdp, *dp; 217 void *auxp; 218 { 219 struct clock_softc *sc = (void *)dp; 220 static struct todr_chip_handle tch; 221 222 tch.todr_gettime_ymdhms = atari_rtc_get; 223 tch.todr_settime_ymdhms = atari_rtc_set; 224 tch.todr_setwen = NULL; 225 226 todr_attach(&tch); 227 228 sc->sc_flags = 0; 229 230 /* 231 * Initialize Timer-A in the ST-MFP. We use a divisor of 200. 232 * The MFP clock runs at 2457600Hz. Therefore the timer runs 233 * at an effective rate of: 2457600/200 = 12288Hz. The 234 * following expression works for 48, 64 or 96 hz. 235 */ 236 divisor = CLOCK_HZ/hz; 237 MFP->mf_tacr = 0; /* Stop timer */ 238 MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ 239 MFP->mf_tadr = divisor; /* Set divisor */ 240 241 clk_timecounter.tc_frequency = CLOCK_HZ; 242 243 if (hz != 48 && hz != 64 && hz != 96) { /* XXX */ 244 printf (": illegal value %d for systemclock, reset to %d\n\t", 245 hz, 64); 246 hz = 64; 247 } 248 printf(": system hz %d timer-A divisor 200/%d\n", hz, divisor); 249 tc_init(&clk_timecounter); 250 251 #ifdef STATCLOCK 252 if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz)) 253 stathz = hz; 254 if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz)) 255 profhz = hz << 1; 256 257 MFP->mf_tcdcr &= 0x7; /* Stop timer */ 258 MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */ 259 MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */ 260 261 statmin = (CLOCK_HZ/stathz) - (statvar >> 1); 262 profmin = (CLOCK_HZ/profhz) - (statvar >> 1); 263 clk2min = statmin; 264 #endif /* STATCLOCK */ 265 266 } 267 268 void cpu_initclocks() 269 { 270 MFP->mf_tacr = T_Q200; /* Start timer */ 271 MFP->mf_ipra = (u_int8_t)~IA_TIMA;/* Clear pending interrupts */ 272 MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ 273 MFP->mf_imra |= IA_TIMA; /* ..... */ 274 275 #ifdef STATCLOCK 276 MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */ 277 MFP->mf_iprb = (u_int8_t)~IB_TIMC;/* Clear pending interrupts */ 278 MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */ 279 MFP->mf_imrb |= IB_TIMC; /* ..... */ 280 #endif /* STATCLOCK */ 281 } 282 283 void 284 setstatclockrate(newhz) 285 int newhz; 286 { 287 #ifdef STATCLOCK 288 if (newhz == stathz) 289 clk2min = statmin; 290 else clk2min = profmin; 291 #endif /* STATCLOCK */ 292 } 293 294 #ifdef STATCLOCK 295 void 296 statintr(frame) 297 struct clockframe frame; 298 { 299 register int var, r; 300 301 var = statvar - 1; 302 do { 303 r = random() & var; 304 } while(r == 0); 305 306 /* 307 * Note that we are always lagging behind as the new divisor 308 * value will not be loaded until the next interrupt. This 309 * shouldn't disturb the median frequency (I think ;-) ) as 310 * only the value used when switching frequencies is used 311 * twice. This shouldn't happen very often. 312 */ 313 MFP->mf_tcdr = clk2min + r; 314 315 statclock(&frame); 316 } 317 #endif /* STATCLOCK */ 318 319 static u_int 320 clk_getcounter(struct timecounter *tc) 321 { 322 u_int delta; 323 u_char ipra, tadr; 324 int s, cur_hardclock; 325 326 s = splhigh(); 327 ipra = MFP->mf_ipra; 328 tadr = MFP->mf_tadr; 329 delta = divisor - tadr; 330 331 if (ipra & IA_TIMA) 332 delta += divisor; 333 cur_hardclock = hardclock_ticks; 334 splx(s); 335 336 return (divisor - tadr) + divisor * cur_hardclock; 337 } 338 339 #define TIMB_FREQ 614400 340 #define TIMB_LIMIT 256 341 342 /* 343 * Wait "n" microseconds. 344 * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz. 345 * Note: timer had better have been programmed before this is first used! 346 */ 347 void 348 delay(unsigned int n) 349 { 350 int ticks, otick, remaining; 351 352 /* 353 * Read the counter first, so that the rest of the setup overhead is 354 * counted. 355 */ 356 otick = MFP->mf_tbdr; 357 358 if (n <= UINT_MAX / TIMB_FREQ) { 359 /* 360 * For unsigned arithmetic, division can be replaced with 361 * multiplication with the inverse and a shift. 362 */ 363 remaining = n * TIMB_FREQ / 1000000; 364 } else { 365 /* This is a very long delay. 366 * Being slow here doesn't matter. 367 */ 368 remaining = (unsigned long long) n * TIMB_FREQ / 1000000; 369 } 370 371 while(remaining > 0) { 372 ticks = MFP->mf_tbdr; 373 if(ticks > otick) 374 remaining -= TIMB_LIMIT - (ticks - otick); 375 else 376 remaining -= otick - ticks; 377 otick = ticks; 378 } 379 } 380 381 #ifdef GPROF 382 /* 383 * profclock() is expanded in line in lev6intr() unless profiling kernel. 384 * Assumes it is called with clock interrupts blocked. 385 */ 386 profclock(pc, ps) 387 void *pc; 388 int ps; 389 { 390 /* 391 * Came from user mode. 392 * If this process is being profiled record the tick. 393 */ 394 if (USERMODE(ps)) { 395 if (p->p_stats.p_prof.pr_scale) 396 addupc(pc, &curproc->p_stats.p_prof, 1); 397 } 398 /* 399 * Came from kernel (supervisor) mode. 400 * If we are profiling the kernel, record the tick. 401 */ 402 else if (profiling < 2) { 403 register int s = pc - s_lowpc; 404 405 if (s < s_textsize) 406 kcount[s / (HISTFRACTION * sizeof (*kcount))]++; 407 } 408 /* 409 * Kernel profiling was on but has been disabled. 410 * Mark as no longer profiling kernel and if all profiling done, 411 * disable the clock. 412 */ 413 if (profiling && (profon & PRF_KERNEL)) { 414 profon &= ~PRF_KERNEL; 415 if (profon == PRF_NONE) 416 stopprofclock(); 417 } 418 } 419 #endif 420 421 /*********************************************************************** 422 * Real Time Clock support * 423 ***********************************************************************/ 424 425 u_int mc146818_read(rtc, regno) 426 void *rtc; 427 u_int regno; 428 { 429 ((struct rtc *)rtc)->rtc_regno = regno; 430 return(((struct rtc *)rtc)->rtc_data & 0377); 431 } 432 433 void mc146818_write(rtc, regno, value) 434 void *rtc; 435 u_int regno, value; 436 { 437 ((struct rtc *)rtc)->rtc_regno = regno; 438 ((struct rtc *)rtc)->rtc_data = value; 439 } 440 441 static int 442 atari_rtc_get(todr_chip_handle_t todr, struct clock_ymdhms *dtp) 443 { 444 int sps; 445 mc_todregs clkregs; 446 u_int regb; 447 448 sps = splhigh(); 449 regb = mc146818_read(RTC, MC_REGB); 450 MC146818_GETTOD(RTC, &clkregs); 451 splx(sps); 452 453 regb &= MC_REGB_24HR|MC_REGB_BINARY; 454 if (regb != (MC_REGB_24HR|MC_REGB_BINARY)) { 455 printf("Error: Nonstandard RealTimeClock Configuration -" 456 " value ignored\n" 457 " A write to /dev/rtc will correct this.\n"); 458 return(0); 459 } 460 if(clkregs[MC_SEC] > 59) 461 return -1; 462 if(clkregs[MC_MIN] > 59) 463 return -1; 464 if(clkregs[MC_HOUR] > 23) 465 return -1; 466 if(range_test(clkregs[MC_DOM], 1, 31)) 467 return -1; 468 if (range_test(clkregs[MC_MONTH], 1, 12)) 469 return -1; 470 if(clkregs[MC_YEAR] > 99) 471 return -1; 472 473 dtp->dt_year = clkregs[MC_YEAR] + GEMSTARTOFTIME; 474 dtp->dt_mon = clkregs[MC_MONTH]; 475 dtp->dt_day = clkregs[MC_DOM]; 476 dtp->dt_hour = clkregs[MC_HOUR]; 477 dtp->dt_min = clkregs[MC_MIN]; 478 dtp->dt_sec = clkregs[MC_SEC]; 479 480 return 0; 481 } 482 483 static int 484 atari_rtc_set(todr_chip_handle_t todr, struct clock_ymdhms *dtp) 485 { 486 int s; 487 mc_todregs clkregs; 488 489 clkregs[MC_YEAR] = dtp->dt_year - GEMSTARTOFTIME; 490 clkregs[MC_MONTH] = dtp->dt_mon; 491 clkregs[MC_DOM] = dtp->dt_day; 492 clkregs[MC_HOUR] = dtp->dt_hour; 493 clkregs[MC_MIN] = dtp->dt_min; 494 clkregs[MC_SEC] = dtp->dt_sec; 495 496 s = splclock(); 497 MC146818_PUTTOD(RTC, &clkregs); 498 splx(s); 499 500 return 0; 501 } 502 503 /*********************************************************************** 504 * RTC-device support * 505 ***********************************************************************/ 506 int 507 rtcopen(dev, flag, mode, l) 508 dev_t dev; 509 int flag, mode; 510 struct lwp *l; 511 { 512 int unit = minor(dev); 513 struct clock_softc *sc; 514 515 sc = device_lookup_private(&clock_cd, unit); 516 if (sc == NULL) 517 return ENXIO; 518 if (sc->sc_flags & RTC_OPEN) 519 return EBUSY; 520 521 sc->sc_flags = RTC_OPEN; 522 return 0; 523 } 524 525 int 526 rtcclose(dev, flag, mode, l) 527 dev_t dev; 528 int flag; 529 int mode; 530 struct lwp *l; 531 { 532 int unit = minor(dev); 533 struct clock_softc *sc = device_lookup_private(&clock_cd, unit); 534 535 sc->sc_flags = 0; 536 return 0; 537 } 538 539 int 540 rtcread(dev, uio, flags) 541 dev_t dev; 542 struct uio *uio; 543 int flags; 544 { 545 struct clock_softc *sc; 546 mc_todregs clkregs; 547 int s, length; 548 char buffer[16]; 549 550 sc = device_lookup_private(&clock_cd, minor(dev)); 551 552 s = splhigh(); 553 MC146818_GETTOD(RTC, &clkregs); 554 splx(s); 555 556 sprintf(buffer, "%4d%02d%02d%02d%02d.%02d\n", 557 clkregs[MC_YEAR] + GEMSTARTOFTIME, 558 clkregs[MC_MONTH], clkregs[MC_DOM], 559 clkregs[MC_HOUR], clkregs[MC_MIN], clkregs[MC_SEC]); 560 561 if (uio->uio_offset > strlen(buffer)) 562 return 0; 563 564 length = strlen(buffer) - uio->uio_offset; 565 if (length > uio->uio_resid) 566 length = uio->uio_resid; 567 568 return(uiomove((void *)buffer, length, uio)); 569 } 570 571 static int 572 twodigits(buffer, pos) 573 char *buffer; 574 int pos; 575 { 576 int result = 0; 577 578 if (buffer[pos] >= '0' && buffer[pos] <= '9') 579 result = (buffer[pos] - '0') * 10; 580 if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9') 581 result += (buffer[pos+1] - '0'); 582 return(result); 583 } 584 585 int 586 rtcwrite(dev, uio, flags) 587 dev_t dev; 588 struct uio *uio; 589 int flags; 590 { 591 mc_todregs clkregs; 592 int s, length, error; 593 char buffer[16]; 594 595 /* 596 * We require atomic updates! 597 */ 598 length = uio->uio_resid; 599 if (uio->uio_offset || (length != sizeof(buffer) 600 && length != sizeof(buffer - 1))) 601 return(EINVAL); 602 603 if ((error = uiomove((void *)buffer, sizeof(buffer), uio))) 604 return(error); 605 606 if (length == sizeof(buffer) && buffer[sizeof(buffer) - 1] != '\n') 607 return(EINVAL); 608 609 s = splclock(); 610 mc146818_write(RTC, MC_REGB, 611 mc146818_read(RTC, MC_REGB) | MC_REGB_24HR | MC_REGB_BINARY); 612 MC146818_GETTOD(RTC, &clkregs); 613 splx(s); 614 615 clkregs[MC_SEC] = twodigits(buffer, 13); 616 clkregs[MC_MIN] = twodigits(buffer, 10); 617 clkregs[MC_HOUR] = twodigits(buffer, 8); 618 clkregs[MC_DOM] = twodigits(buffer, 6); 619 clkregs[MC_MONTH] = twodigits(buffer, 4); 620 s = twodigits(buffer, 0) * 100 + twodigits(buffer, 2); 621 clkregs[MC_YEAR] = s - GEMSTARTOFTIME; 622 623 s = splclock(); 624 MC146818_PUTTOD(RTC, &clkregs); 625 splx(s); 626 627 return(0); 628 } 629