xref: /csrg-svn/sys/luna68k/luna68k/clock.c (revision 56521)
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