1 /* $NetBSD: clock.c,v 1.28 1997/07/06 23:17:55 is 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/param.h> 46 #include <sys/kernel.h> 47 #include <sys/device.h> 48 #include <sys/systm.h> 49 #include <machine/psl.h> 50 #include <machine/cpu.h> 51 #include <amiga/amiga/device.h> 52 #include <amiga/amiga/custom.h> 53 #include <amiga/amiga/cia.h> 54 #ifdef DRACO 55 #include <dev/ic/ds.h> 56 #include <amiga/amiga/drcustom.h> 57 #endif 58 #include <amiga/dev/rtc.h> 59 #include <amiga/dev/zbusvar.h> 60 61 #include <dev/clock_subr.h> 62 63 #if defined(PROF) && defined(PROFTIMER) 64 #include <sys/PROF.h> 65 #endif 66 67 /* the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz. 68 We're using a 100 Hz clock. */ 69 70 #define CLK_INTERVAL amiga_clk_interval 71 int amiga_clk_interval; 72 int eclockfreq; 73 struct CIA *clockcia; 74 75 /* 76 * Machine-dependent clock routines. 77 * 78 * Startrtclock restarts the real-time clock, which provides 79 * hardclock interrupts to kern_clock.c. 80 * 81 * Inittodr initializes the time of day hardware which provides 82 * date functions. 83 * 84 * Resettodr restores the time of day hardware after a time change. 85 * 86 * A note on the real-time clock: 87 * We actually load the clock with CLK_INTERVAL-1 instead of CLK_INTERVAL. 88 * This is because the counter decrements to zero after N+1 enabled clock 89 * periods where N is the value loaded into the counter. 90 */ 91 92 int clockmatch __P((struct device *, struct cfdata *, void *)); 93 void clockattach __P((struct device *, struct device *, void *)); 94 void cpu_initclocks __P((void)); 95 void calibrate_delay __P((struct device *)); 96 97 struct cfattach clock_ca = { 98 sizeof(struct device), clockmatch, clockattach 99 }; 100 101 struct cfdriver clock_cd = { 102 NULL, "clock", DV_DULL, NULL, 0 }; 103 104 int 105 clockmatch(pdp, cfp, auxp) 106 struct device *pdp; 107 struct cfdata *cfp; 108 void *auxp; 109 { 110 if (matchname("clock", auxp)) 111 return(1); 112 return(0); 113 } 114 115 /* 116 * Start the real-time clock. 117 */ 118 void 119 clockattach(pdp, dp, auxp) 120 struct device *pdp, *dp; 121 void *auxp; 122 { 123 char *clockchip; 124 unsigned short interval; 125 #ifdef DRACO 126 u_char dracorev; 127 #endif 128 129 if (eclockfreq == 0) 130 eclockfreq = 715909; /* guess NTSC */ 131 132 CLK_INTERVAL = (eclockfreq / 100); 133 134 #ifdef DRACO 135 dracorev = is_draco(); 136 if (dracorev >= 4) { 137 CLK_INTERVAL = (eclockfreq / 700); 138 clockchip = "QuickLogic"; 139 } else if (dracorev) { 140 clockcia = (struct CIA *)CIAAbase; 141 clockchip = "CIA A"; 142 } else 143 #endif 144 { 145 clockcia = (struct CIA *)CIABbase; 146 clockchip = "CIA B"; 147 } 148 149 if (dp) 150 printf(": %s system hz %d hardware hz %d\n", clockchip, hz, 151 #ifdef DRACO 152 dracorev >= 4 ? eclockfreq / 7 : eclockfreq); 153 #else 154 eclockfreq); 155 #endif 156 157 #ifdef DRACO 158 if (dracorev >= 4) { 159 /* 160 * can't preload anything beforehand, timer is free_running; 161 * but need this for delay calibration. 162 */ 163 164 draco_ioct->io_timerlo = CLK_INTERVAL & 0xff; 165 draco_ioct->io_timerhi = CLK_INTERVAL >> 8; 166 167 calibrate_delay(dp); 168 169 return; 170 } 171 #endif 172 /* 173 * stop timer A 174 */ 175 clockcia->cra = clockcia->cra & 0xc0; 176 clockcia->icr = 1 << 0; /* disable timer A interrupt */ 177 interval = clockcia->icr; /* and make sure it's clear */ 178 179 /* 180 * load interval into registers. 181 * the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz 182 * supprort for PAL WHEN?!?! XXX 183 */ 184 interval = CLK_INTERVAL - 1; 185 186 /* 187 * order of setting is important ! 188 */ 189 clockcia->talo = interval & 0xff; 190 clockcia->tahi = interval >> 8; 191 /* 192 * start timer A in continuous mode 193 */ 194 clockcia->cra = (clockcia->cra & 0xc0) | 1; 195 196 calibrate_delay(dp); 197 } 198 199 /* 200 * Calibrate delay loop. 201 * We use two iterations because we don't have enough bits to do a factor of 202 * 8 with better than 1%. 203 * 204 * XXX Note that we MUST stay below 1 tick if using clkread(), even for 205 * underestimated values of delaydivisor. 206 * 207 * XXX the "ns" below is only correct for a shift of 10 bits, and even then 208 * off by 2.4% 209 */ 210 211 void calibrate_delay(dp) 212 struct device *dp; 213 { 214 unsigned long t1, t2; 215 extern u_int32_t delaydivisor; 216 /* XXX this should be defined elsewhere */ 217 218 if (dp) 219 printf("Calibrating delay loop... "); 220 221 do { 222 t1 = clkread(); 223 delay(1024); 224 t2 = clkread(); 225 } while (t2 <= t1); 226 t2 -= t1; 227 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 228 #ifdef DIAGNOSTIC 229 if (dp) 230 printf("\ndiff %ld us, new divisor %u/1024 us\n", t2, 231 delaydivisor); 232 do { 233 t1 = clkread(); 234 delay(1024); 235 t2 = clkread(); 236 } while (t2 <= t1); 237 t2 -= t1; 238 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 239 if (dp) 240 printf("diff %ld us, new divisor %u/1024 us\n", t2, 241 delaydivisor); 242 #endif 243 do { 244 t1 = clkread(); 245 delay(1024); 246 t2 = clkread(); 247 } while (t2 <= t1); 248 t2 -= t1; 249 delaydivisor = (delaydivisor * t2 + 1023) >> 10; 250 #ifdef DIAGNOSTIC 251 if (dp) 252 printf("diff %ld us, new divisor ", t2); 253 #endif 254 if (dp) 255 printf("%u/1024 us\n", delaydivisor); 256 } 257 258 void 259 cpu_initclocks() 260 { 261 #ifdef DRACO 262 unsigned char dracorev; 263 dracorev = is_draco(); 264 if (dracorev >= 4) { 265 draco_ioct->io_timerlo = CLK_INTERVAL & 0xFF; 266 draco_ioct->io_timerhi = CLK_INTERVAL >> 8; 267 draco_ioct->io_timerrst = 0; /* any value resets */ 268 draco_ioct->io_status2 |= DRSTAT2_TMRINTENA; 269 270 return; 271 } 272 #endif 273 /* 274 * enable interrupts for timer A 275 */ 276 clockcia->icr = (1<<7) | (1<<0); 277 278 /* 279 * start timer A in continuous shot mode 280 */ 281 clockcia->cra = (clockcia->cra & 0xc0) | 1; 282 283 /* 284 * and globally enable interrupts for ciab 285 */ 286 #ifdef DRACO 287 if (dracorev) /* we use cia a on DraCo */ 288 *draco_intena |= DRIRQ_INT2; 289 else 290 #endif 291 custom.intena = INTF_SETCLR | INTF_EXTER; 292 293 } 294 295 void 296 setstatclockrate(hz) 297 int hz; 298 { 299 } 300 301 /* 302 * Returns number of usec since last recorded clock "tick" 303 * (i.e. clock interrupt). 304 */ 305 u_long 306 clkread() 307 { 308 u_int interval; 309 u_char hi, hi2, lo; 310 311 #ifdef DRACO 312 if (is_draco() >= 4) { 313 hi2 = draco_ioct->io_chiprev; /* latch timer */ 314 hi = draco_ioct->io_timerhi; 315 lo = draco_ioct->io_timerlo; 316 interval = ((hi<<8) | lo); 317 if (interval > CLK_INTERVAL) /* timer underflow */ 318 interval = 65536 + CLK_INTERVAL - interval; 319 else 320 interval = CLK_INTERVAL - interval; 321 322 } else 323 #endif 324 { 325 hi = clockcia->tahi; 326 lo = clockcia->talo; 327 hi2 = clockcia->tahi; 328 if (hi != hi2) { 329 lo = clockcia->talo; 330 hi = hi2; 331 } 332 333 interval = (CLK_INTERVAL - 1) - ((hi<<8) | lo); 334 335 /* 336 * should read ICR and if there's an int pending, adjust 337 * interval. However, since reading ICR clears the interrupt, 338 * we'd lose a hardclock int, and this is not tolerable. 339 */ 340 } 341 342 return((interval * tick) / CLK_INTERVAL); 343 } 344 345 #if notyet 346 347 /* implement this later. I'd suggest using both timers in CIA-A, they're 348 not yet used. */ 349 350 #include "clock.h" 351 #if NCLOCK > 0 352 /* 353 * /dev/clock: mappable high resolution timer. 354 * 355 * This code implements a 32-bit recycling counter (with a 4 usec period) 356 * using timers 2 & 3 on the 6840 clock chip. The counter can be mapped 357 * RO into a user's address space to achieve low overhead (no system calls), 358 * high-precision timing. 359 * 360 * Note that timer 3 is also used for the high precision profiling timer 361 * (PROFTIMER code above). Care should be taken when both uses are 362 * configured as only a token effort is made to avoid conflicting use. 363 */ 364 #include <sys/proc.h> 365 #include <sys/resourcevar.h> 366 #include <sys/ioctl.h> 367 #include <sys/malloc.h> 368 #include <vm/vm.h> 369 #include <amiga/amiga/clockioctl.h> 370 #include <sys/specdev.h> 371 #include <sys/vnode.h> 372 #include <sys/mman.h> 373 374 int clockon = 0; /* non-zero if high-res timer enabled */ 375 #ifdef PROFTIMER 376 int profprocs = 0; /* # of procs using profiling timer */ 377 #endif 378 #ifdef DEBUG 379 int clockdebug = 0; 380 #endif 381 382 /*ARGSUSED*/ 383 clockopen(dev, flags) 384 dev_t dev; 385 { 386 #ifdef PROFTIMER 387 #ifdef PROF 388 /* 389 * Kernel profiling enabled, give up. 390 */ 391 if (profiling) 392 return(EBUSY); 393 #endif 394 /* 395 * If any user processes are profiling, give up. 396 */ 397 if (profprocs) 398 return(EBUSY); 399 #endif 400 if (!clockon) { 401 startclock(); 402 clockon++; 403 } 404 return(0); 405 } 406 407 /*ARGSUSED*/ 408 clockclose(dev, flags) 409 dev_t dev; 410 { 411 (void) clockunmmap(dev, (caddr_t)0, curproc); /* XXX */ 412 stopclock(); 413 clockon = 0; 414 return(0); 415 } 416 417 /*ARGSUSED*/ 418 clockioctl(dev, cmd, data, flag, p) 419 dev_t dev; 420 u_long cmd; 421 caddr_t data; 422 struct proc *p; 423 { 424 int error = 0; 425 426 switch (cmd) { 427 428 case CLOCKMAP: 429 error = clockmmap(dev, (caddr_t *)data, p); 430 break; 431 432 case CLOCKUNMAP: 433 error = clockunmmap(dev, *(caddr_t *)data, p); 434 break; 435 436 case CLOCKGETRES: 437 *(int *)data = CLK_RESOLUTION; 438 break; 439 440 default: 441 error = EINVAL; 442 break; 443 } 444 return(error); 445 } 446 447 /*ARGSUSED*/ 448 clockmap(dev, off, prot) 449 dev_t dev; 450 { 451 return((off + (INTIOBASE+CLKBASE+CLKSR-1)) >> PGSHIFT); 452 } 453 454 clockmmap(dev, addrp, p) 455 dev_t dev; 456 caddr_t *addrp; 457 struct proc *p; 458 { 459 int error; 460 struct vnode vn; 461 struct specinfo si; 462 int flags; 463 464 flags = MAP_FILE|MAP_SHARED; 465 if (*addrp) 466 flags |= MAP_FIXED; 467 else 468 *addrp = (caddr_t)0x1000000; /* XXX */ 469 vn.v_type = VCHR; /* XXX */ 470 vn.v_specinfo = &si; /* XXX */ 471 vn.v_rdev = dev; /* XXX */ 472 error = vm_mmap(&p->p_vmspace->vm_map, (vm_offset_t *)addrp, 473 PAGE_SIZE, VM_PROT_ALL, flags, (caddr_t)&vn, 0); 474 return(error); 475 } 476 477 clockunmmap(dev, addr, p) 478 dev_t dev; 479 caddr_t addr; 480 struct proc *p; 481 { 482 int rv; 483 484 if (addr == 0) 485 return(EINVAL); /* XXX: how do we deal with this? */ 486 rv = vm_deallocate(p->p_vmspace->vm_map, (vm_offset_t)addr, PAGE_SIZE); 487 return(rv == KERN_SUCCESS ? 0 : EINVAL); 488 } 489 490 startclock() 491 { 492 register struct clkreg *clk = (struct clkreg *)clkstd[0]; 493 494 clk->clk_msb2 = -1; clk->clk_lsb2 = -1; 495 clk->clk_msb3 = -1; clk->clk_lsb3 = -1; 496 497 clk->clk_cr2 = CLK_CR3; 498 clk->clk_cr3 = CLK_OENAB|CLK_8BIT; 499 clk->clk_cr2 = CLK_CR1; 500 clk->clk_cr1 = CLK_IENAB; 501 } 502 503 stopclock() 504 { 505 register struct clkreg *clk = (struct clkreg *)clkstd[0]; 506 507 clk->clk_cr2 = CLK_CR3; 508 clk->clk_cr3 = 0; 509 clk->clk_cr2 = CLK_CR1; 510 clk->clk_cr1 = CLK_IENAB; 511 } 512 #endif 513 514 #endif 515 516 517 #ifdef PROFTIMER 518 /* 519 * This code allows the amiga kernel to use one of the extra timers on 520 * the clock chip for profiling, instead of the regular system timer. 521 * The advantage of this is that the profiling timer can be turned up to 522 * a higher interrupt rate, giving finer resolution timing. The profclock 523 * routine is called from the lev6intr in locore, and is a specialized 524 * routine that calls addupc. The overhead then is far less than if 525 * hardclock/softclock was called. Further, the context switch code in 526 * locore has been changed to turn the profile clock on/off when switching 527 * into/out of a process that is profiling (startprofclock/stopprofclock). 528 * This reduces the impact of the profiling clock on other users, and might 529 * possibly increase the accuracy of the profiling. 530 */ 531 int profint = PRF_INTERVAL; /* Clock ticks between interrupts */ 532 int profscale = 0; /* Scale factor from sys clock to prof clock */ 533 char profon = 0; /* Is profiling clock on? */ 534 535 /* profon values - do not change, locore.s assumes these values */ 536 #define PRF_NONE 0x00 537 #define PRF_USER 0x01 538 #define PRF_KERNEL 0x80 539 540 initprofclock() 541 { 542 #if NCLOCK > 0 543 struct proc *p = curproc; /* XXX */ 544 545 /* 546 * If the high-res timer is running, force profiling off. 547 * Unfortunately, this gets reflected back to the user not as 548 * an error but as a lack of results. 549 */ 550 if (clockon) { 551 p->p_stats->p_prof.pr_scale = 0; 552 return; 553 } 554 /* 555 * Keep track of the number of user processes that are profiling 556 * by checking the scale value. 557 * 558 * XXX: this all assumes that the profiling code is well behaved; 559 * i.e. profil() is called once per process with pcscale non-zero 560 * to turn it on, and once with pcscale zero to turn it off. 561 * Also assumes you don't do any forks or execs. Oh well, there 562 * is always adb... 563 */ 564 if (p->p_stats->p_prof.pr_scale) 565 profprocs++; 566 else 567 profprocs--; 568 #endif 569 /* 570 * The profile interrupt interval must be an even divisor 571 * of the CLK_INTERVAL so that scaling from a system clock 572 * tick to a profile clock tick is possible using integer math. 573 */ 574 if (profint > CLK_INTERVAL || (CLK_INTERVAL % profint) != 0) 575 profint = CLK_INTERVAL; 576 profscale = CLK_INTERVAL / profint; 577 } 578 579 startprofclock() 580 { 581 unsigned short interval; 582 583 /* stop timer B */ 584 clockcia->crb = clockcia->crb & 0xc0; 585 586 /* load interval into registers. 587 the clocks run at NTSC: 715.909kHz or PAL: 709.379kHz */ 588 589 interval = profint - 1; 590 591 /* order of setting is important ! */ 592 clockcia->tblo = interval & 0xff; 593 clockcia->tbhi = interval >> 8; 594 595 /* enable interrupts for timer B */ 596 clockcia->icr = (1<<7) | (1<<1); 597 598 /* start timer B in continuous shot mode */ 599 clockcia->crb = (clockcia->crb & 0xc0) | 1; 600 } 601 602 stopprofclock() 603 { 604 /* stop timer B */ 605 clockcia->crb = clockcia->crb & 0xc0; 606 } 607 608 #ifdef PROF 609 /* 610 * profclock() is expanded in line in lev6intr() unless profiling kernel. 611 * Assumes it is called with clock interrupts blocked. 612 */ 613 profclock(pc, ps) 614 caddr_t pc; 615 int ps; 616 { 617 /* 618 * Came from user mode. 619 * If this process is being profiled record the tick. 620 */ 621 if (USERMODE(ps)) { 622 if (p->p_stats.p_prof.pr_scale) 623 addupc(pc, &curproc->p_stats.p_prof, 1); 624 } 625 /* 626 * Came from kernel (supervisor) mode. 627 * If we are profiling the kernel, record the tick. 628 */ 629 else if (profiling < 2) { 630 register int s = pc - s_lowpc; 631 632 if (s < s_textsize) 633 kcount[s / (HISTFRACTION * sizeof (*kcount))]++; 634 } 635 /* 636 * Kernel profiling was on but has been disabled. 637 * Mark as no longer profiling kernel and if all profiling done, 638 * disable the clock. 639 */ 640 if (profiling && (profon & PRF_KERNEL)) { 641 profon &= ~PRF_KERNEL; 642 if (profon == PRF_NONE) 643 stopprofclock(); 644 } 645 } 646 #endif 647 #endif 648 649 /* this is a hook set by a clock driver for the configured realtime clock, 650 returning plain current unix-time */ 651 time_t (*gettod) __P((void)); 652 int (*settod) __P((time_t)); 653 void *clockaddr; 654 655 time_t a3gettod __P((void)); 656 time_t a2gettod __P((void)); 657 int a3settod __P((time_t)); 658 int a2settod __P((time_t)); 659 660 #ifdef DRACO 661 int draco_ds_read_bit __P((void *)); 662 void draco_ds_write_bit __P((void *, int)); 663 void draco_ds_reset __P((void *)); 664 665 time_t dracogettod __P((void)); 666 667 #ifdef __NOTYET__ 668 int dracosettod __P((time_t)); 669 #endif 670 #endif 671 672 int rtcinit __P((void)); 673 674 /* 675 * Initialize the time of day register, based on the time base which is, e.g. 676 * from a filesystem. 677 */ 678 void 679 inittodr(base) 680 time_t base; 681 { 682 time_t timbuf = base; /* assume no battery clock exists */ 683 684 if (gettod == NULL && rtcinit() == 0) 685 printf("WARNING: no battery clock\n"); 686 else 687 timbuf = gettod() + rtc_offset * 60; 688 689 if (timbuf < base) { 690 printf("WARNING: bad date in battery clock\n"); 691 timbuf = base; 692 } 693 694 /* Battery clock does not store usec's, so forget about it. */ 695 time.tv_sec = timbuf; 696 } 697 698 void 699 resettodr() 700 { 701 if (settod && settod(time.tv_sec - rtc_offset * 60) == 0) 702 printf("Cannot set battery backed clock\n"); 703 } 704 705 int 706 rtcinit() 707 { 708 clockaddr = (void *)ztwomap(0xdc0000); 709 #ifdef DRACO 710 if (is_draco()) { 711 /* XXX to be done */ 712 gettod = dracogettod; 713 settod = (void *)0; 714 } else 715 #endif 716 if (is_a3000() || is_a4000()) { 717 if (a3gettod() == 0) 718 return(0); 719 gettod = a3gettod; 720 settod = a3settod; 721 } else { 722 if (a2gettod() == 0) 723 return(0); 724 gettod = a2gettod; 725 settod = a2settod; 726 } 727 return(1); 728 } 729 730 time_t 731 a3gettod() 732 { 733 struct rtclock3000 *rt; 734 struct clock_ymdhms dt; 735 time_t secs; 736 737 rt = clockaddr; 738 739 /* hold clock */ 740 rt->control1 = A3CONTROL1_HOLD_CLOCK; 741 742 /* Copy the info. Careful about the order! */ 743 dt.dt_sec = rt->second1 * 10 + rt->second2; 744 dt.dt_min = rt->minute1 * 10 + rt->minute2; 745 dt.dt_hour = rt->hour1 * 10 + rt->hour2; 746 dt.dt_wday = rt->weekday; 747 dt.dt_day = rt->day1 * 10 + rt->day2; 748 dt.dt_mon = rt->month1 * 10 + rt->month2; 749 dt.dt_year = rt->year1 * 10 + rt->year2; 750 751 dt.dt_year += CLOCK_BASE_YEAR; 752 753 /* let it run again.. */ 754 rt->control1 = A3CONTROL1_FREE_CLOCK; 755 756 if ((dt.dt_hour > 23) || 757 (dt.dt_wday > 6) || 758 (dt.dt_day > 31) || 759 (dt.dt_mon > 12) || 760 (dt.dt_year < STARTOFTIME) || (dt.dt_year > 2036)) 761 return (0); 762 763 secs = clock_ymdhms_to_secs(&dt); 764 return (secs); 765 } 766 767 int 768 a3settod(secs) 769 time_t secs; 770 { 771 struct rtclock3000 *rt; 772 struct clock_ymdhms dt; 773 774 rt = clockaddr; 775 /* 776 * there seem to be problems with the bitfield addressing 777 * currently used.. 778 */ 779 780 if (! rt) 781 return (0); 782 783 clock_secs_to_ymdhms(secs, &dt); 784 dt.dt_year -= CLOCK_BASE_YEAR; 785 786 rt->control1 = A3CONTROL1_HOLD_CLOCK; 787 rt->second1 = dt.dt_sec / 10; 788 rt->second2 = dt.dt_sec % 10; 789 rt->minute1 = dt.dt_min / 10; 790 rt->minute2 = dt.dt_min % 10; 791 rt->hour1 = dt.dt_hour / 10; 792 rt->hour2 = dt.dt_hour % 10; 793 rt->weekday = dt.dt_wday; 794 rt->day1 = dt.dt_day / 10; 795 rt->day2 = dt.dt_day % 10; 796 rt->month1 = dt.dt_mon / 10; 797 rt->month2 = dt.dt_mon % 10; 798 rt->year1 = dt.dt_year / 10; 799 rt->year2 = dt.dt_year % 10; 800 rt->control1 = A3CONTROL1_FREE_CLOCK; 801 802 return (1); 803 } 804 805 time_t 806 a2gettod() 807 { 808 struct rtclock2000 *rt; 809 struct clock_ymdhms dt; 810 time_t secs; 811 int i; 812 813 rt = clockaddr; 814 815 /* 816 * hold clock 817 */ 818 rt->control1 |= A2CONTROL1_HOLD; 819 i = 0x1000; 820 while (rt->control1 & A2CONTROL1_BUSY && i--) 821 ; 822 if (rt->control1 & A2CONTROL1_BUSY) 823 return (0); /* Give up and say it's not there */ 824 825 /* Copy the info. Careful about the order! */ 826 dt.dt_sec = rt->second1 * 10 + rt->second2; 827 dt.dt_min = rt->minute1 * 10 + rt->minute2; 828 dt.dt_hour = (rt->hour1 & 3) * 10 + rt->hour2; 829 dt.dt_day = rt->day1 * 10 + rt->day2; 830 dt.dt_mon = rt->month1 * 10 + rt->month2; 831 dt.dt_year = rt->year1 * 10 + rt->year2; 832 dt.dt_wday = rt->weekday; 833 834 /* 835 * The oki clock chip has a register to put the clock into 836 * 12/24h mode. 837 * 838 * clockmode | A2HOUR1_PM 839 * 24h 12h | am = 0, pm = 1 840 * --------------------------------- 841 * 0 12 | 0 842 * 1 1 | 0 843 * .. .. | 0 844 * 11 11 | 0 845 * 12 12 | 1 846 * 13 1 | 1 847 * .. .. | 1 848 * 23 11 | 1 849 * 850 */ 851 852 if ((rt->control3 & A2CONTROL3_24HMODE) == 0) { 853 if ((rt->hour1 & A2HOUR1_PM) == 0 && dt.dt_hour == 12) 854 dt.dt_hour = 0; 855 else if ((rt->hour1 & A2HOUR1_PM) && dt.dt_hour != 12) 856 dt.dt_hour += 12; 857 } 858 859 /* 860 * release the clock 861 */ 862 rt->control1 &= ~A2CONTROL1_HOLD; 863 864 dt.dt_year += CLOCK_BASE_YEAR; 865 866 if ((dt.dt_hour > 23) || 867 (dt.dt_day > 31) || 868 (dt.dt_mon > 12) || 869 (dt.dt_year < STARTOFTIME) || (dt.dt_year > 2036)) 870 return (0); 871 872 secs = clock_ymdhms_to_secs(&dt); 873 return (secs); 874 } 875 876 int 877 a2settod(secs) 878 time_t secs; 879 { 880 struct rtclock2000 *rt; 881 struct clock_ymdhms dt; 882 int ampm, i; 883 884 rt = clockaddr; 885 /* 886 * there seem to be problems with the bitfield addressing 887 * currently used.. 888 */ 889 if (! rt) 890 return (0); 891 892 clock_secs_to_ymdhms(secs, &dt); 893 dt.dt_year -= CLOCK_BASE_YEAR; 894 895 /* 896 * hold clock 897 */ 898 rt->control1 |= A2CONTROL1_HOLD; 899 i = 0x1000; 900 while (rt->control1 & A2CONTROL1_BUSY && i--) 901 ; 902 if (rt->control1 & A2CONTROL1_BUSY) 903 return (0); /* Give up and say it's not there */ 904 905 ampm = 0; 906 if ((rt->control3 & A2CONTROL3_24HMODE) == 0) { 907 if (dt.dt_hour >= 12) { 908 ampm = A2HOUR1_PM; 909 if (dt.dt_hour != 12) 910 dt.dt_hour -= 12; 911 } else if (dt.dt_hour == 0) { 912 dt.dt_hour = 12; 913 } 914 } 915 rt->hour1 = (dt.dt_hour / 10) | ampm; 916 rt->hour2 = dt.dt_hour % 10; 917 rt->second1 = dt.dt_sec / 10; 918 rt->second2 = dt.dt_sec % 10; 919 rt->minute1 = dt.dt_min / 10; 920 rt->minute2 = dt.dt_min % 10; 921 rt->day1 = dt.dt_day / 10; 922 rt->day2 = dt.dt_day % 10; 923 rt->month1 = dt.dt_mon / 10; 924 rt->month2 = dt.dt_mon % 10; 925 rt->year1 = dt.dt_year / 10; 926 rt->year2 = dt.dt_year % 10; 927 rt->weekday = dt.dt_wday; 928 929 /* 930 * release the clock 931 */ 932 rt->control2 &= ~A2CONTROL1_HOLD; 933 934 return (1); 935 } 936 937 #ifdef DRACO 938 939 940 int 941 draco_ds_read_bit(p) 942 void *p; 943 { 944 struct drioct *draco_ioct; 945 946 draco_ioct = p; 947 948 while (draco_ioct->io_status & DRSTAT_CLKBUSY); 949 950 draco_ioct->io_clockw1 = 0; 951 952 while (draco_ioct->io_status & DRSTAT_CLKBUSY); 953 954 return (draco_ioct->io_status & DRSTAT_CLKDAT); 955 } 956 957 void 958 draco_ds_write_bit(p, b) 959 void *p; 960 int b; 961 { 962 struct drioct *draco_ioct; 963 964 draco_ioct = p; 965 966 while (draco_ioct->io_status & DRSTAT_CLKBUSY); 967 968 if (b) 969 draco_ioct->io_clockw1 = 0; 970 else 971 draco_ioct->io_clockw0 = 0; 972 } 973 974 void 975 draco_ds_reset(p) 976 void *p; 977 { 978 struct drioct *draco_ioct; 979 980 draco_ioct = p; 981 982 draco_ioct->io_clockrst = 0; 983 } 984 985 /* 986 * We could return 1/256 of a seconds, but would need to change the interface 987 */ 988 989 time_t 990 dracogettod() 991 { 992 u_int32_t clkbuf; 993 u_int8_t rombuf[8]; 994 int i; 995 struct ds_handle draco_dsh; 996 997 draco_dsh.ds_read_bit = draco_ds_read_bit; 998 draco_dsh.ds_write_bit = draco_ds_write_bit; 999 draco_dsh.ds_reset = draco_ds_reset; 1000 draco_dsh.ds_hw_handle = (void *)(DRCCADDR + DRIOCTLPG*NBPG); 1001 1002 draco_dsh.ds_reset(draco_dsh.ds_hw_handle); 1003 1004 ds_write_byte(&draco_dsh, DS_ROM_READ); 1005 for (i=0; i<8; ++i) 1006 rombuf[i] = ds_read_byte(&draco_dsh); 1007 1008 printf("DraCo RTC: sernum %d (ROM %02x%02x%02x%02x%02x%02x%02x%02x)\n", 1009 (rombuf[3] << 24) + (rombuf[2] << 16) + 1010 (rombuf[1] << 8) + rombuf[7], 1011 rombuf[7], rombuf[6], rombuf[5], rombuf[4], 1012 rombuf[3], rombuf[2], rombuf[1], rombuf[0]); 1013 1014 1015 ds_write_byte(&draco_dsh, DS_MEM_READ_MEMORY); 1016 ds_write_byte(&draco_dsh, 0x03); /* low ads byte of realtime second */ 1017 ds_write_byte(&draco_dsh, 0x02); /* high ads byte of realtime second */ 1018 1019 clkbuf = ds_read_byte(&draco_dsh) 1020 + (ds_read_byte(&draco_dsh)<<8) 1021 + (ds_read_byte(&draco_dsh)<<16) 1022 + (ds_read_byte(&draco_dsh)<<24); 1023 1024 /* BSD time is wr. 1.1.1970; AmigaOS time wrt. 1.1.1978 */ 1025 1026 clkbuf += (8*365 + 2) * 86400; 1027 1028 return ((time_t)clkbuf); 1029 } 1030 1031 #endif 1032