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