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