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