1/* $NetBSD: clock.c,v 1.64 2022/06/26 18:46:14 tsutsui 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. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah $Hdr: clock.c 1.18 91/01/21$ 37 * 38 * @(#)clock.c 7.6 (Berkeley) 5/7/91 39 */ 40 41#include <sys/cdefs.h> 42__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.64 2022/06/26 18:46:14 tsutsui Exp $"); 43 44#include <sys/param.h> 45#include <sys/kernel.h> 46#include <sys/systm.h> 47#include <sys/device.h> 48#include <sys/uio.h> 49#include <sys/conf.h> 50#include <sys/proc.h> 51#include <sys/event.h> 52#include <sys/timetc.h> 53 54#include <dev/clock_subr.h> 55 56#include <machine/psl.h> 57#include <machine/cpu.h> 58#include <machine/iomap.h> 59#include <machine/mfp.h> 60#include <atari/dev/clockreg.h> 61#include <atari/dev/clockvar.h> 62#include <atari/atari/device.h> 63 64#if defined(GPROF) && defined(PROFTIMER) 65#include <machine/profile.h> 66#endif 67 68#include "ioconf.h" 69 70static int atari_rtc_get(todr_chip_handle_t, struct clock_ymdhms *); 71static int atari_rtc_set(todr_chip_handle_t, struct clock_ymdhms *); 72 73/* 74 * The MFP clock runs at 2457600Hz. We use a {system,stat,prof}clock divider 75 * of 200. Therefore the timer runs at an effective rate of: 76 * 2457600/200 = 12288Hz. 77 */ 78#define CLOCK_HZ 12288 79 80static u_int clk_getcounter(struct timecounter *); 81 82static struct timecounter clk_timecounter = { 83 .tc_get_timecount = clk_getcounter, 84 .tc_counter_mask = ~0u, 85 .tc_frequency = CLOCK_HZ, 86 .tc_name = "clock", 87 .tc_quality = 100, 88}; 89 90/* 91 * Machine-dependent clock routines. 92 * 93 * Inittodr initializes the time of day hardware which provides 94 * date functions. 95 * 96 * Resettodr restores the time of day hardware after a time change. 97 */ 98 99struct clock_softc { 100 device_t sc_dev; 101 int sc_flags; 102 struct todr_chip_handle sc_handle; 103}; 104 105/* 106 * 'sc_flags' state info. Only used by the rtc-device functions. 107 */ 108#define RTC_OPEN 1 109 110static dev_type_open(rtcopen); 111static dev_type_close(rtcclose); 112static dev_type_read(rtcread); 113static dev_type_write(rtcwrite); 114 115static void clockattach(device_t, device_t, void *); 116static int clockmatch(device_t, cfdata_t, void *); 117 118CFATTACH_DECL_NEW(clock, sizeof(struct clock_softc), 119 clockmatch, clockattach, NULL, NULL); 120 121const struct cdevsw rtc_cdevsw = { 122 .d_open = rtcopen, 123 .d_close = rtcclose, 124 .d_read = rtcread, 125 .d_write = rtcwrite, 126 .d_ioctl = noioctl, 127 .d_stop = nostop, 128 .d_tty = notty, 129 .d_poll = nopoll, 130 .d_mmap = nommap, 131 .d_kqfilter = nokqfilter, 132 .d_discard = nodiscard, 133 .d_flag = 0 134}; 135 136void statintr(struct clockframe); 137 138static int twodigits(char *, int); 139 140static int divisor; /* Systemclock divisor */ 141 142/* 143 * Statistics and profile clock intervals and variances. Variance must 144 * be a power of 2. Since this gives us an even number, not an odd number, 145 * we discard one case and compensate. That is, a variance of 64 would 146 * give us offsets in [0..63]. Instead, we take offsets in [1..63]. 147 * This is symmetric around the point 32, or statvar/2, and thus averages 148 * to that value (assuming uniform random numbers). 149 */ 150#ifdef STATCLOCK 151static int statvar = 32; /* {stat,prof}clock variance */ 152static int statmin; /* statclock divisor - variance/2 */ 153static int profmin; /* profclock divisor - variance/2 */ 154static int clk2min; /* current, from above choices */ 155#endif 156 157static int 158clockmatch(device_t parent, cfdata_t cf, void *aux) 159{ 160 161 if (!strcmp("clock", aux)) 162 return 1; 163 return 0; 164} 165 166/* 167 * Start the real-time clock. 168 */ 169static void 170clockattach(device_t parent, device_t self, void *aux) 171{ 172 struct clock_softc *sc = device_private(self); 173 struct todr_chip_handle *tch; 174 175 sc->sc_dev = self; 176 tch = &sc->sc_handle; 177 tch->todr_gettime_ymdhms = atari_rtc_get; 178 tch->todr_settime_ymdhms = atari_rtc_set; 179 tch->todr_setwen = NULL; 180 181 todr_attach(tch); 182 183 sc->sc_flags = 0; 184 185 /* 186 * Initialize Timer-A in the ST-MFP. We use a divisor of 200. 187 * The MFP clock runs at 2457600Hz. Therefore the timer runs 188 * at an effective rate of: 2457600/200 = 12288Hz. The 189 * following expression works for 48, 64 or 96 hz. 190 */ 191 divisor = CLOCK_HZ/hz; 192 MFP->mf_tacr = 0; /* Stop timer */ 193 MFP->mf_iera &= ~IA_TIMA; /* Disable timer interrupts */ 194 MFP->mf_tadr = divisor; /* Set divisor */ 195 196 clk_timecounter.tc_frequency = CLOCK_HZ; 197 198 if (hz != 48 && hz != 64 && hz != 96) { /* XXX */ 199 aprint_normal(": illegal value %d for systemclock, reset to %d\n\t", 200 hz, 64); 201 hz = 64; 202 } 203 aprint_normal(": system hz %d timer-A divisor 200/%d\n", hz, divisor); 204 tc_init(&clk_timecounter); 205 206#ifdef STATCLOCK 207 if ((stathz == 0) || (stathz > hz) || (CLOCK_HZ % stathz)) 208 stathz = hz; 209 if ((profhz == 0) || (profhz > (hz << 1)) || (CLOCK_HZ % profhz)) 210 profhz = hz << 1; 211 212 MFP->mf_tcdcr &= 0x7; /* Stop timer */ 213 MFP->mf_ierb &= ~IB_TIMC; /* Disable timer inter. */ 214 MFP->mf_tcdr = CLOCK_HZ/stathz; /* Set divisor */ 215 216 statmin = (CLOCK_HZ/stathz) - (statvar >> 1); 217 profmin = (CLOCK_HZ/profhz) - (statvar >> 1); 218 clk2min = statmin; 219#endif /* STATCLOCK */ 220} 221 222void 223cpu_initclocks(void) 224{ 225 226 MFP->mf_tacr = T_Q200; /* Start timer */ 227 MFP->mf_ipra = (u_int8_t)~IA_TIMA;/* Clear pending interrupts */ 228 MFP->mf_iera |= IA_TIMA; /* Enable timer interrupts */ 229 MFP->mf_imra |= IA_TIMA; /* ..... */ 230 231#ifdef STATCLOCK 232 MFP->mf_tcdcr = (MFP->mf_tcdcr & 0x7) | (T_Q200<<4); /* Start */ 233 MFP->mf_iprb = (u_int8_t)~IB_TIMC;/* Clear pending interrupts */ 234 MFP->mf_ierb |= IB_TIMC; /* Enable timer interrupts */ 235 MFP->mf_imrb |= IB_TIMC; /* ..... */ 236#endif /* STATCLOCK */ 237} 238 239void 240setstatclockrate(int newhz) 241{ 242 243#ifdef STATCLOCK 244 if (newhz == stathz) 245 clk2min = statmin; 246 else clk2min = profmin; 247#endif /* STATCLOCK */ 248} 249 250#ifdef STATCLOCK 251void 252statintr(struct clockframe frame) 253{ 254 register int var, r; 255 256 var = statvar - 1; 257 do { 258 r = random() & var; 259 } while (r == 0); 260 261 /* 262 * Note that we are always lagging behind as the new divisor 263 * value will not be loaded until the next interrupt. This 264 * shouldn't disturb the median frequency (I think ;-) ) as 265 * only the value used when switching frequencies is used 266 * twice. This shouldn't happen very often. 267 */ 268 MFP->mf_tcdr = clk2min + r; 269 270 statclock(&frame); 271} 272#endif /* STATCLOCK */ 273 274static u_int 275clk_getcounter(struct timecounter *tc) 276{ 277 uint32_t delta, count, cur_hardclock; 278 uint8_t ipra, tadr; 279 int s; 280 static uint32_t lastcount; 281 282 s = splhigh(); 283 cur_hardclock = getticks(); 284 ipra = MFP->mf_ipra; 285 tadr = MFP->mf_tadr; 286 delta = divisor - tadr; 287 288 if (ipra & IA_TIMA) 289 delta += divisor; 290 splx(s); 291 292 count = (divisor * cur_hardclock) + delta; 293 if ((int32_t)(count - lastcount) < 0) { 294 /* XXX wrapped; maybe hardclock() is blocked more than 2/HZ */ 295 count = lastcount + 1; 296 } 297 lastcount = count; 298 299 return count; 300} 301 302#define TIMB_FREQ 614400 303#define TIMB_LIMIT 256 304 305void 306init_delay(void) 307{ 308 309 /* 310 * Initialize Timer-B in the ST-MFP. This timer is used by 311 * the 'delay' function below. This timer is setup to be 312 * continueously counting from 255 back to zero at a 313 * frequency of 614400Hz. We do this *early* in the 314 * initialisation process. 315 */ 316 MFP->mf_tbcr = 0; /* Stop timer */ 317 MFP->mf_iera &= ~IA_TIMB; /* Disable timer interrupts */ 318 MFP->mf_tbdr = 0; 319 MFP->mf_tbcr = T_Q004; /* Start timer */ 320} 321 322/* 323 * Wait "n" microseconds. 324 * Relies on MFP-Timer B counting down from TIMB_LIMIT at TIMB_FREQ Hz. 325 * Note: timer had better have been programmed before this is first used! 326 */ 327void 328delay(unsigned int n) 329{ 330 int ticks, otick, remaining; 331 332 /* 333 * Read the counter first, so that the rest of the setup overhead is 334 * counted. 335 */ 336 otick = MFP->mf_tbdr; 337 338 if (n <= UINT_MAX / TIMB_FREQ) { 339 /* 340 * For unsigned arithmetic, division can be replaced with 341 * multiplication with the inverse and a shift. 342 */ 343 remaining = n * TIMB_FREQ / 1000000; 344 } else { 345 /* This is a very long delay. 346 * Being slow here doesn't matter. 347 */ 348 remaining = (unsigned long long) n * TIMB_FREQ / 1000000; 349 } 350 351 while (remaining > 0) { 352 ticks = MFP->mf_tbdr; 353 if (ticks > otick) 354 remaining -= TIMB_LIMIT - (ticks - otick); 355 else 356 remaining -= otick - ticks; 357 otick = ticks; 358 } 359} 360 361#ifdef GPROF 362/* 363 * profclock() is expanded in line in lev6intr() unless profiling kernel. 364 * Assumes it is called with clock interrupts blocked. 365 */ 366profclock(void *pc, int ps) 367{ 368 369 /* 370 * Came from user mode. 371 * If this process is being profiled record the tick. 372 */ 373 if (USERMODE(ps)) { 374 if (p->p_stats.p_prof.pr_scale) 375 addupc(pc, &curproc->p_stats.p_prof, 1); 376 } 377 /* 378 * Came from kernel (supervisor) mode. 379 * If we are profiling the kernel, record the tick. 380 */ 381 else if (profiling < 2) { 382 register int s = pc - s_lowpc; 383 384 if (s < s_textsize) 385 kcount[s / (HISTFRACTION * sizeof(*kcount))]++; 386 } 387 /* 388 * Kernel profiling was on but has been disabled. 389 * Mark as no longer profiling kernel and if all profiling done, 390 * disable the clock. 391 */ 392 if (profiling && (profon & PRF_KERNEL)) { 393 profon &= ~PRF_KERNEL; 394 if (profon == PRF_NONE) 395 stopprofclock(); 396 } 397} 398#endif 399 400/*********************************************************************** 401 * Real Time Clock support * 402 ***********************************************************************/ 403 404u_int mc146818_read(void *cookie, u_int regno) 405{ 406 struct rtc *rtc = cookie; 407 408 rtc->rtc_regno = regno; 409 return rtc->rtc_data & 0xff; 410} 411 412void mc146818_write(void *cookie, u_int regno, u_int value) 413{ 414 struct rtc *rtc = cookie; 415 416 rtc->rtc_regno = regno; 417 rtc->rtc_data = value; 418} 419 420static int 421atari_rtc_get(todr_chip_handle_t todr, struct clock_ymdhms *dtp) 422{ 423 int sps; 424 mc_todregs clkregs; 425 u_int regb; 426 427 sps = splhigh(); 428 regb = mc146818_read(RTC, MC_REGB); 429 MC146818_GETTOD(RTC, &clkregs); 430 splx(sps); 431 432 regb &= MC_REGB_24HR|MC_REGB_BINARY; 433 if (regb != (MC_REGB_24HR|MC_REGB_BINARY)) { 434 printf("Error: Nonstandard RealTimeClock Configuration -" 435 " value ignored\n" 436 " A write to /dev/rtc will correct this.\n"); 437 return 0; 438 } 439 if (clkregs[MC_SEC] > 59) 440 return -1; 441 if (clkregs[MC_MIN] > 59) 442 return -1; 443 if (clkregs[MC_HOUR] > 23) 444 return -1; 445 if (range_test(clkregs[MC_DOM], 1, 31)) 446 return -1; 447 if (range_test(clkregs[MC_MONTH], 1, 12)) 448 return -1; 449 if (clkregs[MC_YEAR] > 99) 450 return -1; 451 452 dtp->dt_year = clkregs[MC_YEAR] + GEMSTARTOFTIME; 453 dtp->dt_mon = clkregs[MC_MONTH]; 454 dtp->dt_day = clkregs[MC_DOM]; 455 dtp->dt_hour = clkregs[MC_HOUR]; 456 dtp->dt_min = clkregs[MC_MIN]; 457 dtp->dt_sec = clkregs[MC_SEC]; 458 459 return 0; 460} 461 462static int 463atari_rtc_set(todr_chip_handle_t todr, struct clock_ymdhms *dtp) 464{ 465 int s; 466 mc_todregs clkregs; 467 468 clkregs[MC_YEAR] = dtp->dt_year - GEMSTARTOFTIME; 469 clkregs[MC_MONTH] = dtp->dt_mon; 470 clkregs[MC_DOM] = dtp->dt_day; 471 clkregs[MC_HOUR] = dtp->dt_hour; 472 clkregs[MC_MIN] = dtp->dt_min; 473 clkregs[MC_SEC] = dtp->dt_sec; 474 475 s = splclock(); 476 MC146818_PUTTOD(RTC, &clkregs); 477 splx(s); 478 479 return 0; 480} 481 482/*********************************************************************** 483 * RTC-device support * 484 ***********************************************************************/ 485static int 486rtcopen(dev_t dev, int flag, int mode, struct lwp *l) 487{ 488 int unit = minor(dev); 489 struct clock_softc *sc; 490 491 sc = device_lookup_private(&clock_cd, unit); 492 if (sc == NULL) 493 return ENXIO; 494 if (sc->sc_flags & RTC_OPEN) 495 return EBUSY; 496 497 sc->sc_flags = RTC_OPEN; 498 return 0; 499} 500 501static int 502rtcclose(dev_t dev, int flag, int mode, struct lwp *l) 503{ 504 int unit = minor(dev); 505 struct clock_softc *sc = device_lookup_private(&clock_cd, unit); 506 507 sc->sc_flags = 0; 508 return 0; 509} 510 511static int 512rtcread(dev_t dev, struct uio *uio, int flags) 513{ 514 mc_todregs clkregs; 515 int s, length; 516 char buffer[16 + 1]; 517 518 s = splhigh(); 519 MC146818_GETTOD(RTC, &clkregs); 520 splx(s); 521 522 snprintf(buffer, sizeof(buffer), "%4d%02d%02d%02d%02d.%02d\n", 523 clkregs[MC_YEAR] + GEMSTARTOFTIME, 524 clkregs[MC_MONTH], clkregs[MC_DOM], 525 clkregs[MC_HOUR], clkregs[MC_MIN], clkregs[MC_SEC]); 526 527 if (uio->uio_offset > strlen(buffer)) 528 return 0; 529 530 length = strlen(buffer) - uio->uio_offset; 531 if (length > uio->uio_resid) 532 length = uio->uio_resid; 533 534 return uiomove((void *)buffer, length, uio); 535} 536 537static int 538twodigits(char *buffer, int pos) 539{ 540 int result = 0; 541 542 if (buffer[pos] >= '0' && buffer[pos] <= '9') 543 result = (buffer[pos] - '0') * 10; 544 if (buffer[pos+1] >= '0' && buffer[pos+1] <= '9') 545 result += (buffer[pos+1] - '0'); 546 return result; 547} 548 549static int 550rtcwrite(dev_t dev, struct uio *uio, int flags) 551{ 552 mc_todregs clkregs; 553 int s, length, error; 554 char buffer[16]; 555 556 /* 557 * We require atomic updates! 558 */ 559 length = uio->uio_resid; 560 if (uio->uio_offset || (length != sizeof(buffer) 561 && length != sizeof(buffer) - 1)) 562 return EINVAL; 563 564 if ((error = uiomove((void *)buffer, sizeof(buffer), uio))) 565 return error; 566 567 if (length == sizeof(buffer) && buffer[sizeof(buffer) - 1] != '\n') 568 return EINVAL; 569 570 s = splclock(); 571 mc146818_write(RTC, MC_REGB, 572 mc146818_read(RTC, MC_REGB) | MC_REGB_24HR | MC_REGB_BINARY); 573 MC146818_GETTOD(RTC, &clkregs); 574 splx(s); 575 576 clkregs[MC_SEC] = twodigits(buffer, 13); 577 clkregs[MC_MIN] = twodigits(buffer, 10); 578 clkregs[MC_HOUR] = twodigits(buffer, 8); 579 clkregs[MC_DOM] = twodigits(buffer, 6); 580 clkregs[MC_MONTH] = twodigits(buffer, 4); 581 s = twodigits(buffer, 0) * 100 + twodigits(buffer, 2); 582 clkregs[MC_YEAR] = s - GEMSTARTOFTIME; 583 584 s = splclock(); 585 MC146818_PUTTOD(RTC, &clkregs); 586 splx(s); 587 588 return 0; 589} 590