153981Sfujita /*
253981Sfujita * Copyright (c) 1988 University of Utah.
353981Sfujita * Copyright (c) 1992 OMRON Corporation.
463195Sbostic * Copyright (c) 1982, 1990, 1992, 1993
563195Sbostic * The Regents of the University of California. 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*64266Smckusick * @(#)clock.c 8.2 (Berkeley) 08/15/93
1753981Sfujita */
1853981Sfujita
1956521Sbostic #include <sys/param.h>
2056521Sbostic #include <sys/kernel.h>
2153981Sfujita
2259979Sakito #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 */
cpu_initclocks()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
setstatclockrate(newhz)9555581Sfujita setstatclockrate(newhz)
9655581Sfujita int newhz;
9753981Sfujita {
9855581Sfujita }
9953981Sfujita
microtime(tvp)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 */
inittodr(base)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
resettodr()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) {
155*64266Smckusick bbc2->cal_ctl_b |= BBC2_B_SET;
15659945Sakito bbc2->cal_sec = tmptr->tm_sec;
15759945Sakito bbc2->cal_min = tmptr->tm_min;
15859945Sakito bbc2->cal_hour =tmptr->tm_hour;
15959945Sakito bbc2->cal_day = tmptr->tm_mday;
16059945Sakito bbc2->cal_mon = tmptr->tm_mon;
16159975Sakito bbc2->cal_year = tmptr->tm_year;
162*64266Smckusick bbc2->cal_ctl_b &= ~BBC2_B_SET;
16359945Sakito } else
16459945Sakito #endif
16559945Sakito {
16659945Sakito bbc->cal_ctl |= BBC_WRT;
16759945Sakito bbc->cal_sec = binary_to_bcd(tmptr->tm_sec);
16859945Sakito bbc->cal_min = binary_to_bcd(tmptr->tm_min);
16959945Sakito bbc->cal_hour = binary_to_bcd(tmptr->tm_hour);
17059945Sakito bbc->cal_day = binary_to_bcd(tmptr->tm_mday);
17159945Sakito bbc->cal_mon = binary_to_bcd(tmptr->tm_mon);
17259945Sakito bbc->cal_year = binary_to_bcd(tmptr->tm_year);
17359945Sakito bbc->cal_ctl &= ~BBC_WRT;
17459945Sakito }
17553981Sfujita
17653981Sfujita splx(s);
17753981Sfujita }
17853981Sfujita
17953981Sfujita struct bbc_tm *
gmt_to_bbc(tim)18053981Sfujita gmt_to_bbc(tim)
18153981Sfujita long tim;
18253981Sfujita {
18353981Sfujita register int i;
18453981Sfujita register long hms, day;
18553981Sfujita static struct bbc_tm rt;
18653981Sfujita
18753981Sfujita day = tim / SECDAY;
18853981Sfujita hms = tim % SECDAY;
18953981Sfujita
19053981Sfujita /* Hours, minutes, seconds are easy */
19153981Sfujita rt.tm_hour = hms / 3600;
19253981Sfujita rt.tm_min = (hms % 3600) / 60;
19353981Sfujita rt.tm_sec = (hms % 3600) % 60;
19453981Sfujita
19553981Sfujita /* Number of years in days */
19653981Sfujita for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
19753981Sfujita day -= days_in_year(i);
19853981Sfujita rt.tm_year = i;
19953981Sfujita
20053981Sfujita /* Number of months in days left */
20153981Sfujita if (leapyear(rt.tm_year))
20253981Sfujita days_in_month(FEBRUARY) = 29;
20353981Sfujita for (i = 1; day >= days_in_month(i); i++)
20453981Sfujita day -= days_in_month(i);
20553981Sfujita days_in_month(FEBRUARY) = 28;
20653981Sfujita rt.tm_mon = i;
20753981Sfujita
20853981Sfujita /* Days are what is left over (+1) from all that. */
20953981Sfujita rt.tm_mday = day + 1;
21053981Sfujita
21153981Sfujita return(&rt);
21253981Sfujita }
21353981Sfujita
bbc_to_gmt(timbuf)21453981Sfujita bbc_to_gmt(timbuf)
21553981Sfujita u_long *timbuf;
21653981Sfujita {
21753981Sfujita register int i,s;
21853981Sfujita register u_long tmp;
21953981Sfujita int year, month, day, hour, min, sec;
22053981Sfujita
22153981Sfujita if (!battery_clock)
22253981Sfujita return(0);
22353981Sfujita
22453981Sfujita s = splimp();
22553981Sfujita
22653981Sfujita /* read bb-clock */
22759945Sakito #ifdef LUNA2
22859945Sakito if (machineid == LUNA_II) {
229*64266Smckusick while (bbc2->cal_ctl_a & BBC2_A_UIP) {} /* wait (max 224 us) */
230*64266Smckusick bbc2->cal_ctl_b |= BBC2_B_SET;
23159945Sakito sec = bbc2->cal_sec;
23259945Sakito min = bbc2->cal_min;
23359945Sakito hour = bbc2->cal_hour;
23459945Sakito day = bbc2->cal_day;
23559945Sakito month = bbc2->cal_mon;
23659945Sakito year = bbc2->cal_year + 1900;
237*64266Smckusick bbc2->cal_ctl_b &= ~BBC2_B_SET;
23859945Sakito } else
23959945Sakito #endif
24059945Sakito {
24159945Sakito bbc->cal_ctl |= BBC_RD;
24259945Sakito sec = bcd_to_binary(bbc->cal_sec);
24359945Sakito min = bcd_to_binary(bbc->cal_min);
24459945Sakito hour = bcd_to_binary(bbc->cal_hour);
24559945Sakito day = bcd_to_binary(bbc->cal_day);
24659945Sakito month = bcd_to_binary(bbc->cal_mon);
24759945Sakito year = bcd_to_binary(bbc->cal_year) + 1900;
24859945Sakito bbc->cal_ctl &= ~BBC_RD;
24959945Sakito }
25059945Sakito
25153981Sfujita splx(s);
25253981Sfujita
25353981Sfujita range_test(hour, 0, 23);
25453981Sfujita range_test(day, 1, 31);
25553981Sfujita range_test(month, 1, 12);
256*64266Smckusick
25759945Sakito if (year < 1970) {
25859945Sakito year += 100;
25959945Sakito }
26053981Sfujita
26153981Sfujita tmp = 0;
26253981Sfujita
26353981Sfujita for (i = STARTOFTIME; i < year; i++)
26453981Sfujita tmp += days_in_year(i);
26553981Sfujita if (leapyear(year) && month > FEBRUARY)
26653981Sfujita tmp++;
26753981Sfujita
26853981Sfujita for (i = 1; i < month; i++)
26953981Sfujita tmp += days_in_month(i);
27053981Sfujita
27153981Sfujita tmp += (day - 1);
27253981Sfujita tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
27353981Sfujita
27453981Sfujita *timbuf = tmp;
27553981Sfujita return(1);
27653981Sfujita }
27753981Sfujita
batterychk()27853981Sfujita batterychk()
27953981Sfujita {
28053981Sfujita static char btchkdata[] = "chk";
28153981Sfujita
28259945Sakito #ifdef LUNA2
28359945Sakito if (machineid == LUNA_II) {
28459945Sakito /* not yet */
28559945Sakito battery_chkfg = 1;
28659945Sakito battery_clock = 1;
28759945Sakito return;
28859945Sakito }
28959945Sakito #endif
29053981Sfujita /* if already checked, return */
29153981Sfujita if (battery_chkfg)
29253981Sfujita return;
29353981Sfujita
29453981Sfujita battery_chkfg = 1;
29553981Sfujita if (badaddr((caddr_t)bbc, 2))
29653981Sfujita return;
29753981Sfujita
29853981Sfujita strcpy(bbc->nvram.nv_testwrite, btchkdata);
29953981Sfujita if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) {
30053981Sfujita printf("WARNING: calendar clock battery down\n");
30153981Sfujita return;
30253981Sfujita }
30353981Sfujita battery_clock = 1;
30453981Sfujita return;
30553981Sfujita }
30659975Sakito
30759975Sakito #define LUNA1_HZ 60
30859975Sakito
modify_clock_param()30959975Sakito modify_clock_param()
31059975Sakito {
31159975Sakito extern int hz, tick, tickadj;
31259975Sakito
31359975Sakito if (machineid == LUNA_I) {
31459975Sakito hz = LUNA1_HZ;
31559975Sakito tick = 1000000 / hz;
31659975Sakito tickadj = 30000 / (60 * hz); /* can adjust 30ms in 60s */
31759975Sakito }
31859975Sakito }
319