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*59945Sakito * @(#)clock.c 7.8 (Berkeley) 05/12/93 1753981Sfujita */ 1853981Sfujita 1956521Sbostic #include <sys/param.h> 2056521Sbostic #include <sys/kernel.h> 2153981Sfujita 2256521Sbostic #include <luna68k/luna68k/clockreg.h> 2356521Sbostic 24*59945Sakito #ifdef LUNA2 25*59945Sakito #include <machine/cpu.h> 26*59945Sakito #endif 27*59945Sakito 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; 36*59945Sakito #ifdef LUNA2 37*59945Sakito volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR; 38*59945Sakito #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 68*59945Sakito #ifdef LUNA2 69*59945Sakito if (machineid == LUNA_II) { 70*59945Sakito /* not yet */ 71*59945Sakito battery_chkfg = 1; 72*59945Sakito battery_clock = 1; 73*59945Sakito return; 74*59945Sakito } 75*59945Sakito #endif 76*59945Sakito 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 */ 156*59945Sakito #ifdef LUNA2 157*59945Sakito if (machineid == LUNA_II) { 158*59945Sakito #if 1 159*59945Sakito /* not yet */ 160*59945Sakito printf("WARNING: not supported resettodr() at LUNA2 yet.\n"); 161*59945Sakito return; 162*59945Sakito #else 163*59945Sakito /* bbc2->cal_ctl_? |= BBC_WRT; */ 164*59945Sakito bbc2->cal_sec = tmptr->tm_sec; 165*59945Sakito bbc2->cal_min = tmptr->tm_min; 166*59945Sakito bbc2->cal_hour =tmptr->tm_hour; 167*59945Sakito bbc2->cal_day = tmptr->tm_mday; 168*59945Sakito bbc2->cal_mon = tmptr->tm_mon; 169*59945Sakito bbc2->cal_year = tmptr->tm_year); 170*59945Sakito /* bbc2->cal_ctl_? &= ~BBC_WRT; */ 171*59945Sakito #endif 172*59945Sakito } else 173*59945Sakito #endif 174*59945Sakito { 175*59945Sakito bbc->cal_ctl |= BBC_WRT; 176*59945Sakito bbc->cal_sec = binary_to_bcd(tmptr->tm_sec); 177*59945Sakito bbc->cal_min = binary_to_bcd(tmptr->tm_min); 178*59945Sakito bbc->cal_hour = binary_to_bcd(tmptr->tm_hour); 179*59945Sakito bbc->cal_day = binary_to_bcd(tmptr->tm_mday); 180*59945Sakito bbc->cal_mon = binary_to_bcd(tmptr->tm_mon); 181*59945Sakito bbc->cal_year = binary_to_bcd(tmptr->tm_year); 182*59945Sakito bbc->cal_ctl &= ~BBC_WRT; 183*59945Sakito } 18453981Sfujita 18553981Sfujita splx(s); 18653981Sfujita } 18753981Sfujita 18853981Sfujita struct bbc_tm * 18953981Sfujita gmt_to_bbc(tim) 19053981Sfujita long tim; 19153981Sfujita { 19253981Sfujita register int i; 19353981Sfujita register long hms, day; 19453981Sfujita static struct bbc_tm rt; 19553981Sfujita 19653981Sfujita day = tim / SECDAY; 19753981Sfujita hms = tim % SECDAY; 19853981Sfujita 19953981Sfujita /* Hours, minutes, seconds are easy */ 20053981Sfujita rt.tm_hour = hms / 3600; 20153981Sfujita rt.tm_min = (hms % 3600) / 60; 20253981Sfujita rt.tm_sec = (hms % 3600) % 60; 20353981Sfujita 20453981Sfujita /* Number of years in days */ 20553981Sfujita for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 20653981Sfujita day -= days_in_year(i); 20753981Sfujita rt.tm_year = i; 20853981Sfujita 20953981Sfujita /* Number of months in days left */ 21053981Sfujita if (leapyear(rt.tm_year)) 21153981Sfujita days_in_month(FEBRUARY) = 29; 21253981Sfujita for (i = 1; day >= days_in_month(i); i++) 21353981Sfujita day -= days_in_month(i); 21453981Sfujita days_in_month(FEBRUARY) = 28; 21553981Sfujita rt.tm_mon = i; 21653981Sfujita 21753981Sfujita /* Days are what is left over (+1) from all that. */ 21853981Sfujita rt.tm_mday = day + 1; 21953981Sfujita 22053981Sfujita return(&rt); 22153981Sfujita } 22253981Sfujita 22353981Sfujita bbc_to_gmt(timbuf) 22453981Sfujita u_long *timbuf; 22553981Sfujita { 22653981Sfujita register int i,s; 22753981Sfujita register u_long tmp; 22853981Sfujita int year, month, day, hour, min, sec; 22953981Sfujita 23053981Sfujita if (!battery_clock) 23153981Sfujita return(0); 23253981Sfujita 23353981Sfujita s = splimp(); 23453981Sfujita 23553981Sfujita /* read bb-clock */ 236*59945Sakito #ifdef LUNA2 237*59945Sakito if (machineid == LUNA_II) { 238*59945Sakito sec = bbc2->cal_sec; 239*59945Sakito min = bbc2->cal_min; 240*59945Sakito hour = bbc2->cal_hour; 241*59945Sakito day = bbc2->cal_day; 242*59945Sakito month = bbc2->cal_mon; 243*59945Sakito year = bbc2->cal_year + 1900; 244*59945Sakito } else 245*59945Sakito #endif 246*59945Sakito { 247*59945Sakito bbc->cal_ctl |= BBC_RD; 248*59945Sakito sec = bcd_to_binary(bbc->cal_sec); 249*59945Sakito min = bcd_to_binary(bbc->cal_min); 250*59945Sakito hour = bcd_to_binary(bbc->cal_hour); 251*59945Sakito day = bcd_to_binary(bbc->cal_day); 252*59945Sakito month = bcd_to_binary(bbc->cal_mon); 253*59945Sakito year = bcd_to_binary(bbc->cal_year) + 1900; 254*59945Sakito bbc->cal_ctl &= ~BBC_RD; 255*59945Sakito } 256*59945Sakito 25753981Sfujita splx(s); 25853981Sfujita 25953981Sfujita range_test(hour, 0, 23); 26053981Sfujita range_test(day, 1, 31); 26153981Sfujita range_test(month, 1, 12); 262*59945Sakito #if 1 /* limitted 2000 now ... */ 26353981Sfujita range_test(year, STARTOFTIME, 2000); 264*59945Sakito #else 265*59945Sakito if (year < 1970) { 266*59945Sakito year += 100; 267*59945Sakito } 268*59945Sakito #endif 26953981Sfujita 27053981Sfujita tmp = 0; 27153981Sfujita 27253981Sfujita for (i = STARTOFTIME; i < year; i++) 27353981Sfujita tmp += days_in_year(i); 27453981Sfujita if (leapyear(year) && month > FEBRUARY) 27553981Sfujita tmp++; 27653981Sfujita 27753981Sfujita for (i = 1; i < month; i++) 27853981Sfujita tmp += days_in_month(i); 27953981Sfujita 28053981Sfujita tmp += (day - 1); 28153981Sfujita tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 28253981Sfujita 28353981Sfujita *timbuf = tmp; 28453981Sfujita return(1); 28553981Sfujita } 28653981Sfujita 28753981Sfujita batterychk() 28853981Sfujita { 28953981Sfujita static char btchkdata[] = "chk"; 29053981Sfujita 291*59945Sakito #ifdef LUNA2 292*59945Sakito if (machineid == LUNA_II) { 293*59945Sakito /* not yet */ 294*59945Sakito battery_chkfg = 1; 295*59945Sakito battery_clock = 1; 296*59945Sakito return; 297*59945Sakito } 298*59945Sakito #endif 29953981Sfujita /* if already checked, return */ 30053981Sfujita if (battery_chkfg) 30153981Sfujita return; 30253981Sfujita 30353981Sfujita battery_chkfg = 1; 30453981Sfujita if (badaddr((caddr_t)bbc, 2)) 30553981Sfujita return; 30653981Sfujita 30753981Sfujita strcpy(bbc->nvram.nv_testwrite, btchkdata); 30853981Sfujita if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) { 30953981Sfujita printf("WARNING: calendar clock battery down\n"); 31053981Sfujita return; 31153981Sfujita } 31253981Sfujita battery_clock = 1; 31353981Sfujita return; 31453981Sfujita } 315