Annotation of Gnu-Mach/chips/mc_clock.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.