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