|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990 Carnegie Mellon University ! 4: * All Rights Reserved. ! 5: * ! 6: * Permission to use, copy, modify and distribute this software and its ! 7: * documentation is hereby granted, provided that both the copyright ! 8: * notice and this permission notice appear in all copies of the ! 9: * software, derivative works or modified versions, and any portions ! 10: * thereof, and that both notices appear in supporting documentation. ! 11: * ! 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 15: * ! 16: * Carnegie Mellon requests users of this software to return to ! 17: * ! 18: * Software Distribution Coordinator or [email protected] ! 19: * School of Computer Science ! 20: * Carnegie Mellon University ! 21: * Pittsburgh PA 15213-3890 ! 22: * ! 23: * any improvements or extensions that they make and grant Carnegie Mellon ! 24: * the rights to redistribute these changes. ! 25: */ ! 26: /* ! 27: * File: mc_clock.c ! 28: * Author: Alessandro Forin ! 29: * Date: 8/90 ! 30: * ! 31: * Driver for the MC146818 Clock ! 32: */ ! 33: ! 34: #include <mc.h> ! 35: #if NMC > 0 ! 36: #include <platforms.h> ! 37: ! 38: #include <mach/std_types.h> ! 39: #include <machine/machspl.h> /* spl definitions */ ! 40: #include <chips/busses.h> ! 41: ! 42: #include <sys/time.h> ! 43: #include <kern/time_out.h> ! 44: #include <chips/mc_clock.h> ! 45: ! 46: #ifdef DECSTATION ! 47: #include <mips/mips_cpu.h> ! 48: #include <mips/clock.h> ! 49: #endif /*DECSTATION*/ ! 50: ! 51: #ifdef FLAMINGO ! 52: #include <alpha/clock.h> ! 53: #endif /*FLAMINGO*/ ! 54: ! 55: #define private static ! 56: #define public ! 57: ! 58: ! 59: /* Architecture-specific defines */ ! 60: ! 61: #ifdef DECSTATION ! 62: ! 63: #define MC_DEFAULT_ADDRESS (mc_clock_ram_t *)PHYS_TO_K1SEG(0x1d000000) ! 64: #define MC_DOES_DELAYS 1 ! 65: ! 66: /* ! 67: * Both the Pmax and the 3max implementations of the chip map ! 68: * bytes of the chip's RAM to 32 bit words (low byte). ! 69: * For convenience, we redefine here the chip's RAM layout ! 70: * making padding explicit. ! 71: */ ! 72: ! 73: typedef struct { ! 74: volatile unsigned char mc_second; ! 75: char pad0[3]; ! 76: volatile unsigned char mc_alarm_second; ! 77: char pad1[3]; ! 78: volatile unsigned char mc_minute; ! 79: char pad2[3]; ! 80: volatile unsigned char mc_alarm_minute; ! 81: char pad3[3]; ! 82: volatile unsigned char mc_hour; ! 83: char pad4[3]; ! 84: volatile unsigned char mc_alarm_hour; ! 85: char pad5[3]; ! 86: volatile unsigned char mc_day_of_week; ! 87: char pad6[3]; ! 88: volatile unsigned char mc_day_of_month; ! 89: char pad7[3]; ! 90: volatile unsigned char mc_month; ! 91: char pad8[3]; ! 92: volatile unsigned char mc_year; ! 93: char pad9[3]; ! 94: volatile unsigned char mc_register_A; ! 95: char pad10[3]; ! 96: volatile unsigned char mc_register_B; ! 97: char pad11[3]; ! 98: volatile unsigned char mc_register_C; ! 99: char pad12[3]; ! 100: volatile unsigned char mc_register_D; ! 101: char pad13[3]; ! 102: unsigned char mc_non_volatile_ram[50 * 4]; /* unused */ ! 103: } mc_clock_ram_t; ! 104: ! 105: #define MC_CLOCK_PADDED 1 ! 106: ! 107: #endif /*DECSTATION*/ ! 108: ! 109: ! 110: #ifdef FLAMINGO ! 111: #define MC_DEFAULT_ADDRESS 0L ! 112: ! 113: /* padded, later */ ! 114: ! 115: #endif /* FLAMINGO */ ! 116: ! 117: ! 118: ! 119: #ifndef MC_CLOCK_PADDED ! 120: typedef mc_clock_t mc_clock_ram_t; /* No padding needed */ ! 121: #endif ! 122: ! 123: /* ! 124: * Functions provided herein ! 125: */ ! 126: int mc_probe( vm_offset_t addr, struct bus_ctlr * ); ! 127: private void mc_attach(); ! 128: ! 129: int mc_intr(); ! 130: ! 131: void mc_open(), mc_close(), mc_write(); ! 132: private unsigned int mc_read(); ! 133: ! 134: private void mc_wait_for_uip( mc_clock_ram_t *clock ); ! 135: ! 136: ! 137: /* ! 138: * Status ! 139: */ ! 140: boolean_t mc_running = FALSE; ! 141: boolean_t mc_new_century = FALSE; /* "year" info overfloweth */ ! 142: ! 143: private int days_per_month[12] = { ! 144: 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ! 145: }; ! 146: ! 147: private unsigned int mc_read(); /* forward */ ! 148: private void mc_wait_for_uip(); ! 149: ! 150: /* ! 151: * Where is the chip's RAM mapped ! 152: */ ! 153: private mc_clock_ram_t *rt_clock = MC_DEFAULT_ADDRESS; ! 154: ! 155: /* ! 156: * (Auto?)Configuration ! 157: */ ! 158: private vm_offset_t mc_std[NMC] = { 0 }; ! 159: private struct bus_device *mc_info[NMC]; ! 160: ! 161: struct bus_driver mc_driver = ! 162: { mc_probe, 0, mc_attach, 0, mc_std, "mc", mc_info, }; ! 163: ! 164: ! 165: mc_probe(vm_offset_t addr, struct bus_ctlr *ui) ! 166: { ! 167: rt_clock = (mc_clock_ram_t *)addr; ! 168: return 1; ! 169: } ! 170: ! 171: private void ! 172: mc_attach() ! 173: { ! 174: printf(": MC146818 or like Time-Of-Year chip"); ! 175: } ! 176: ! 177: /* ! 178: * Interrupt routine ! 179: */ ! 180: #if MC_DOES_DELAYS ! 181: ! 182: private int config_step = 3; ! 183: private volatile int had_intr; ! 184: ! 185: mc_intr(spllevel) ! 186: spl_t spllevel; ! 187: { ! 188: /* ! 189: * Interrupt flags are read-to-clear. ! 190: */ ! 191: if (config_step > 2) ! 192: return (rt_clock->mc_register_C & MC_REG_C_IRQF); ! 193: had_intr = (rt_clock->mc_register_C & MC_REG_C_IRQF) ? 1 : 0; ! 194: if (config_step++ == 0) ! 195: accurate_config_delay(spllevel); ! 196: return had_intr; ! 197: } ! 198: #else /* MC_DOES_DELAYS */ ! 199: ! 200: mc_intr() ! 201: { ! 202: return (rt_clock->mc_register_C); /* clear intr */ ! 203: } ! 204: ! 205: #endif /* MC_DOES_DELAYS */ ! 206: ! 207: /* ! 208: * Start real-time clock. ! 209: */ ! 210: void ! 211: mc_open() ! 212: { ! 213: /* ! 214: * All we should need to do is to enable interrupts, but ! 215: * since we do not know what OS last ran on this box ! 216: * we'll reset it all over again. Just kidding.. ! 217: */ ! 218: unsigned unix_seconds_now; ! 219: ! 220: /* ! 221: * Check for battery backup power. If we do not have it, ! 222: * warn the user. Time will be bogus only after power up. ! 223: */ ! 224: if ((rt_clock->mc_register_D & MC_REG_D_VRT) == 0) ! 225: printf("WARNING: clock batteries are low\n"); ! 226: ! 227: /* ! 228: * Read the current time settings, check if the year info ! 229: * has been screwed up. ! 230: */ ! 231: unix_seconds_now = mc_read(); ! 232: ! 233: if (unix_seconds_now < (SECYR * (1990 - YRREF))) ! 234: printf("The prom has clobbered the clock\n"); ! 235: ! 236: time.tv_sec = (long)unix_seconds_now; ! 237: mc_write(); ! 238: ! 239: mc_running = TRUE; ! 240: } ! 241: ! 242: void ! 243: mc_close() ! 244: { ! 245: /* ! 246: * Disable interrupts, but keep the chip running. ! 247: * Note we are called at splhigh and an interrupt ! 248: * might be pending already. ! 249: */ ! 250: ! 251: mc_intr(0); ! 252: rt_clock->mc_register_B &= ~(MC_REG_B_UIE|MC_REG_B_AIE|MC_REG_B_PIE); ! 253: mc_running = FALSE; ! 254: #if MC_DOES_DELAYS ! 255: config_step = 0; ! 256: #endif ! 257: } ! 258: ! 259: ! 260: /* ! 261: * Set time-of-day. Must be called at splhigh() ! 262: */ ! 263: void ! 264: mc_write() ! 265: { ! 266: register mc_clock_ram_t *clock = rt_clock; ! 267: register unsigned years, months, days, hours, minutes, seconds; ! 268: register unsigned unix_seconds = time.tv_sec; ! 269: int frequence_selector, temp; ! 270: int bogus_hz = 0; ! 271: ! 272: /* ! 273: * Convert U*x time into absolute time ! 274: */ ! 275: ! 276: years = YRREF; ! 277: while (1) { ! 278: seconds = SECYR; ! 279: if (LEAPYEAR(years)) ! 280: seconds += SECDAY; ! 281: if (unix_seconds < seconds) ! 282: break; ! 283: unix_seconds -= seconds; ! 284: years++; ! 285: } ! 286: ! 287: months = 0; ! 288: while (1) { ! 289: seconds = days_per_month[months++] * SECDAY; ! 290: if (months == 2 /* February */ && LEAPYEAR(years)) ! 291: seconds += SECDAY; ! 292: if (unix_seconds < seconds) ! 293: break; ! 294: unix_seconds -= seconds; ! 295: } ! 296: ! 297: days = unix_seconds / SECDAY; ! 298: unix_seconds -= SECDAY * days++; ! 299: ! 300: hours = unix_seconds / SECHOUR; ! 301: unix_seconds -= SECHOUR * hours; ! 302: ! 303: minutes = unix_seconds / SECMIN; ! 304: unix_seconds -= SECMIN * minutes; ! 305: ! 306: seconds = unix_seconds; ! 307: ! 308: /* ! 309: * Trim years into 0-99 range. ! 310: */ ! 311: if ((years -= 1900) > 99) { ! 312: years -= 100; ! 313: mc_new_century = TRUE; ! 314: } ! 315: ! 316: /* ! 317: * Check for "hot dates" ! 318: */ ! 319: if (days >= 28 && days <= 30 && ! 320: hours == 23 && minutes == 59 && ! 321: seconds >= 58) ! 322: seconds = 57; ! 323: ! 324: /* ! 325: * Select the interrupt frequency based on system params ! 326: */ ! 327: switch (hz) { ! 328: case 1024: ! 329: frequence_selector = MC_BASE_32_KHz | MC_RATE_1024_Hz; ! 330: break; ! 331: case 512: ! 332: frequence_selector = MC_BASE_32_KHz | MC_RATE_512_Hz; ! 333: break; ! 334: case 256: ! 335: frequence_selector = MC_BASE_32_KHz | MC_RATE_256_Hz; ! 336: break; ! 337: case 128: ! 338: frequence_selector = MC_BASE_32_KHz | MC_RATE_128_Hz; ! 339: break; ! 340: case 64: ! 341: default_frequence: ! 342: frequence_selector = MC_BASE_32_KHz | MC_RATE_64_Hz; ! 343: break; ! 344: default: ! 345: bogus_hz = hz; ! 346: hz = 64; ! 347: tick = 1000000 / 64; ! 348: goto default_frequence; ! 349: } ! 350: ! 351: /* ! 352: * Stop updates while we fix it ! 353: */ ! 354: mc_wait_for_uip(clock); ! 355: clock->mc_register_B = MC_REG_B_STOP; ! 356: wbflush(); ! 357: ! 358: /* ! 359: * Ack any pending interrupts ! 360: */ ! 361: temp = clock->mc_register_C; ! 362: ! 363: /* ! 364: * Reset the frequency divider, in case we are changing it. ! 365: */ ! 366: clock->mc_register_A = MC_BASE_RESET; ! 367: ! 368: /* ! 369: * Now update the time ! 370: */ ! 371: clock->mc_second = seconds; ! 372: clock->mc_minute = minutes; ! 373: clock->mc_hour = hours; ! 374: clock->mc_day_of_month = days; ! 375: clock->mc_month = months; ! 376: clock->mc_year = years; ! 377: ! 378: /* ! 379: * Spec says the VRT bit can be validated, but does not say how. I ! 380: * assume it is via reading the register. ! 381: */ ! 382: temp = clock->mc_register_D; ! 383: ! 384: /* ! 385: * Reconfigure the chip and get it started again ! 386: */ ! 387: clock->mc_register_A = frequence_selector; ! 388: clock->mc_register_B = MC_REG_B_24HM | MC_REG_B_DM | MC_REG_B_PIE; ! 389: ! 390: /* ! 391: * Print warnings, if we have to ! 392: */ ! 393: if (bogus_hz != 0) ! 394: printf("Unacceptable value (%d Hz) for hz, reset to %d Hz\n", ! 395: bogus_hz, hz); ! 396: } ! 397: ! 398: ! 399: /* ! 400: * Internal functions ! 401: */ ! 402: ! 403: private void ! 404: mc_wait_for_uip(clock) ! 405: mc_clock_ram_t *clock; ! 406: { ! 407: while (clock->mc_register_A & MC_REG_A_UIP) ! 408: delay(MC_UPD_MINIMUM >> 2); ! 409: } ! 410: ! 411: private unsigned int ! 412: mc_read() ! 413: { ! 414: /* ! 415: * Note we only do this at boot time ! 416: */ ! 417: register unsigned years, months, days, hours, minutes, seconds; ! 418: register mc_clock_ram_t *clock = rt_clock;; ! 419: ! 420: /* ! 421: * If the chip is updating, wait ! 422: */ ! 423: mc_wait_for_uip(clock); ! 424: ! 425: years = clock->mc_year; ! 426: months = clock->mc_month; ! 427: days = clock->mc_day_of_month; ! 428: hours = clock->mc_hour; ! 429: minutes = clock->mc_minute; ! 430: seconds = clock->mc_second; ! 431: ! 432: /* ! 433: * Convert to Unix time ! 434: */ ! 435: seconds += minutes * SECMIN; ! 436: seconds += hours * SECHOUR; ! 437: seconds += (days - 1) * SECDAY; ! 438: if (months > 2 /* February */ && LEAPYEAR(years)) ! 439: seconds += SECDAY; ! 440: while (months > 1) ! 441: seconds += days_per_month[--months - 1]; ! 442: ! 443: /* ! 444: * Note that in ten years from today (Aug,1990) the new century will ! 445: * cause the trouble that mc_new_century attempts to avoid. ! 446: */ ! 447: if (mc_new_century) ! 448: years += 100; ! 449: years += 1900; /* chip base year in YRREF's century */ ! 450: ! 451: for (--years; years >= YRREF; years--) { ! 452: seconds += SECYR; ! 453: if (LEAPYEAR(years)) ! 454: seconds += SECDAY; ! 455: } ! 456: ! 457: return seconds; ! 458: } ! 459: ! 460: #ifdef MC_DOES_DELAYS ! 461: ! 462: /* ! 463: * Timed delays ! 464: */ ! 465: extern unsigned int cpu_speed; ! 466: ! 467: void ! 468: config_delay(speed) ! 469: { ! 470: /* ! 471: * This is just an initial estimate, later on with the clock ! 472: * running we'll tune it more accurately. ! 473: */ ! 474: cpu_speed = speed; ! 475: } ! 476: ! 477: accurate_config_delay(spllevel) ! 478: spl_t spllevel; ! 479: { ! 480: register unsigned int i; ! 481: register spl_t s; ! 482: int inner_loop_count; ! 483: ! 484: #ifdef mips ! 485: /* find "spllevel - 1" */ ! 486: s = spllevel | ((spllevel >> 1) & SR_INT_MASK); ! 487: splx(s); ! 488: #else ! 489: #endif ! 490: ! 491: /* wait till we have an interrupt pending */ ! 492: had_intr = 0; ! 493: while (!had_intr) ! 494: continue; ! 495: ! 496: had_intr = 0; ! 497: i = delay_timing_function(1, &had_intr, &inner_loop_count); ! 498: ! 499: splx(spllevel); ! 500: ! 501: i *= hz; ! 502: cpu_speed = i / (inner_loop_count * 1000000); ! 503: ! 504: /* roundup clock speed */ ! 505: i /= 100000; ! 506: if ((i % 10) >= 5) ! 507: i += 5; ! 508: printf("Estimating CPU clock at %d Mhz\n", i / 10); ! 509: if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) { ! 510: printf("%s\n", "This machine looks like a DEC 2100"); ! 511: machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000; ! 512: } ! 513: } ! 514: #endif /* MC_DOES_DELAYS */ ! 515: ! 516: #endif NMC > 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.