1 /* $NetBSD: clock.c,v 1.31 1997/09/15 22:17:55 is 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 41 * 42 * @(#)clock.c 7.6 (Berkeley) 5/7/91 43 */ 44 45 #include <sys/param.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <sys/systm.h> 49 #include <machine/psl.h> 50 #include <machine/cpu.h> 51 #include <amiga/amiga/device.h> 52 #include <amiga/amiga/custom.h> 53 #include <amiga/amiga/cia.h> 54 #ifdef DRACO 55 #include <amiga/amiga/drcustom.h> 56 #endif 57 #include <amiga/dev/rtc.h> 58 #include <amiga/dev/zbusvar.h> 59 60 #if defined(PROF) && defined(PROFTIMER) 61 #include <sys/PROF.h> 62 #endif 63 64 /* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz. 65 We're using a 100 Hz clock. */ 66 67 #define CLK_INTERVAL amiga_clk_interval 68 int amiga_clk_interval; 69 int eclockfreq; 70 struct CIA *clockcia; 71 72 /* 73 * Machine-dependent clock routines. 74 * 75 * Startrtclock restarts the real-time clock, which provides 76 * hardclock interrupts to kern_clock.c. 77 * 78 * Inittodr initializes the time of day hardware which provides 79 * date functions. 80 * 81 * Resettodr restores the time of day hardware after a time change. 82 * 83 * A note on the real-time clock: 84 * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL. 85 * This is because the counter decrements to zero after N+1 enabled clock 86 * periods where N is the value loaded into the counter. 87 */ 88 89 int clockmatch __P((struct device *, struct cfdata *, void *)); 90 void clockattach __P((struct device *, struct device *, void *)); 91 void cpu_initclocks __P((void)); 92 void calibrate_delay __P((struct device *)); 93 94 struct cfattach clock_ca = { 95 sizeof(struct device), clockmatch, clockattach 96 }; 97 98 struct cfdriver clock_cd = { 99 NULL, "clock", DV_DULL, NULL, 0 }; 100 101 int 102 clockmatch(pdp, cfp, auxp) 103 struct device *pdp; 104 struct cfdata *cfp; 105 void *auxp; 106 { 107 if (matchname("clock", auxp)) 108 return(1); 109 return(0); 110 } 111 112 /* 113 * Start the real-time clock. 114 */ 115 void 116 clockattach(pdp, dp, auxp) 117 struct device *pdp, *dp; 118 void *auxp; 119 { 120 char *clockchip; 121 unsigned short interval; 122 #ifdef DRACO 123 u_char dracorev; 124 #endif 125 126 if (eclockfreq == 0) 127 eclockfreq = 715909; /* guess NTSC */ 128 129 CLK_INTERVAL = (eclockfreq / 100); 130 131 #ifdef DRACO 132 dracorev = is_draco(); 133 if (dracorev >= 4) { 134 CLK_INTERVAL = (eclockfreq / 700); 135 clockchip = "QuickLogic"; 136 } else if (dracorev) { 137 clockcia = (struct CIA *)CIAAbase; 138 clockchip = "CIA A"; 139 } else 140 #endif 141 { 142 clockcia = (struct CIA *)CIABbase; 143 clockchip = "CIA B"; 144 } 145 146 if (dp) 147 printf(": %s system hz %d hardware hz %d\n", clockchip, hz, 148 #ifdef DRACO 149 dracorev >= 4 ? eclockfreq / 7 : eclockfreq); 150 #else 151 eclockfreq); 152 #endif 153 154 #ifdef DRACO 155 if (dracorev >= 4) { 156 /* 157 * can't preload anything beforehand, timer is free_running; 158 * but need this for delay calibration. 159 */ 160 161 draco_ioct->io_timerlo = CLK_INTERVAL & 0xff; 162 draco_ioct->io_timerhi = CLK_INTERVAL >> 8; 163 164 calibrate_delay(dp); 165 166 return; 167 } 168 #endif 169 /* 170 * stop timer A 171 */ 172 clockcia->cra = clockcia->cra & 0xc0; 173 clockcia->icr = 1 << 0; /* disable timer A interrupt */ 174 interval = clockcia->icr; /* and make sure it's clear */ 175 176 /* 177 * load interval into registers. 178 * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz 179 * supprort for PAL WHEN?!?! XXX 180 */ 181 interval = CLK_INTERVAL - 1; 182 183 /* 184 * order of setting is important ! 185 */ 186 clockcia->talo = interval & 0xff; 187 clockcia->tahi = interval >> 8; 188 /* 189 * start timer A in continuous mode 190 */ 191 clockcia->cra = (clockcia->cra & 0xc0) | 1; 192 193 calibrate_delay(dp); 194 } 195 196 /* 197 * Calibrate delay loop. 198 * We use two iterations because we don't have enough bits to do a factor of 199 * 8 with better than 1%. 200 * 201 * XXX Note that we MUST stay below 1 tick if using clkread(), even for 202 * underestimated values of delaydivisor. 203 * 204 * XXX the "ns" below is only correct for a shift of 10 bits, and even then 205 * off by 2.4% 206 */ 207 208 void calibrate_delay(dp) 209 struct device *dp; 210 { 211 unsigned long t1, t2; 212 extern u_int32_t delaydivisor; 213 /* XXX this should be defined elsewhere */ 214 215 if (dp) 216 printf("Calibrating delay loop... "); 217 218 do { 219 t1 = clkread(); 220 delay(1024); 221 t2 = clkread(); 222 } while (t2 <= t1); 223 t2 -= t1; 224 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 225 #ifdef DEBUG 226 if (dp) 227 printf("\ndiff %ld us, new divisor %u/1024 us\n", t2, 228 delaydivisor); 229 do { 230 t1 = clkread(); 231 delay(1024); 232 t2 = clkread(); 233 } while (t2 <= t1); 234 t2 -= t1; 235 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 236 if (dp) 237 printf("diff %ld us, new divisor %u/1024 us\n", t2, 238 delaydivisor); 239 #endif 240 do { 241 t1 = clkread(); 242 delay(1024); 243 t2 = clkread(); 244 } while (t2 <= t1); 245 t2 -= t1; 246 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 247 #ifdef DEBUG 248 if (dp) 249 printf("diff %ld us, new divisor ", t2); 250 #endif 251 if (dp) 252 printf("%u/1024 us\n", delaydivisor); 253 } 254 255 void 256 cpu_initclocks() 257 { 258 #ifdef DRACO 259 unsigned char dracorev; 260 dracorev = is_draco(); 261 if (dracorev >= 4) { 262 draco_ioct->io_timerlo = CLK_INTERVAL & 0xFF; 263 draco_ioct->io_timerhi = CLK_INTERVAL >> 8; 264 draco_ioct->io_timerrst = 0; /* any value resets */ 265 draco_ioct->io_status2 |= DRSTAT2_TMRINTENA; 266 267 return; 268 } 269 #endif 270 /* 271 * enable interrupts for timer A 272 */ 273 clockcia->icr = (1<<7) | (1<<0); 274 275 /* 276 * start timer A in continuous shot mode 277 */ 278 clockcia->cra = (clockcia->cra & 0xc0) | 1; 279 280 /* 281 * and globally enable interrupts for ciab 282 */ 283 #ifdef DRACO 284 if (dracorev) /* we use cia a on DraCo */ 285 *draco_intena |= DRIRQ_INT2; 286 else 287 #endif 288 custom.intena = INTF_SETCLR | INTF_EXTER; 289 290 } 291 292 void 293 setstatclockrate(hz) 294 int hz; 295 { 296 } 297 298 /* 299 * Returns number of usec since last recorded clock "tick" 300 * (i.e. clock interrupt). 301 */ 302 u_long 303 clkread() 304 { 305 u_int interval; 306 u_char hi, hi2, lo; 307 308 #ifdef DRACO 309 if (is_draco() >= 4) { 310 hi2 = draco_ioct->io_chiprev; /* latch timer */ 311 hi = draco_ioct->io_timerhi; 312 lo = draco_ioct->io_timerlo; 313 interval = ((hi<<8) | lo); 314 if (interval > CLK_INTERVAL) /* timer underflow */ 315 interval = 65536 + CLK_INTERVAL - interval; 316 else 317 interval = CLK_INTERVAL - interval; 318 319 } else 320 #endif 321 { 322 hi = clockcia->tahi; 323 lo = clockcia->talo; 324 hi2 = clockcia->tahi; 325 if (hi != hi2) { 326 lo = clockcia->talo; 327 hi = hi2; 328 } 329 330 interval = (CLK_INTERVAL - 1) - ((hi<<8) | lo); 331 332 /* 333 * should read ICR and if there's an int pending, adjust 334 * interval. However, since reading ICR clears the interrupt, 335 * we'd lose a hardclock int, and this is not tolerable. 336 */ 337 } 338 339 return((interval * tick) / CLK_INTERVAL); 340 } 341 342 #if notyet 343 344 /* implement this later. I'd suggest using both timers in CIA-A, they're 345 not yet used. */ 346 347 #include "clock.h" 348 #if NCLOCK > 0 349 /* 350 * /dev/clock: mappable high resolution timer. 351 * 352 * This code implements a 32-bit recycling counter (with a 4 usec period) 353 * using timers 2 & 3 on the 6840 clock chip. The counter can be mapped 354 * RO into a user's address space to achieve low overhead (no system calls), 355 * high-precision timing. 356 * 357 * Note that timer 3 is also used for the high precision profiling timer 358 * (PROFTIMER code above). Care should be taken when both uses are 359 * configured as only a token effort is made to avoid conflicting use. 360 */ 361 #include <sys/proc.h> 362 #include <sys/resourcevar.h> 363 #include <sys/ioctl.h> 364 #include <sys/malloc.h> 365 #include <vm/vm.h> 366 #include <amiga/amiga/clockioctl.h> 367 #include <sys/specdev.h> 368 #include <sys/vnode.h> 369 #include <sys/mman.h> 370 371 int clockon = 0; /* non-zero if high-res timer enabled */ 372 #ifdef PROFTIMER 373 int profprocs = 0; /* # of procs using profiling timer */ 374 #endif 375 #ifdef DEBUG 376 int clockdebug = 0; 377 #endif 378 379 /*ARGSUSED*/ 380 clockopen(dev, flags) 381 dev_t dev; 382 { 383 #ifdef PROFTIMER 384 #ifdef PROF 385 /* 386 * Kernel profiling enabled, give up. 387 */ 388 if (profiling) 389 return(EBUSY); 390 #endif 391 /* 392 * If any user processes are profiling, give up. 393 */ 394 if (profprocs) 395 return(EBUSY); 396 #endif 397 if (!clockon) { 398 startclock(); 399 clockon++; 400 } 401 return(0); 402 } 403 404 /*ARGSUSED*/ 405 clockclose(dev, flags) 406 dev_t dev; 407 { 408 (void) clockunmmap(dev, (caddr_t)0, curproc); /* XXX */ 409 stopclock(); 410 clockon = 0; 411 return(0); 412 } 413 414 /*ARGSUSED*/ 415 clockioctl(dev, cmd, data, flag, p) 416 dev_t dev; 417 u_long cmd; 418 caddr_t data; 419 struct proc *p; 420 { 421 int error = 0; 422 423 switch (cmd) { 424 425 case CLOCKMAP: 426 error = clockmmap(dev, (caddr_t *)data, p); 427 break; 428 429 case CLOCKUNMAP: 430 error = clockunmmap(dev, *(caddr_t *)data, p); 431 break; 432 433 case CLOCKGETRES: 434 *(int *)data = CLK_RESOLUTION; 435 break; 436 437 default: 438 error = EINVAL; 439 break; 440 } 441 return(error); 442 } 443 444 /*ARGSUSED*/ 445 clockmap(dev, off, prot) 446 dev_t dev; 447 { 448 return((off + (INTIOBASE+CLKBASE+CLKSR-1)) >> PGSHIFT); 449 } 450 451 clockmmap(dev, addrp, p) 452 dev_t dev; 453 caddr_t *addrp; 454 struct proc *p; 455 { 456 int error; 457 struct vnode vn; 458 struct specinfo si; 459 int flags; 460 461 flags = MAP_FILE|MAP_SHARED; 462 if (*addrp) 463 flags |= MAP_FIXED; 464 else 465 *addrp = (caddr_t)0x1000000; /* XXX */ 466 vn.v_type = VCHR; /* XXX */ 467 vn.v_specinfo = &si; /* XXX */ 468 vn.v_rdev = dev; /* XXX */ 469 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 470 PAGE_SIZE, VM_PROT_ALL, flags, (caddr_t)&vn, 0); 471 return(error); 472 } 473 474 clockunmmap(dev, addr, p) 475 dev_t dev; 476 caddr_t addr; 477 struct proc *p; 478 { 479 int rv; 480 481 if (addr == 0) 482 return(EINVAL); /* XXX: how do we deal with this? */ 483 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, PAGE_SIZE); 484 return(rv == KERN_SUCCESS ? 0 : EINVAL); 485 } 486 487 startclock() 488 { 489 register struct clkreg *clk = (struct clkreg *)clkstd[0]; 490 491 clk->clk_msb2 = -1; clk->clk_lsb2 = -1; 492 clk->clk_msb3 = -1; clk->clk_lsb3 = -1; 493 494 clk->clk_cr2 = CLK_CR3; 495 clk->clk_cr3 = CLK_OENAB|CLK_8BIT; 496 clk->clk_cr2 = CLK_CR1; 497 clk->clk_cr1 = CLK_IENAB; 498 } 499 500 stopclock() 501 { 502 register struct clkreg *clk = (struct clkreg *)clkstd[0]; 503 504 clk->clk_cr2 = CLK_CR3; 505 clk->clk_cr3 = 0; 506 clk->clk_cr2 = CLK_CR1; 507 clk->clk_cr1 = CLK_IENAB; 508 } 509 #endif 510 511 #endif 512 513 514 #ifdef PROFTIMER 515 /* 516 * This code allows the amiga kernel to use one of the extra timers on 517 * the clock chip for profiling, instead of the regular system timer. 518 * The advantage of this is that the profiling timer can be turned up to 519 * a higher interrupt rate, giving finer resolution timing. The profclock 520 * routine is called from the lev6intr in locore, and is a specialized 521 * routine that calls addupc. The overhead then is far less than if 522 * hardclock/softclock was called. Further, the context switch code in 523 * locore has been changed to turn the profile clock on/off when switching 524 * into/out of a process that is profiling (startprofclock/stopprofclock). 525 * This reduces the impact of the profiling clock on other users, and might 526 * possibly increase the accuracy of the profiling. 527 */ 528 int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ 529 int profscale = 0; /* Scale factor from sys clock to prof clock */ 530 char profon = 0; /* Is profiling clock on? */ 531 532 /* profon values - do not change, locore.s assumes these values */ 533 #define PRF_NONE 0x00 534 #define PRF_USER 0x01 535 #define PRF_KERNEL 0x80 536 537 initprofclock() 538 { 539 #if NCLOCK > 0 540 struct proc *p = curproc; /* XXX */ 541 542 /* 543 * If the high-res timer is running, force profiling off. 544 * Unfortunately, this gets reflected back to the user not as 545 * an error but as a lack of results. 546 */ 547 if (clockon) { 548 p->p_stats->p_prof.pr_scale = 0; 549 return; 550 } 551 /* 552 * Keep track of the number of user processes that are profiling 553 * by checking the scale value. 554 * 555 * XXX: this all assumes that the profiling code is well behaved; 556 * i.e. profil() is called once per process with pcscale non-zero 557 * to turn it on, and once with pcscale zero to turn it off. 558 * Also assumes you don't do any forks or execs. Oh well, there 559 * is always adb... 560 */ 561 if (p->p_stats->p_prof.pr_scale) 562 profprocs++; 563 else 564 profprocs--; 565 #endif 566 /* 567 * The profile interrupt interval must be an even divisor 568 * of the CLK_INTERVAL so that scaling from a system clock 569 * tick to a profile clock tick is possible using integer math. 570 */ 571 if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0) 572 profint = CLK_INTERVAL; 573 profscale = CLK_INTERVAL / profint; 574 } 575 576 startprofclock() 577 { 578 unsigned short interval; 579 580 /* stop timer B */ 581 clockcia->crb = clockcia->crb & 0xc0; 582 583 /* load interval into registers. 584 the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */ 585 586 interval = profint - 1; 587 588 /* order of setting is important ! */ 589 clockcia->tblo = interval & 0xff; 590 clockcia->tbhi = interval >> 8; 591 592 /* enable interrupts for timer B */ 593 clockcia->icr = (1<<7) | (1<<1); 594 595 /* start timer B in continuous shot mode */ 596 clockcia->crb = (clockcia->crb & 0xc0) | 1; 597 } 598 599 stopprofclock() 600 { 601 /* stop timer B */ 602 clockcia->crb = clockcia->crb & 0xc0; 603 } 604 605 #ifdef PROF 606 /* 607 * profclock() is expanded in line in lev6intr() unless profiling kernel. 608 * Assumes it is called with clock interrupts blocked. 609 */ 610 profclock(pc, ps) 611 caddr_t pc; 612 int ps; 613 { 614 /* 615 * Came from user mode. 616 * If this process is being profiled record the tick. 617 */ 618 if (USERMODE(ps)) { 619 if (p->p_stats.p_prof.pr_scale) 620 addupc(pc, &curproc->p_stats.p_prof, 1); 621 } 622 /* 623 * Came from kernel (supervisor) mode. 624 * If we are profiling the kernel, record the tick. 625 */ 626 else if (profiling < 2) { 627 register int s = pc - s_lowpc; 628 629 if (s < s_textsize) 630 kcount[s / (HISTFRACTION * sizeof (*kcount))]++; 631 } 632 /* 633 * Kernel profiling was on but has been disabled. 634 * Mark as no longer profiling kernel and if all profiling done, 635 * disable the clock. 636 */ 637 if (profiling && (profon & PRF_KERNEL)) { 638 profon &= ~PRF_KERNEL; 639 if (profon == PRF_NONE) 640 stopprofclock(); 641 } 642 } 643 #endif 644 #endif 645 646 /* 647 * Initialize the time of day register, based on the time base which is, e.g. 648 * from a filesystem. 649 */ 650 void 651 inittodr(base) 652 time_t base; 653 { 654 time_t timbuf = base; /* assume no battery clock exists */ 655 656 if (gettod == NULL) 657 printf("WARNING: no battery clock\n"); 658 else 659 timbuf = gettod() + rtc_offset * 60; 660 661 if (timbuf < base) { 662 printf("WARNING: bad date in battery clock\n"); 663 timbuf = base; 664 } 665 666 /* Battery clock does not store usec's, so forget about it. */ 667 time.tv_sec = timbuf; 668 } 669 670 void 671 resettodr() 672 { 673 if (settod && settod(time.tv_sec - rtc_offset * 60) == 0) 674 printf("Cannot set battery backed clock\n"); 675 } 676