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*59979Sakito * @(#)clock.c 7.10 (Berkeley) 05/12/93 1753981Sfujita */ 1853981Sfujita 1956521Sbostic #include <sys/param.h> 2056521Sbostic #include <sys/kernel.h> 2153981Sfujita 22*59979Sakito #include <machine/cpu.h> 2356521Sbostic #include <luna68k/luna68k/clockreg.h> 2456521Sbostic 2555581Sfujita extern int clock_on; 2655581Sfujita 2753981Sfujita static int month_days[12] = { 2853981Sfujita 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 2953981Sfujita }; 3053981Sfujita struct bbc_tm *gmt_to_bbc(); 3153981Sfujita 3253981Sfujita volatile struct bbc *bbc = (struct bbc *)BBC_ADDR; 3359945Sakito #ifdef LUNA2 3459945Sakito volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR; 3559945Sakito #endif 3653981Sfujita 3753981Sfujita int battery_clock; 3853981Sfujita int battery_chkfg; 3953981Sfujita 4053981Sfujita /* 4153981Sfujita * Machine-dependent clock routines. 4253981Sfujita * 4353981Sfujita * Startrtclock just checks battry backuped clock 4453981Sfujita * (when it does not work, starts it). 4553981Sfujita * 4653981Sfujita * Enablertclock sets flag for clock interrupt. 4753981Sfujita * 4853981Sfujita * Inittodr initializes the time of day hardware which provides 4953981Sfujita * date functions. 5053981Sfujita * 5153981Sfujita * Resettodr restores the time of day hardware after a time change. 5253981Sfujita * 5353981Sfujita */ 5453981Sfujita 5553981Sfujita /* 5653981Sfujita * Start the real-time clock. 5753981Sfujita */ 5855581Sfujita cpu_initclocks() 5953981Sfujita { 6053981Sfujita static char *rtcstrings = "RTC"; /* For compat */ 6153981Sfujita 6256149Sakito /* set flag for clockintr. */ 6356149Sakito clock_on = 1; 6456149Sakito 6559945Sakito #ifdef LUNA2 6659945Sakito if (machineid == LUNA_II) { 6759945Sakito /* not yet */ 6859945Sakito battery_chkfg = 1; 6959945Sakito battery_clock = 1; 7059945Sakito return; 7159945Sakito } 7259945Sakito #endif 7359945Sakito 7453981Sfujita batterychk(); 7553981Sfujita if (!battery_clock) 7653981Sfujita return; 7753981Sfujita 7853981Sfujita if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */ 7953981Sfujita return; 8053981Sfujita 8153981Sfujita printf("Initialize Battery Backup Clock.\n"); 8253981Sfujita bbc->cal_ctl |= BBC_WRT; 8353981Sfujita bbc->cal_sec &= ~BBC_STOP; 8453981Sfujita bbc->cal_hour |= BBC_KICK; 8553981Sfujita bbc->cal_dow &= ~BBC_FRQ; 8653981Sfujita bbc->cal_ctl &= ~BBC_WRT; 8753981Sfujita DELAY(BBC_DELAY); 8853981Sfujita bbc->cal_ctl |= BBC_WRT; 8953981Sfujita bbc->cal_hour &= ~BBC_KICK; 9053981Sfujita bbc->cal_ctl &= ~BBC_WRT; 9159643Sakito strcpy(bbc->nvram.nv_calclock, rtcstrings); 9253981Sfujita } 9353981Sfujita 9455581Sfujita void 9555581Sfujita setstatclockrate(newhz) 9655581Sfujita int newhz; 9753981Sfujita { 9855581Sfujita } 9953981Sfujita 10055581Sfujita microtime(tvp) 10155581Sfujita register struct timeval *tvp; 10255581Sfujita { 10355581Sfujita int s = splhigh(); 10455581Sfujita 10555581Sfujita *tvp = time; 10655581Sfujita tvp->tv_usec += tick; 10755581Sfujita while (tvp->tv_usec > 1000000) { 10855581Sfujita tvp->tv_sec++; 10955581Sfujita tvp->tv_usec -= 1000000; 11055581Sfujita } 11155581Sfujita splx(s); 11253981Sfujita } 11353981Sfujita 11453981Sfujita /* 11553981Sfujita * Initialize the time of day register, based on the time base which is, e.g. 11653981Sfujita * from a filesystem. 11753981Sfujita */ 11853981Sfujita inittodr(base) 11953981Sfujita time_t base; 12053981Sfujita { 12153981Sfujita u_long timbuf = base; /* assume no battery clock exists */ 12253981Sfujita 12353981Sfujita /* 12453981Sfujita * bbc_to_gmt converts and stores the gmt in timbuf. 12553981Sfujita * If an error is detected in bbc_to_gmt, or if the filesystem 12653981Sfujita * time is more recent than the gmt time in the clock, 12753981Sfujita * then use the filesystem time and warn the user. 12853981Sfujita */ 12953981Sfujita if (!bbc_to_gmt(&timbuf) || timbuf < base) { 13053981Sfujita printf("WARNING: bad date in battery clock\n"); 13153981Sfujita timbuf = base; 13253981Sfujita } 13353981Sfujita if (base < 5*SECYR) { 13453981Sfujita printf("WARNING: preposterous time in file system"); 13553981Sfujita timbuf = 6*SECYR + 186*SECDAY + SECDAY/2; 13653981Sfujita printf(" -- CHECK AND RESET THE DATE!\n"); 13753981Sfujita } 13853981Sfujita 13953981Sfujita /* Battery clock does not store usec's, so forget about it. */ 14053981Sfujita time.tv_sec = timbuf; 14153981Sfujita } 14253981Sfujita 14353981Sfujita resettodr() 14453981Sfujita { 14553981Sfujita register int i,s; 14653981Sfujita register struct bbc_tm *tmptr; 14753981Sfujita 14853981Sfujita tmptr = gmt_to_bbc(time.tv_sec); 14953981Sfujita 15053981Sfujita s = splimp(); 15153981Sfujita 15253981Sfujita /* set bb-clock */ 15359945Sakito #ifdef LUNA2 15459945Sakito if (machineid == LUNA_II) { 15559945Sakito bbc2->cal_sec = tmptr->tm_sec; 15659945Sakito bbc2->cal_min = tmptr->tm_min; 15759945Sakito bbc2->cal_hour =tmptr->tm_hour; 15859945Sakito bbc2->cal_day = tmptr->tm_mday; 15959945Sakito bbc2->cal_mon = tmptr->tm_mon; 16059975Sakito bbc2->cal_year = tmptr->tm_year; 16159945Sakito } else 16259945Sakito #endif 16359945Sakito { 16459945Sakito bbc->cal_ctl |= BBC_WRT; 16559945Sakito bbc->cal_sec = binary_to_bcd(tmptr->tm_sec); 16659945Sakito bbc->cal_min = binary_to_bcd(tmptr->tm_min); 16759945Sakito bbc->cal_hour = binary_to_bcd(tmptr->tm_hour); 16859945Sakito bbc->cal_day = binary_to_bcd(tmptr->tm_mday); 16959945Sakito bbc->cal_mon = binary_to_bcd(tmptr->tm_mon); 17059945Sakito bbc->cal_year = binary_to_bcd(tmptr->tm_year); 17159945Sakito bbc->cal_ctl &= ~BBC_WRT; 17259945Sakito } 17353981Sfujita 17453981Sfujita splx(s); 17553981Sfujita } 17653981Sfujita 17753981Sfujita struct bbc_tm * 17853981Sfujita gmt_to_bbc(tim) 17953981Sfujita long tim; 18053981Sfujita { 18153981Sfujita register int i; 18253981Sfujita register long hms, day; 18353981Sfujita static struct bbc_tm rt; 18453981Sfujita 18553981Sfujita day = tim / SECDAY; 18653981Sfujita hms = tim % SECDAY; 18753981Sfujita 18853981Sfujita /* Hours, minutes, seconds are easy */ 18953981Sfujita rt.tm_hour = hms / 3600; 19053981Sfujita rt.tm_min = (hms % 3600) / 60; 19153981Sfujita rt.tm_sec = (hms % 3600) % 60; 19253981Sfujita 19353981Sfujita /* Number of years in days */ 19453981Sfujita for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++) 19553981Sfujita day -= days_in_year(i); 19653981Sfujita rt.tm_year = i; 19753981Sfujita 19853981Sfujita /* Number of months in days left */ 19953981Sfujita if (leapyear(rt.tm_year)) 20053981Sfujita days_in_month(FEBRUARY) = 29; 20153981Sfujita for (i = 1; day >= days_in_month(i); i++) 20253981Sfujita day -= days_in_month(i); 20353981Sfujita days_in_month(FEBRUARY) = 28; 20453981Sfujita rt.tm_mon = i; 20553981Sfujita 20653981Sfujita /* Days are what is left over (+1) from all that. */ 20753981Sfujita rt.tm_mday = day + 1; 20853981Sfujita 20953981Sfujita return(&rt); 21053981Sfujita } 21153981Sfujita 21253981Sfujita bbc_to_gmt(timbuf) 21353981Sfujita u_long *timbuf; 21453981Sfujita { 21553981Sfujita register int i,s; 21653981Sfujita register u_long tmp; 21753981Sfujita int year, month, day, hour, min, sec; 21853981Sfujita 21953981Sfujita if (!battery_clock) 22053981Sfujita return(0); 22153981Sfujita 22253981Sfujita s = splimp(); 22353981Sfujita 22453981Sfujita /* read bb-clock */ 22559945Sakito #ifdef LUNA2 22659945Sakito if (machineid == LUNA_II) { 22759945Sakito sec = bbc2->cal_sec; 22859945Sakito min = bbc2->cal_min; 22959945Sakito hour = bbc2->cal_hour; 23059945Sakito day = bbc2->cal_day; 23159945Sakito month = bbc2->cal_mon; 23259945Sakito year = bbc2->cal_year + 1900; 23359945Sakito } else 23459945Sakito #endif 23559945Sakito { 23659945Sakito bbc->cal_ctl |= BBC_RD; 23759945Sakito sec = bcd_to_binary(bbc->cal_sec); 23859945Sakito min = bcd_to_binary(bbc->cal_min); 23959945Sakito hour = bcd_to_binary(bbc->cal_hour); 24059945Sakito day = bcd_to_binary(bbc->cal_day); 24159945Sakito month = bcd_to_binary(bbc->cal_mon); 24259945Sakito year = bcd_to_binary(bbc->cal_year) + 1900; 24359945Sakito bbc->cal_ctl &= ~BBC_RD; 24459945Sakito } 24559945Sakito 24653981Sfujita splx(s); 24753981Sfujita 24853981Sfujita range_test(hour, 0, 23); 24953981Sfujita range_test(day, 1, 31); 25053981Sfujita range_test(month, 1, 12); 25159945Sakito #if 1 /* limitted 2000 now ... */ 25253981Sfujita range_test(year, STARTOFTIME, 2000); 25359945Sakito #else 25459945Sakito if (year < 1970) { 25559945Sakito year += 100; 25659945Sakito } 25759945Sakito #endif 25853981Sfujita 25953981Sfujita tmp = 0; 26053981Sfujita 26153981Sfujita for (i = STARTOFTIME; i < year; i++) 26253981Sfujita tmp += days_in_year(i); 26353981Sfujita if (leapyear(year) && month > FEBRUARY) 26453981Sfujita tmp++; 26553981Sfujita 26653981Sfujita for (i = 1; i < month; i++) 26753981Sfujita tmp += days_in_month(i); 26853981Sfujita 26953981Sfujita tmp += (day - 1); 27053981Sfujita tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec; 27153981Sfujita 27253981Sfujita *timbuf = tmp; 27353981Sfujita return(1); 27453981Sfujita } 27553981Sfujita 27653981Sfujita batterychk() 27753981Sfujita { 27853981Sfujita static char btchkdata[] = "chk"; 27953981Sfujita 28059945Sakito #ifdef LUNA2 28159945Sakito if (machineid == LUNA_II) { 28259945Sakito /* not yet */ 28359945Sakito battery_chkfg = 1; 28459945Sakito battery_clock = 1; 28559945Sakito return; 28659945Sakito } 28759945Sakito #endif 28853981Sfujita /* if already checked, return */ 28953981Sfujita if (battery_chkfg) 29053981Sfujita return; 29153981Sfujita 29253981Sfujita battery_chkfg = 1; 29353981Sfujita if (badaddr((caddr_t)bbc, 2)) 29453981Sfujita return; 29553981Sfujita 29653981Sfujita strcpy(bbc->nvram.nv_testwrite, btchkdata); 29753981Sfujita if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) { 29853981Sfujita printf("WARNING: calendar clock battery down\n"); 29953981Sfujita return; 30053981Sfujita } 30153981Sfujita battery_clock = 1; 30253981Sfujita return; 30353981Sfujita } 30459975Sakito 30559975Sakito #define LUNA1_HZ 60 30659975Sakito 30759975Sakito modify_clock_param() 30859975Sakito { 30959975Sakito extern int hz, tick, tickadj; 31059975Sakito 31159975Sakito if (machineid == LUNA_I) { 31259975Sakito hz = LUNA1_HZ; 31359975Sakito tick = 1000000 / hz; 31459975Sakito tickadj = 30000 / (60 * hz); /* can adjust 30ms in 60s */ 31559975Sakito } 31659975Sakito } 317