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