Annotation of Gnu-Mach/chips/mc_clock.c, revision 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.