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