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