diff options
Diffstat (limited to 'chips/mc_clock.c')
-rw-r--r-- | chips/mc_clock.c | 516 |
1 files changed, 0 insertions, 516 deletions
diff --git a/chips/mc_clock.c b/chips/mc_clock.c deleted file mode 100644 index 15fa049..0000000 --- a/chips/mc_clock.c +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1991,1990 Carnegie Mellon University - * All Rights Reserved. - * - * Permission to use, copy, modify and distribute this software and its - * documentation is hereby granted, provided that both the copyright - * notice and this permission notice appear in all copies of the - * software, derivative works or modified versions, and any portions - * thereof, and that both notices appear in supporting documentation. - * - * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" - * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR - * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. - * - * Carnegie Mellon requests users of this software to return to - * - * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU - * School of Computer Science - * Carnegie Mellon University - * Pittsburgh PA 15213-3890 - * - * any improvements or extensions that they make and grant Carnegie Mellon - * the rights to redistribute these changes. - */ -/* - * File: mc_clock.c - * Author: Alessandro Forin - * Date: 8/90 - * - * Driver for the MC146818 Clock - */ - -#include <mc.h> -#if NMC > 0 -#include <platforms.h> - -#include <mach/std_types.h> -#include <machine/machspl.h> /* spl definitions */ -#include <chips/busses.h> - -#include <sys/time.h> -#include <kern/time_out.h> -#include <chips/mc_clock.h> - -#ifdef DECSTATION -#include <mips/mips_cpu.h> -#include <mips/clock.h> -#endif /*DECSTATION*/ - -#ifdef FLAMINGO -#include <alpha/clock.h> -#endif /*FLAMINGO*/ - -#define private static -#define public - - -/* Architecture-specific defines */ - -#ifdef DECSTATION - -#define MC_DEFAULT_ADDRESS (mc_clock_ram_t *)PHYS_TO_K1SEG(0x1d000000) -#define MC_DOES_DELAYS 1 - -/* - * Both the Pmax and the 3max implementations of the chip map - * bytes of the chip's RAM to 32 bit words (low byte). - * For convenience, we redefine here the chip's RAM layout - * making padding explicit. - */ - -typedef struct { - volatile unsigned char mc_second; - char pad0[3]; - volatile unsigned char mc_alarm_second; - char pad1[3]; - volatile unsigned char mc_minute; - char pad2[3]; - volatile unsigned char mc_alarm_minute; - char pad3[3]; - volatile unsigned char mc_hour; - char pad4[3]; - volatile unsigned char mc_alarm_hour; - char pad5[3]; - volatile unsigned char mc_day_of_week; - char pad6[3]; - volatile unsigned char mc_day_of_month; - char pad7[3]; - volatile unsigned char mc_month; - char pad8[3]; - volatile unsigned char mc_year; - char pad9[3]; - volatile unsigned char mc_register_A; - char pad10[3]; - volatile unsigned char mc_register_B; - char pad11[3]; - volatile unsigned char mc_register_C; - char pad12[3]; - volatile unsigned char mc_register_D; - char pad13[3]; - unsigned char mc_non_volatile_ram[50 * 4]; /* unused */ -} mc_clock_ram_t; - -#define MC_CLOCK_PADDED 1 - -#endif /*DECSTATION*/ - - -#ifdef FLAMINGO -#define MC_DEFAULT_ADDRESS 0L - -/* padded, later */ - -#endif /* FLAMINGO */ - - - -#ifndef MC_CLOCK_PADDED -typedef mc_clock_t mc_clock_ram_t; /* No padding needed */ -#endif - -/* - * Functions provided herein - */ -int mc_probe( vm_offset_t addr, struct bus_ctlr * ); -private void mc_attach(); - -int mc_intr(); - -void mc_open(), mc_close(), mc_write(); -private unsigned int mc_read(); - -private void mc_wait_for_uip( mc_clock_ram_t *clock ); - - -/* - * Status - */ -boolean_t mc_running = FALSE; -boolean_t mc_new_century = FALSE; /* "year" info overfloweth */ - -private int days_per_month[12] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -private unsigned int mc_read(); /* forward */ -private void mc_wait_for_uip(); - -/* - * Where is the chip's RAM mapped - */ -private mc_clock_ram_t *rt_clock = MC_DEFAULT_ADDRESS; - -/* - * (Auto?)Configuration - */ -private vm_offset_t mc_std[NMC] = { 0 }; -private struct bus_device *mc_info[NMC]; - -struct bus_driver mc_driver = - { mc_probe, 0, mc_attach, 0, mc_std, "mc", mc_info, }; - - -mc_probe(vm_offset_t addr, struct bus_ctlr *ui) -{ - rt_clock = (mc_clock_ram_t *)addr; - return 1; -} - -private void -mc_attach() -{ - printf(": MC146818 or like Time-Of-Year chip"); -} - -/* - * Interrupt routine - */ -#if MC_DOES_DELAYS - -private int config_step = 3; -private volatile int had_intr; - -mc_intr(spllevel) - spl_t spllevel; -{ - /* - * Interrupt flags are read-to-clear. - */ - if (config_step > 2) - return (rt_clock->mc_register_C & MC_REG_C_IRQF); - had_intr = (rt_clock->mc_register_C & MC_REG_C_IRQF) ? 1 : 0; - if (config_step++ == 0) - accurate_config_delay(spllevel); - return had_intr; -} -#else /* MC_DOES_DELAYS */ - -mc_intr() -{ - return (rt_clock->mc_register_C); /* clear intr */ -} - -#endif /* MC_DOES_DELAYS */ - -/* - * Start real-time clock. - */ -void -mc_open() -{ - /* - * All we should need to do is to enable interrupts, but - * since we do not know what OS last ran on this box - * we'll reset it all over again. Just kidding.. - */ - unsigned unix_seconds_now; - - /* - * Check for battery backup power. If we do not have it, - * warn the user. Time will be bogus only after power up. - */ - if ((rt_clock->mc_register_D & MC_REG_D_VRT) == 0) - printf("WARNING: clock batteries are low\n"); - - /* - * Read the current time settings, check if the year info - * has been screwed up. - */ - unix_seconds_now = mc_read(); - - if (unix_seconds_now < (SECYR * (1990 - YRREF))) - printf("The prom has clobbered the clock\n"); - - time.tv_sec = (long)unix_seconds_now; - mc_write(); - - mc_running = TRUE; -} - -void -mc_close() -{ - /* - * Disable interrupts, but keep the chip running. - * Note we are called at splhigh and an interrupt - * might be pending already. - */ - - mc_intr(0); - rt_clock->mc_register_B &= ~(MC_REG_B_UIE|MC_REG_B_AIE|MC_REG_B_PIE); - mc_running = FALSE; -#if MC_DOES_DELAYS - config_step = 0; -#endif -} - - -/* - * Set time-of-day. Must be called at splhigh() - */ -void -mc_write() -{ - register mc_clock_ram_t *clock = rt_clock; - register unsigned years, months, days, hours, minutes, seconds; - register unsigned unix_seconds = time.tv_sec; - int frequence_selector, temp; - int bogus_hz = 0; - - /* - * Convert U*x time into absolute time - */ - - years = YRREF; - while (1) { - seconds = SECYR; - if (LEAPYEAR(years)) - seconds += SECDAY; - if (unix_seconds < seconds) - break; - unix_seconds -= seconds; - years++; - } - - months = 0; - while (1) { - seconds = days_per_month[months++] * SECDAY; - if (months == 2 /* February */ && LEAPYEAR(years)) - seconds += SECDAY; - if (unix_seconds < seconds) - break; - unix_seconds -= seconds; - } - - days = unix_seconds / SECDAY; - unix_seconds -= SECDAY * days++; - - hours = unix_seconds / SECHOUR; - unix_seconds -= SECHOUR * hours; - - minutes = unix_seconds / SECMIN; - unix_seconds -= SECMIN * minutes; - - seconds = unix_seconds; - - /* - * Trim years into 0-99 range. - */ - if ((years -= 1900) > 99) { - years -= 100; - mc_new_century = TRUE; - } - - /* - * Check for "hot dates" - */ - if (days >= 28 && days <= 30 && - hours == 23 && minutes == 59 && - seconds >= 58) - seconds = 57; - - /* - * Select the interrupt frequency based on system params - */ - switch (hz) { - case 1024: - frequence_selector = MC_BASE_32_KHz | MC_RATE_1024_Hz; - break; - case 512: - frequence_selector = MC_BASE_32_KHz | MC_RATE_512_Hz; - break; - case 256: - frequence_selector = MC_BASE_32_KHz | MC_RATE_256_Hz; - break; - case 128: - frequence_selector = MC_BASE_32_KHz | MC_RATE_128_Hz; - break; - case 64: -default_frequence: - frequence_selector = MC_BASE_32_KHz | MC_RATE_64_Hz; - break; - default: - bogus_hz = hz; - hz = 64; - tick = 1000000 / 64; - goto default_frequence; - } - - /* - * Stop updates while we fix it - */ - mc_wait_for_uip(clock); - clock->mc_register_B = MC_REG_B_STOP; - wbflush(); - - /* - * Ack any pending interrupts - */ - temp = clock->mc_register_C; - - /* - * Reset the frequency divider, in case we are changing it. - */ - clock->mc_register_A = MC_BASE_RESET; - - /* - * Now update the time - */ - clock->mc_second = seconds; - clock->mc_minute = minutes; - clock->mc_hour = hours; - clock->mc_day_of_month = days; - clock->mc_month = months; - clock->mc_year = years; - - /* - * Spec says the VRT bit can be validated, but does not say how. I - * assume it is via reading the register. - */ - temp = clock->mc_register_D; - - /* - * Reconfigure the chip and get it started again - */ - clock->mc_register_A = frequence_selector; - clock->mc_register_B = MC_REG_B_24HM | MC_REG_B_DM | MC_REG_B_PIE; - - /* - * Print warnings, if we have to - */ - if (bogus_hz != 0) - printf("Unacceptable value (%d Hz) for hz, reset to %d Hz\n", - bogus_hz, hz); -} - - -/* - * Internal functions - */ - -private void -mc_wait_for_uip(clock) - mc_clock_ram_t *clock; -{ - while (clock->mc_register_A & MC_REG_A_UIP) - delay(MC_UPD_MINIMUM >> 2); -} - -private unsigned int -mc_read() -{ - /* - * Note we only do this at boot time - */ - register unsigned years, months, days, hours, minutes, seconds; - register mc_clock_ram_t *clock = rt_clock;; - - /* - * If the chip is updating, wait - */ - mc_wait_for_uip(clock); - - years = clock->mc_year; - months = clock->mc_month; - days = clock->mc_day_of_month; - hours = clock->mc_hour; - minutes = clock->mc_minute; - seconds = clock->mc_second; - - /* - * Convert to Unix time - */ - seconds += minutes * SECMIN; - seconds += hours * SECHOUR; - seconds += (days - 1) * SECDAY; - if (months > 2 /* February */ && LEAPYEAR(years)) - seconds += SECDAY; - while (months > 1) - seconds += days_per_month[--months - 1]; - - /* - * Note that in ten years from today (Aug,1990) the new century will - * cause the trouble that mc_new_century attempts to avoid. - */ - if (mc_new_century) - years += 100; - years += 1900; /* chip base year in YRREF's century */ - - for (--years; years >= YRREF; years--) { - seconds += SECYR; - if (LEAPYEAR(years)) - seconds += SECDAY; - } - - return seconds; -} - -#ifdef MC_DOES_DELAYS - -/* - * Timed delays - */ -extern unsigned int cpu_speed; - -void -config_delay(speed) -{ - /* - * This is just an initial estimate, later on with the clock - * running we'll tune it more accurately. - */ - cpu_speed = speed; -} - -accurate_config_delay(spllevel) - spl_t spllevel; -{ - register unsigned int i; - register spl_t s; - int inner_loop_count; - -#ifdef mips - /* find "spllevel - 1" */ - s = spllevel | ((spllevel >> 1) & SR_INT_MASK); - splx(s); -#else -#endif - - /* wait till we have an interrupt pending */ - had_intr = 0; - while (!had_intr) - continue; - - had_intr = 0; - i = delay_timing_function(1, &had_intr, &inner_loop_count); - - splx(spllevel); - - i *= hz; - cpu_speed = i / (inner_loop_count * 1000000); - - /* roundup clock speed */ - i /= 100000; - if ((i % 10) >= 5) - i += 5; - printf("Estimating CPU clock at %d Mhz\n", i / 10); - if (isa_pmax() && cpu_speed != MC_DELAY_PMAX) { - printf("%s\n", "This machine looks like a DEC 2100"); - machine_slot[cpu_number()].cpu_subtype = CPU_SUBTYPE_MIPS_R2000; - } -} -#endif /* MC_DOES_DELAYS */ - -#endif NMC > 0 |