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$ 14*58695Sakito * from: hp300/hp300/clock.c 7.19 (Berkeley) 2/18/93 1553981Sfujita * 16*58695Sakito * @(#)clock.c 7.6 (Berkeley) 03/17/93 1753981Sfujita */ 1853981Sfujita 1956521Sbostic #include <sys/param.h> 2056521Sbostic #include <sys/kernel.h> 2153981Sfujita 2256521Sbostic #include <luna68k/luna68k/clockreg.h> 2356521Sbostic 2455581Sfujita extern int clock_on; 2555581Sfujita 2653981Sfujita static int month_days[12] = { 2753981Sfujita 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 2853981Sfujita }; 2953981Sfujita struct bbc_tm *gmt_to_bbc(); 3053981Sfujita 3153981Sfujita volatile struct bbc *bbc = (struct bbc *)BBC_ADDR; 3253981Sfujita 3353981Sfujita int battery_clock; 3453981Sfujita int battery_chkfg; 3553981Sfujita 3653981Sfujita /* 3753981Sfujita * Machine-dependent clock routines. 3853981Sfujita * 3953981Sfujita * Startrtclock just checks battry backuped clock 4053981Sfujita * (when it does not work, starts it). 4153981Sfujita * 4253981Sfujita * Enablertclock sets flag for clock interrupt. 4353981Sfujita * 4453981Sfujita * Inittodr initializes the time of day hardware which provides 4553981Sfujita * date functions. 4653981Sfujita * 4753981Sfujita * Resettodr restores the time of day hardware after a time change. 4853981Sfujita * 4953981Sfujita */ 5053981Sfujita 5153981Sfujita /* 5253981Sfujita * Start the real-time clock. 5353981Sfujita */ 5455581Sfujita cpu_initclocks() 5553981Sfujita { 5653981Sfujita static char *rtcstrings = "RTC"; /* For compat */ 5753981Sfujita 5856149Sakito /* set flag for clockintr. */ 5956149Sakito clock_on = 1; 6056149Sakito 6153981Sfujita batterychk(); 6253981Sfujita if (!battery_clock) 6353981Sfujita return; 6453981Sfujita 6553981Sfujita if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */ 6653981Sfujita return; 6753981Sfujita 6853981Sfujita printf("Initialize Battery Backup Clock.\n"); 6953981Sfujita bbc->cal_ctl |= BBC_WRT; 7053981Sfujita bbc->cal_sec &= ~BBC_STOP; 7153981Sfujita bbc->cal_hour |= BBC_KICK; 7253981Sfujita bbc->cal_dow &= ~BBC_FRQ; 7353981Sfujita bbc->cal_ctl &= ~BBC_WRT; 7453981Sfujita DELAY(BBC_DELAY); 7553981Sfujita bbc->cal_ctl |= BBC_WRT; 7653981Sfujita bbc->cal_hour &= ~BBC_KICK; 7753981Sfujita bbc->cal_ctl &= ~BBC_WRT; 7853981Sfujita strcpy(bbc->nvram,rtcstrings); 7953981Sfujita } 8053981Sfujita 8155581Sfujita void 8255581Sfujita setstatclockrate(newhz) 8355581Sfujita int newhz; 8453981Sfujita { 8555581Sfujita } 8653981Sfujita 8755581Sfujita microtime(tvp) 8855581Sfujita register struct timeval *tvp; 8955581Sfujita { 9055581Sfujita int s = splhigh(); 9155581Sfujita 9255581Sfujita *tvp = time; 9355581Sfujita tvp->tv_usec += tick; 9455581Sfujita while (tvp->tv_usec > 1000000) { 9555581Sfujita tvp->tv_sec++; 9655581Sfujita tvp->tv_usec -= 1000000; 9755581Sfujita } 9855581Sfujita splx(s); 9953981Sfujita } 10053981Sfujita 10153981Sfujita /* 10253981Sfujita * Initialize the time of day register, based on the time base which is, e.g. 10353981Sfujita * from a filesystem. 10453981Sfujita */ 10553981Sfujita inittodr(base) 10653981Sfujita time_t base; 10753981Sfujita { 10853981Sfujita u_long timbuf = base; /* assume no battery clock exists */ 10953981Sfujita 11053981Sfujita /* 11153981Sfujita * bbc_to_gmt converts and stores the gmt in timbuf. 11253981Sfujita * If an error is detected in bbc_to_gmt, or if the filesystem 11353981Sfujita * time is more recent than the gmt time in the clock, 11453981Sfujita * then use the filesystem time and warn the user. 11553981Sfujita */ 11653981Sfujita if (!bbc_to_gmt(&timbuf) || timbuf < base) { 11753981Sfujita printf("WARNING: bad date in battery clock\n"); 11853981Sfujita timbuf = base; 11953981Sfujita } 12053981Sfujita if (base < 5*SECYR) { 12153981Sfujita printf("WARNING: preposterous time in file system"); 12253981Sfujita timbuf = 6*SECYR + 186*SECDAY + SECDAY/2; 12353981Sfujita printf(" -- CHECK AND RESET THE DATE!\n"); 12453981Sfujita } 12553981Sfujita 12653981Sfujita /* Battery clock does not store usec's, so forget about it. */ 12753981Sfujita time.tv_sec = timbuf; 12853981Sfujita } 12953981Sfujita 13053981Sfujita resettodr() 13153981Sfujita { 13253981Sfujita register int i,s; 13353981Sfujita register struct bbc_tm *tmptr; 13453981Sfujita 13553981Sfujita tmptr = gmt_to_bbc(time.tv_sec); 13653981Sfujita 13753981Sfujita s = splimp(); 13853981Sfujita 13953981Sfujita /* set bb-clock */ 14053981Sfujita bbc->cal_ctl |= BBC_WRT; 14153981Sfujita bbc->cal_sec = binary_to_bcd(tmptr->tm_sec); 14253981Sfujita bbc->cal_min = binary_to_bcd(tmptr->tm_min); 14353981Sfujita bbc->cal_hour = binary_to_bcd(tmptr->tm_hour); 14453981Sfujita bbc->cal_day = binary_to_bcd(tmptr->tm_mday); 14553981Sfujita bbc->cal_mon = binary_to_bcd(tmptr->tm_mon); 14653981Sfujita bbc->cal_year = binary_to_bcd(tmptr->tm_year); 14753981Sfujita bbc->cal_ctl &= ~BBC_WRT; 14853981Sfujita 14953981Sfujita splx(s); 15053981Sfujita } 15153981Sfujita 15253981Sfujita struct bbc_tm * 15353981Sfujita gmt_to_bbc(tim) 15453981Sfujita long tim; 15553981Sfujita { 15653981Sfujita register int i; 15753981Sfujita register long hms, day; 15853981Sfujita static struct bbc_tm rt; 15953981Sfujita 16053981Sfujita day = tim / SECDAY; 16153981Sfujita hms = tim % SECDAY; 16253981Sfujita 16353981Sfujita /* Hours, minutes, seconds are easy */ 16453981Sfujita rt.tm_hour = hms / 3600; 16553981Sfujita rt.tm_min = (hms % 3600) / 60; 16653981Sfujita rt.tm_sec = (hms % 3600) % 60; 16753981Sfujita 16853981Sfujita /* Number of years in days */ 16953981Sfujita for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 17053981Sfujita day -= days_in_year(i); 17153981Sfujita rt.tm_year = i; 17253981Sfujita 17353981Sfujita /* Number of months in days left */ 17453981Sfujita if (leapyear(rt.tm_year)) 17553981Sfujita days_in_month(FEBRUARY) = 29; 17653981Sfujita for (i = 1; day >= days_in_month(i); i++) 17753981Sfujita day -= days_in_month(i); 17853981Sfujita days_in_month(FEBRUARY) = 28; 17953981Sfujita rt.tm_mon = i; 18053981Sfujita 18153981Sfujita /* Days are what is left over (+1) from all that. */ 18253981Sfujita rt.tm_mday = day + 1; 18353981Sfujita 18453981Sfujita return(&rt); 18553981Sfujita } 18653981Sfujita 18753981Sfujita bbc_to_gmt(timbuf) 18853981Sfujita u_long *timbuf; 18953981Sfujita { 19053981Sfujita register int i,s; 19153981Sfujita register u_long tmp; 19253981Sfujita int year, month, day, hour, min, sec; 19353981Sfujita 19453981Sfujita if (!battery_clock) 19553981Sfujita return(0); 19653981Sfujita 19753981Sfujita s = splimp(); 19853981Sfujita 19953981Sfujita /* read bb-clock */ 20053981Sfujita bbc->cal_ctl |= BBC_RD; 20153981Sfujita sec = bcd_to_binary(bbc->cal_sec); 20253981Sfujita min = bcd_to_binary(bbc->cal_min); 20353981Sfujita hour = bcd_to_binary(bbc->cal_hour); 20453981Sfujita day = bcd_to_binary(bbc->cal_day); 20553981Sfujita month = bcd_to_binary(bbc->cal_mon); 20653981Sfujita year = bcd_to_binary(bbc->cal_year) + 1900; 20753981Sfujita bbc->cal_ctl &= ~BBC_RD; 20853981Sfujita 20953981Sfujita splx(s); 21053981Sfujita 21153981Sfujita range_test(hour, 0, 23); 21253981Sfujita range_test(day, 1, 31); 21353981Sfujita range_test(month, 1, 12); 21453981Sfujita range_test(year, STARTOFTIME, 2000); 21553981Sfujita 21653981Sfujita tmp = 0; 21753981Sfujita 21853981Sfujita for (i = STARTOFTIME; i < year; i++) 21953981Sfujita tmp += days_in_year(i); 22053981Sfujita if (leapyear(year) && month > FEBRUARY) 22153981Sfujita tmp++; 22253981Sfujita 22353981Sfujita for (i = 1; i < month; i++) 22453981Sfujita tmp += days_in_month(i); 22553981Sfujita 22653981Sfujita tmp += (day - 1); 22753981Sfujita tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 22853981Sfujita 22953981Sfujita *timbuf = tmp; 23053981Sfujita return(1); 23153981Sfujita } 23253981Sfujita 23353981Sfujita batterychk() 23453981Sfujita { 23553981Sfujita static char btchkdata[] = "chk"; 23653981Sfujita 23753981Sfujita /* if already checked, return */ 23853981Sfujita if (battery_chkfg) 23953981Sfujita return; 24053981Sfujita 24153981Sfujita battery_chkfg = 1; 24253981Sfujita if (badaddr((caddr_t)bbc, 2)) 24353981Sfujita return; 24453981Sfujita 24553981Sfujita strcpy(bbc->nvram.nv_testwrite, btchkdata); 24653981Sfujita if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) { 24753981Sfujita printf("WARNING: calendar clock battery down\n"); 24853981Sfujita return; 24953981Sfujita } 25053981Sfujita battery_clock = 1; 25153981Sfujita return; 25253981Sfujita } 253