153981Sfujita /* 253981Sfujita * Copyright (c) 1988 University of Utah. 353981Sfujita * Copyright (c) 1992 OMRON Corporation. 453981Sfujita * Copyright (c) 1982, 1990, 1992 The Regents of the University of California. 553981Sfujita * All rights reserved. 653981Sfujita * 753981Sfujita * This code is derived from software contributed to Berkeley by 853981Sfujita * the Systems Programming Group of the University of Utah Computer 953981Sfujita * Science Department. 1053981Sfujita * 1153981Sfujita * %sccs.include.redist.c% 1253981Sfujita * 1353981Sfujita * from: Utah $Hdr: clock.c 1.18 91/01/21$ 1458695Sakito * from: hp300/hp300/clock.c 7.19 (Berkeley) 2/18/93 1553981Sfujita * 16*59975Sakito * @(#)clock.c 7.9 (Berkeley) 05/12/93 1753981Sfujita */ 1853981Sfujita 1956521Sbostic #include <sys/param.h> 2056521Sbostic #include <sys/kernel.h> 2153981Sfujita 2256521Sbostic #include <luna68k/luna68k/clockreg.h> 2356521Sbostic 2459945Sakito #ifdef LUNA2 2559945Sakito #include <machine/cpu.h> 2659945Sakito #endif 2759945Sakito 2855581Sfujita extern int clock_on; 2955581Sfujita 3053981Sfujita static int month_days[12] = { 3153981Sfujita 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 3253981Sfujita }; 3353981Sfujita struct bbc_tm *gmt_to_bbc(); 3453981Sfujita 3553981Sfujita volatile struct bbc *bbc = (struct bbc *)BBC_ADDR; 3659945Sakito #ifdef LUNA2 3759945Sakito volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR; 3859945Sakito #endif 3953981Sfujita 4053981Sfujita int battery_clock; 4153981Sfujita int battery_chkfg; 4253981Sfujita 4353981Sfujita /* 4453981Sfujita * Machine-dependent clock routines. 4553981Sfujita * 4653981Sfujita * Startrtclock just checks battry backuped clock 4753981Sfujita * (when it does not work, starts it). 4853981Sfujita * 4953981Sfujita * Enablertclock sets flag for clock interrupt. 5053981Sfujita * 5153981Sfujita * Inittodr initializes the time of day hardware which provides 5253981Sfujita * date functions. 5353981Sfujita * 5453981Sfujita * Resettodr restores the time of day hardware after a time change. 5553981Sfujita * 5653981Sfujita */ 5753981Sfujita 5853981Sfujita /* 5953981Sfujita * Start the real-time clock. 6053981Sfujita */ 6155581Sfujita cpu_initclocks() 6253981Sfujita { 6353981Sfujita static char *rtcstrings = "RTC"; /* For compat */ 6453981Sfujita 6556149Sakito /* set flag for clockintr. */ 6656149Sakito clock_on = 1; 6756149Sakito 6859945Sakito #ifdef LUNA2 6959945Sakito if (machineid == LUNA_II) { 7059945Sakito /* not yet */ 7159945Sakito battery_chkfg = 1; 7259945Sakito battery_clock = 1; 7359945Sakito return; 7459945Sakito } 7559945Sakito #endif 7659945Sakito 7753981Sfujita batterychk(); 7853981Sfujita if (!battery_clock) 7953981Sfujita return; 8053981Sfujita 8153981Sfujita if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */ 8253981Sfujita return; 8353981Sfujita 8453981Sfujita printf("Initialize Battery Backup Clock.\n"); 8553981Sfujita bbc->cal_ctl |= BBC_WRT; 8653981Sfujita bbc->cal_sec &= ~BBC_STOP; 8753981Sfujita bbc->cal_hour |= BBC_KICK; 8853981Sfujita bbc->cal_dow &= ~BBC_FRQ; 8953981Sfujita bbc->cal_ctl &= ~BBC_WRT; 9053981Sfujita DELAY(BBC_DELAY); 9153981Sfujita bbc->cal_ctl |= BBC_WRT; 9253981Sfujita bbc->cal_hour &= ~BBC_KICK; 9353981Sfujita bbc->cal_ctl &= ~BBC_WRT; 9459643Sakito strcpy(bbc->nvram.nv_calclock, rtcstrings); 9553981Sfujita } 9653981Sfujita 9755581Sfujita void 9855581Sfujita setstatclockrate(newhz) 9955581Sfujita int newhz; 10053981Sfujita { 10155581Sfujita } 10253981Sfujita 10355581Sfujita microtime(tvp) 10455581Sfujita register struct timeval *tvp; 10555581Sfujita { 10655581Sfujita int s = splhigh(); 10755581Sfujita 10855581Sfujita *tvp = time; 10955581Sfujita tvp->tv_usec += tick; 11055581Sfujita while (tvp->tv_usec > 1000000) { 11155581Sfujita tvp->tv_sec++; 11255581Sfujita tvp->tv_usec -= 1000000; 11355581Sfujita } 11455581Sfujita splx(s); 11553981Sfujita } 11653981Sfujita 11753981Sfujita /* 11853981Sfujita * Initialize the time of day register, based on the time base which is, e.g. 11953981Sfujita * from a filesystem. 12053981Sfujita */ 12153981Sfujita inittodr(base) 12253981Sfujita time_t base; 12353981Sfujita { 12453981Sfujita u_long timbuf = base; /* assume no battery clock exists */ 12553981Sfujita 12653981Sfujita /* 12753981Sfujita * bbc_to_gmt converts and stores the gmt in timbuf. 12853981Sfujita * If an error is detected in bbc_to_gmt, or if the filesystem 12953981Sfujita * time is more recent than the gmt time in the clock, 13053981Sfujita * then use the filesystem time and warn the user. 13153981Sfujita */ 13253981Sfujita if (!bbc_to_gmt(&timbuf) || timbuf < base) { 13353981Sfujita printf("WARNING: bad date in battery clock\n"); 13453981Sfujita timbuf = base; 13553981Sfujita } 13653981Sfujita if (base < 5*SECYR) { 13753981Sfujita printf("WARNING: preposterous time in file system"); 13853981Sfujita timbuf = 6*SECYR + 186*SECDAY + SECDAY/2; 13953981Sfujita printf(" -- CHECK AND RESET THE DATE!\n"); 14053981Sfujita } 14153981Sfujita 14253981Sfujita /* Battery clock does not store usec's, so forget about it. */ 14353981Sfujita time.tv_sec = timbuf; 14453981Sfujita } 14553981Sfujita 14653981Sfujita resettodr() 14753981Sfujita { 14853981Sfujita register int i,s; 14953981Sfujita register struct bbc_tm *tmptr; 15053981Sfujita 15153981Sfujita tmptr = gmt_to_bbc(time.tv_sec); 15253981Sfujita 15353981Sfujita s = splimp(); 15453981Sfujita 15553981Sfujita /* set bb-clock */ 15659945Sakito #ifdef LUNA2 15759945Sakito if (machineid == LUNA_II) { 15859945Sakito bbc2->cal_sec = tmptr->tm_sec; 15959945Sakito bbc2->cal_min = tmptr->tm_min; 16059945Sakito bbc2->cal_hour =tmptr->tm_hour; 16159945Sakito bbc2->cal_day = tmptr->tm_mday; 16259945Sakito bbc2->cal_mon = tmptr->tm_mon; 163*59975Sakito bbc2->cal_year = tmptr->tm_year; 16459945Sakito } else 16559945Sakito #endif 16659945Sakito { 16759945Sakito bbc->cal_ctl |= BBC_WRT; 16859945Sakito bbc->cal_sec = binary_to_bcd(tmptr->tm_sec); 16959945Sakito bbc->cal_min = binary_to_bcd(tmptr->tm_min); 17059945Sakito bbc->cal_hour = binary_to_bcd(tmptr->tm_hour); 17159945Sakito bbc->cal_day = binary_to_bcd(tmptr->tm_mday); 17259945Sakito bbc->cal_mon = binary_to_bcd(tmptr->tm_mon); 17359945Sakito bbc->cal_year = binary_to_bcd(tmptr->tm_year); 17459945Sakito bbc->cal_ctl &= ~BBC_WRT; 17559945Sakito } 17653981Sfujita 17753981Sfujita splx(s); 17853981Sfujita } 17953981Sfujita 18053981Sfujita struct bbc_tm * 18153981Sfujita gmt_to_bbc(tim) 18253981Sfujita long tim; 18353981Sfujita { 18453981Sfujita register int i; 18553981Sfujita register long hms, day; 18653981Sfujita static struct bbc_tm rt; 18753981Sfujita 18853981Sfujita day = tim / SECDAY; 18953981Sfujita hms = tim % SECDAY; 19053981Sfujita 19153981Sfujita /* Hours, minutes, seconds are easy */ 19253981Sfujita rt.tm_hour = hms / 3600; 19353981Sfujita rt.tm_min = (hms % 3600) / 60; 19453981Sfujita rt.tm_sec = (hms % 3600) % 60; 19553981Sfujita 19653981Sfujita /* Number of years in days */ 19753981Sfujita for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 19853981Sfujita day -= days_in_year(i); 19953981Sfujita rt.tm_year = i; 20053981Sfujita 20153981Sfujita /* Number of months in days left */ 20253981Sfujita if (leapyear(rt.tm_year)) 20353981Sfujita days_in_month(FEBRUARY) = 29; 20453981Sfujita for (i = 1; day >= days_in_month(i); i++) 20553981Sfujita day -= days_in_month(i); 20653981Sfujita days_in_month(FEBRUARY) = 28; 20753981Sfujita rt.tm_mon = i; 20853981Sfujita 20953981Sfujita /* Days are what is left over (+1) from all that. */ 21053981Sfujita rt.tm_mday = day + 1; 21153981Sfujita 21253981Sfujita return(&rt); 21353981Sfujita } 21453981Sfujita 21553981Sfujita bbc_to_gmt(timbuf) 21653981Sfujita u_long *timbuf; 21753981Sfujita { 21853981Sfujita register int i,s; 21953981Sfujita register u_long tmp; 22053981Sfujita int year, month, day, hour, min, sec; 22153981Sfujita 22253981Sfujita if (!battery_clock) 22353981Sfujita return(0); 22453981Sfujita 22553981Sfujita s = splimp(); 22653981Sfujita 22753981Sfujita /* read bb-clock */ 22859945Sakito #ifdef LUNA2 22959945Sakito if (machineid == LUNA_II) { 23059945Sakito sec = bbc2->cal_sec; 23159945Sakito min = bbc2->cal_min; 23259945Sakito hour = bbc2->cal_hour; 23359945Sakito day = bbc2->cal_day; 23459945Sakito month = bbc2->cal_mon; 23559945Sakito year = bbc2->cal_year + 1900; 23659945Sakito } else 23759945Sakito #endif 23859945Sakito { 23959945Sakito bbc->cal_ctl |= BBC_RD; 24059945Sakito sec = bcd_to_binary(bbc->cal_sec); 24159945Sakito min = bcd_to_binary(bbc->cal_min); 24259945Sakito hour = bcd_to_binary(bbc->cal_hour); 24359945Sakito day = bcd_to_binary(bbc->cal_day); 24459945Sakito month = bcd_to_binary(bbc->cal_mon); 24559945Sakito year = bcd_to_binary(bbc->cal_year) + 1900; 24659945Sakito bbc->cal_ctl &= ~BBC_RD; 24759945Sakito } 24859945Sakito 24953981Sfujita splx(s); 25053981Sfujita 25153981Sfujita range_test(hour, 0, 23); 25253981Sfujita range_test(day, 1, 31); 25353981Sfujita range_test(month, 1, 12); 25459945Sakito #if 1 /* limitted 2000 now ... */ 25553981Sfujita range_test(year, STARTOFTIME, 2000); 25659945Sakito #else 25759945Sakito if (year < 1970) { 25859945Sakito year += 100; 25959945Sakito } 26059945Sakito #endif 26153981Sfujita 26253981Sfujita tmp = 0; 26353981Sfujita 26453981Sfujita for (i = STARTOFTIME; i < year; i++) 26553981Sfujita tmp += days_in_year(i); 26653981Sfujita if (leapyear(year) && month > FEBRUARY) 26753981Sfujita tmp++; 26853981Sfujita 26953981Sfujita for (i = 1; i < month; i++) 27053981Sfujita tmp += days_in_month(i); 27153981Sfujita 27253981Sfujita tmp += (day - 1); 27353981Sfujita tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 27453981Sfujita 27553981Sfujita *timbuf = tmp; 27653981Sfujita return(1); 27753981Sfujita } 27853981Sfujita 27953981Sfujita batterychk() 28053981Sfujita { 28153981Sfujita static char btchkdata[] = "chk"; 28253981Sfujita 28359945Sakito #ifdef LUNA2 28459945Sakito if (machineid == LUNA_II) { 28559945Sakito /* not yet */ 28659945Sakito battery_chkfg = 1; 28759945Sakito battery_clock = 1; 28859945Sakito return; 28959945Sakito } 29059945Sakito #endif 29153981Sfujita /* if already checked, return */ 29253981Sfujita if (battery_chkfg) 29353981Sfujita return; 29453981Sfujita 29553981Sfujita battery_chkfg = 1; 29653981Sfujita if (badaddr((caddr_t)bbc, 2)) 29753981Sfujita return; 29853981Sfujita 29953981Sfujita strcpy(bbc->nvram.nv_testwrite, btchkdata); 30053981Sfujita if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) { 30153981Sfujita printf("WARNING: calendar clock battery down\n"); 30253981Sfujita return; 30353981Sfujita } 30453981Sfujita battery_clock = 1; 30553981Sfujita return; 30653981Sfujita } 307*59975Sakito 308*59975Sakito #define LUNA1_HZ 60 309*59975Sakito 310*59975Sakito modify_clock_param() 311*59975Sakito { 312*59975Sakito extern int hz, tick, tickadj; 313*59975Sakito 314*59975Sakito if (machineid == LUNA_I) { 315*59975Sakito hz = LUNA1_HZ; 316*59975Sakito tick = 1000000 / hz; 317*59975Sakito tickadj = 30000 / (60 * hz); /* can adjust 30ms in 60s */ 318*59975Sakito } 319*59975Sakito } 320