xref: /original-bsd/sys/luna68k/luna68k/clock.c (revision 2e3047bc)
1cfcf6b6eSfujita /*
2cfcf6b6eSfujita  * Copyright (c) 1988 University of Utah.
3cfcf6b6eSfujita  * Copyright (c) 1992 OMRON Corporation.
40c9190d2Sbostic  * Copyright (c) 1982, 1990, 1992, 1993
50c9190d2Sbostic  *	The Regents of the University of California.  All rights reserved.
6cfcf6b6eSfujita  *
7cfcf6b6eSfujita  * This code is derived from software contributed to Berkeley by
8cfcf6b6eSfujita  * the Systems Programming Group of the University of Utah Computer
9cfcf6b6eSfujita  * Science Department.
10cfcf6b6eSfujita  *
11cfcf6b6eSfujita  * %sccs.include.redist.c%
12cfcf6b6eSfujita  *
13cfcf6b6eSfujita  * from: Utah $Hdr: clock.c 1.18 91/01/21$
1407070784Sakito  * from: hp300/hp300/clock.c	7.19 (Berkeley) 2/18/93
15cfcf6b6eSfujita  *
16*2e3047bcSmckusick  *	@(#)clock.c	8.2 (Berkeley) 08/15/93
17cfcf6b6eSfujita  */
18cfcf6b6eSfujita 
19a7ac273aSbostic #include <sys/param.h>
20a7ac273aSbostic #include <sys/kernel.h>
21a7ac273aSbostic 
220f561374Sakito #include <machine/cpu.h>
233dcda6ecSakito #include <luna68k/luna68k/clockreg.h>
240f561374Sakito 
25346db4ceSfujita extern int clock_on;
26346db4ceSfujita 
27cfcf6b6eSfujita static int month_days[12] = {
28cfcf6b6eSfujita     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
29cfcf6b6eSfujita };
30cfcf6b6eSfujita struct bbc_tm *gmt_to_bbc();
31cfcf6b6eSfujita 
32cfcf6b6eSfujita volatile struct bbc *bbc = (struct bbc *)BBC_ADDR;
330f561374Sakito #ifdef LUNA2
340f561374Sakito volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR;
350f561374Sakito #endif
36cfcf6b6eSfujita 
37cfcf6b6eSfujita int battery_clock;
38cfcf6b6eSfujita int battery_chkfg;
39cfcf6b6eSfujita 
40cfcf6b6eSfujita /*
41cfcf6b6eSfujita  * Machine-dependent clock routines.
42cfcf6b6eSfujita  *
43cfcf6b6eSfujita  * Startrtclock just checks battry backuped clock
44cfcf6b6eSfujita  * (when it does not work, starts it).
45cfcf6b6eSfujita  *
46cfcf6b6eSfujita  * Enablertclock sets flag for clock interrupt.
47cfcf6b6eSfujita  *
48cfcf6b6eSfujita  * Inittodr initializes the time of day hardware which provides
49cfcf6b6eSfujita  * date functions.
50cfcf6b6eSfujita  *
51cfcf6b6eSfujita  * Resettodr restores the time of day hardware after a time change.
52cfcf6b6eSfujita  *
53cfcf6b6eSfujita  */
54cfcf6b6eSfujita 
55cfcf6b6eSfujita /*
56cfcf6b6eSfujita  * Start the real-time clock.
57cfcf6b6eSfujita  */
cpu_initclocks()58346db4ceSfujita cpu_initclocks()
59cfcf6b6eSfujita {
60cfcf6b6eSfujita 	static char *rtcstrings = "RTC";     /* For compat */
61cfcf6b6eSfujita 
626ac5fc78Sakito 	/* set flag for clockintr. */
636ac5fc78Sakito 	clock_on = 1;
646ac5fc78Sakito 
650f561374Sakito #ifdef LUNA2
660f561374Sakito 	if (machineid == LUNA_II) {
670f561374Sakito 		/* not yet */
680f561374Sakito 		battery_chkfg = 1;
690f561374Sakito 		battery_clock = 1;
700f561374Sakito 		return;
710f561374Sakito 	}
720f561374Sakito #endif
730f561374Sakito 
74cfcf6b6eSfujita 	batterychk();
75cfcf6b6eSfujita 	if (!battery_clock)
76cfcf6b6eSfujita 	  return;
77cfcf6b6eSfujita 
78cfcf6b6eSfujita 	if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */
79cfcf6b6eSfujita 	  return;
80cfcf6b6eSfujita 
81cfcf6b6eSfujita 	printf("Initialize Battery Backup Clock.\n");
82cfcf6b6eSfujita 	bbc->cal_ctl |= BBC_WRT;
83cfcf6b6eSfujita 	bbc->cal_sec &= ~BBC_STOP;
84cfcf6b6eSfujita 	bbc->cal_hour |= BBC_KICK;
85cfcf6b6eSfujita 	bbc->cal_dow &= ~BBC_FRQ;
86cfcf6b6eSfujita 	bbc->cal_ctl &= ~BBC_WRT;
87cfcf6b6eSfujita 	DELAY(BBC_DELAY);
88cfcf6b6eSfujita 	bbc->cal_ctl |= BBC_WRT;
89cfcf6b6eSfujita 	bbc->cal_hour &= ~BBC_KICK;
90cfcf6b6eSfujita 	bbc->cal_ctl &= ~BBC_WRT;
91d1d6cde1Sakito 	strcpy(bbc->nvram.nv_calclock, rtcstrings);
92cfcf6b6eSfujita }
93cfcf6b6eSfujita 
94346db4ceSfujita void
setstatclockrate(newhz)95346db4ceSfujita setstatclockrate(newhz)
96346db4ceSfujita         int newhz;
97346db4ceSfujita {
98346db4ceSfujita }
99346db4ceSfujita 
microtime(tvp)100346db4ceSfujita microtime(tvp)
101346db4ceSfujita         register struct timeval *tvp;
102346db4ceSfujita {
103346db4ceSfujita         int s = splhigh();
104346db4ceSfujita 
105346db4ceSfujita         *tvp = time;
106346db4ceSfujita         tvp->tv_usec += tick;
107346db4ceSfujita         while (tvp->tv_usec > 1000000) {
108346db4ceSfujita                 tvp->tv_sec++;
109346db4ceSfujita                 tvp->tv_usec -= 1000000;
110346db4ceSfujita         }
111346db4ceSfujita         splx(s);
112346db4ceSfujita }
113346db4ceSfujita 
114cfcf6b6eSfujita /*
115cfcf6b6eSfujita  * Initialize the time of day register, based on the time base which is, e.g.
116cfcf6b6eSfujita  * from a filesystem.
117cfcf6b6eSfujita  */
inittodr(base)118cfcf6b6eSfujita inittodr(base)
119cfcf6b6eSfujita 	time_t base;
120cfcf6b6eSfujita {
121cfcf6b6eSfujita 	u_long timbuf = base;	/* assume no battery clock exists */
122cfcf6b6eSfujita 
123cfcf6b6eSfujita 	/*
124cfcf6b6eSfujita 	 * bbc_to_gmt converts and stores the gmt in timbuf.
125cfcf6b6eSfujita 	 * If an error is detected in bbc_to_gmt, or if the filesystem
126cfcf6b6eSfujita 	 * time is more recent than the gmt time in the clock,
127cfcf6b6eSfujita 	 * then use the filesystem time and warn the user.
128cfcf6b6eSfujita  	 */
129cfcf6b6eSfujita 	if (!bbc_to_gmt(&timbuf) || timbuf < base) {
130cfcf6b6eSfujita 		printf("WARNING: bad date in battery clock\n");
131cfcf6b6eSfujita 		timbuf = base;
132cfcf6b6eSfujita 	}
133cfcf6b6eSfujita 	if (base < 5*SECYR) {
134cfcf6b6eSfujita 		printf("WARNING: preposterous time in file system");
135cfcf6b6eSfujita 		timbuf = 6*SECYR + 186*SECDAY + SECDAY/2;
136cfcf6b6eSfujita 		printf(" -- CHECK AND RESET THE DATE!\n");
137cfcf6b6eSfujita 	}
138cfcf6b6eSfujita 
139cfcf6b6eSfujita 	/* Battery clock does not store usec's, so forget about it. */
140cfcf6b6eSfujita 	time.tv_sec = timbuf;
141cfcf6b6eSfujita }
142cfcf6b6eSfujita 
resettodr()143cfcf6b6eSfujita resettodr()
144cfcf6b6eSfujita {
145cfcf6b6eSfujita 	register int i,s;
146cfcf6b6eSfujita 	register struct bbc_tm *tmptr;
147cfcf6b6eSfujita 
148cfcf6b6eSfujita 	tmptr = gmt_to_bbc(time.tv_sec);
149cfcf6b6eSfujita 
150cfcf6b6eSfujita 	s = splimp();
151cfcf6b6eSfujita 
152cfcf6b6eSfujita 	/* set bb-clock */
1530f561374Sakito #ifdef LUNA2
1540f561374Sakito 	if (machineid == LUNA_II) {
155*2e3047bcSmckusick 		bbc2->cal_ctl_b |= BBC2_B_SET;
1560f561374Sakito 		bbc2->cal_sec = tmptr->tm_sec;
1570f561374Sakito 		bbc2->cal_min = tmptr->tm_min;
1580f561374Sakito 		bbc2->cal_hour =tmptr->tm_hour;
1590f561374Sakito 		bbc2->cal_day = tmptr->tm_mday;
1600f561374Sakito 		bbc2->cal_mon = tmptr->tm_mon;
1611e3a2a72Sakito 		bbc2->cal_year = tmptr->tm_year;
162*2e3047bcSmckusick 		bbc2->cal_ctl_b &= ~BBC2_B_SET;
1630f561374Sakito 	} else
1640f561374Sakito #endif
1650f561374Sakito 	{
166cfcf6b6eSfujita 		bbc->cal_ctl |= BBC_WRT;
167cfcf6b6eSfujita 		bbc->cal_sec = binary_to_bcd(tmptr->tm_sec);
168cfcf6b6eSfujita 		bbc->cal_min = binary_to_bcd(tmptr->tm_min);
169cfcf6b6eSfujita 		bbc->cal_hour = binary_to_bcd(tmptr->tm_hour);
170cfcf6b6eSfujita 		bbc->cal_day = binary_to_bcd(tmptr->tm_mday);
171cfcf6b6eSfujita 		bbc->cal_mon = binary_to_bcd(tmptr->tm_mon);
172cfcf6b6eSfujita 		bbc->cal_year = binary_to_bcd(tmptr->tm_year);
173cfcf6b6eSfujita 		bbc->cal_ctl &= ~BBC_WRT;
1740f561374Sakito 	}
175cfcf6b6eSfujita 
176cfcf6b6eSfujita 	splx(s);
177cfcf6b6eSfujita }
178cfcf6b6eSfujita 
179cfcf6b6eSfujita struct bbc_tm *
gmt_to_bbc(tim)180cfcf6b6eSfujita gmt_to_bbc(tim)
181cfcf6b6eSfujita 	long tim;
182cfcf6b6eSfujita {
183cfcf6b6eSfujita 	register int i;
184cfcf6b6eSfujita 	register long hms, day;
185cfcf6b6eSfujita 	static struct bbc_tm rt;
186cfcf6b6eSfujita 
187cfcf6b6eSfujita 	day = tim / SECDAY;
188cfcf6b6eSfujita 	hms = tim % SECDAY;
189cfcf6b6eSfujita 
190cfcf6b6eSfujita 	/* Hours, minutes, seconds are easy */
191cfcf6b6eSfujita 	rt.tm_hour = hms / 3600;
192cfcf6b6eSfujita 	rt.tm_min  = (hms % 3600) / 60;
193cfcf6b6eSfujita 	rt.tm_sec  = (hms % 3600) % 60;
194cfcf6b6eSfujita 
195cfcf6b6eSfujita 	/* Number of years in days */
196cfcf6b6eSfujita 	for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
197cfcf6b6eSfujita 	  	day -= days_in_year(i);
198cfcf6b6eSfujita 	rt.tm_year = i;
199cfcf6b6eSfujita 
200cfcf6b6eSfujita 	/* Number of months in days left */
201cfcf6b6eSfujita 	if (leapyear(rt.tm_year))
202cfcf6b6eSfujita 		days_in_month(FEBRUARY) = 29;
203cfcf6b6eSfujita 	for (i = 1; day >= days_in_month(i); i++)
204cfcf6b6eSfujita 		day -= days_in_month(i);
205cfcf6b6eSfujita 	days_in_month(FEBRUARY) = 28;
206cfcf6b6eSfujita 	rt.tm_mon = i;
207cfcf6b6eSfujita 
208cfcf6b6eSfujita 	/* Days are what is left over (+1) from all that. */
209cfcf6b6eSfujita 	rt.tm_mday = day + 1;
210cfcf6b6eSfujita 
211cfcf6b6eSfujita 	return(&rt);
212cfcf6b6eSfujita }
213cfcf6b6eSfujita 
bbc_to_gmt(timbuf)214cfcf6b6eSfujita bbc_to_gmt(timbuf)
215cfcf6b6eSfujita 	u_long *timbuf;
216cfcf6b6eSfujita {
217cfcf6b6eSfujita 	register int i,s;
218cfcf6b6eSfujita 	register u_long tmp;
219cfcf6b6eSfujita 	int year, month, day, hour, min, sec;
220cfcf6b6eSfujita 
221cfcf6b6eSfujita         if (!battery_clock)
222cfcf6b6eSfujita 	   return(0);
223cfcf6b6eSfujita 
224cfcf6b6eSfujita 	s = splimp();
225cfcf6b6eSfujita 
226cfcf6b6eSfujita 	/* read bb-clock */
2270f561374Sakito #ifdef LUNA2
2280f561374Sakito 	if (machineid == LUNA_II) {
229*2e3047bcSmckusick 		while (bbc2->cal_ctl_a & BBC2_A_UIP) {} /* wait (max 224 us) */
230*2e3047bcSmckusick 		bbc2->cal_ctl_b |= BBC2_B_SET;
2310f561374Sakito 		sec = bbc2->cal_sec;
2320f561374Sakito 		min = bbc2->cal_min;
2330f561374Sakito 		hour = bbc2->cal_hour;
2340f561374Sakito 		day = bbc2->cal_day;
2350f561374Sakito 		month = bbc2->cal_mon;
2360f561374Sakito 		year = bbc2->cal_year + 1900;
237*2e3047bcSmckusick 		bbc2->cal_ctl_b &= ~BBC2_B_SET;
2380f561374Sakito 	} else
2390f561374Sakito #endif
2400f561374Sakito 	{
241cfcf6b6eSfujita 		bbc->cal_ctl |= BBC_RD;
242cfcf6b6eSfujita 		sec = bcd_to_binary(bbc->cal_sec);
243cfcf6b6eSfujita 		min = bcd_to_binary(bbc->cal_min);
244cfcf6b6eSfujita 		hour = bcd_to_binary(bbc->cal_hour);
245cfcf6b6eSfujita 		day = bcd_to_binary(bbc->cal_day);
246cfcf6b6eSfujita 		month = bcd_to_binary(bbc->cal_mon);
247cfcf6b6eSfujita 		year = bcd_to_binary(bbc->cal_year) + 1900;
248cfcf6b6eSfujita 		bbc->cal_ctl &= ~BBC_RD;
2490f561374Sakito 	}
250cfcf6b6eSfujita 
251cfcf6b6eSfujita 	splx(s);
252cfcf6b6eSfujita 
253cfcf6b6eSfujita 	range_test(hour, 0, 23);
254cfcf6b6eSfujita 	range_test(day, 1, 31);
255cfcf6b6eSfujita 	range_test(month, 1, 12);
256*2e3047bcSmckusick 
2570f561374Sakito 	if (year < 1970) {
2580f561374Sakito 		year += 100;
2590f561374Sakito 	}
260cfcf6b6eSfujita 
261cfcf6b6eSfujita 	tmp = 0;
262cfcf6b6eSfujita 
263cfcf6b6eSfujita 	for (i = STARTOFTIME; i < year; i++)
264cfcf6b6eSfujita 	    tmp += days_in_year(i);
265cfcf6b6eSfujita 	if (leapyear(year) && month > FEBRUARY)
266cfcf6b6eSfujita 	    tmp++;
267cfcf6b6eSfujita 
268cfcf6b6eSfujita 	for (i = 1; i < month; i++)
269cfcf6b6eSfujita 	    tmp += days_in_month(i);
270cfcf6b6eSfujita 
271cfcf6b6eSfujita 	tmp += (day - 1);
272cfcf6b6eSfujita 	tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
273cfcf6b6eSfujita 
274cfcf6b6eSfujita 	*timbuf = tmp;
275cfcf6b6eSfujita 	return(1);
276cfcf6b6eSfujita }
277cfcf6b6eSfujita 
batterychk()278cfcf6b6eSfujita batterychk()
279cfcf6b6eSfujita {
280cfcf6b6eSfujita 	static char btchkdata[] = "chk";
281cfcf6b6eSfujita 
2820f561374Sakito #ifdef LUNA2
2830f561374Sakito 	if (machineid == LUNA_II) {
2840f561374Sakito 		/* not yet */
2850f561374Sakito 		battery_chkfg = 1;
2860f561374Sakito 		battery_clock = 1;
2870f561374Sakito 		return;
2880f561374Sakito 	}
2890f561374Sakito #endif
290cfcf6b6eSfujita 	/* if already checked, return */
291cfcf6b6eSfujita 	if (battery_chkfg)
292cfcf6b6eSfujita 		return;
293cfcf6b6eSfujita 
294cfcf6b6eSfujita 	battery_chkfg = 1;
295cfcf6b6eSfujita 	if (badaddr((caddr_t)bbc, 2))
296cfcf6b6eSfujita 		return;
297cfcf6b6eSfujita 
298cfcf6b6eSfujita 	strcpy(bbc->nvram.nv_testwrite, btchkdata);
299cfcf6b6eSfujita 	if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) {
300cfcf6b6eSfujita 		printf("WARNING: calendar clock battery down\n");
301cfcf6b6eSfujita 		return;
302cfcf6b6eSfujita 	}
303cfcf6b6eSfujita 	battery_clock = 1;
304cfcf6b6eSfujita 	return;
305cfcf6b6eSfujita }
3061e3a2a72Sakito 
3071e3a2a72Sakito #define	LUNA1_HZ	60
3081e3a2a72Sakito 
modify_clock_param()3091e3a2a72Sakito modify_clock_param()
3101e3a2a72Sakito {
3111e3a2a72Sakito 	extern int	hz, tick, tickadj;
3121e3a2a72Sakito 
3131e3a2a72Sakito 	if (machineid == LUNA_I) {
3141e3a2a72Sakito 		hz = LUNA1_HZ;
3151e3a2a72Sakito 		tick = 1000000 / hz;
3161e3a2a72Sakito 		tickadj = 30000 / (60 * hz);	/* can adjust 30ms in 60s */
3171e3a2a72Sakito 	}
3181e3a2a72Sakito }
319