xref: /original-bsd/sys/luna68k/luna68k/clock.c (revision 95ecee29)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 OMRON Corporation.
4  * Copyright (c) 1982, 1990, 1992, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department.
10  *
11  * %sccs.include.redist.c%
12  *
13  * from: Utah $Hdr: clock.c 1.18 91/01/21$
14  * from: hp300/hp300/clock.c	7.19 (Berkeley) 2/18/93
15  *
16  *	@(#)clock.c	8.2 (Berkeley) 08/15/93
17  */
18 
19 #include <sys/param.h>
20 #include <sys/kernel.h>
21 
22 #include <machine/cpu.h>
23 #include <luna68k/luna68k/clockreg.h>
24 
25 extern int clock_on;
26 
27 static int month_days[12] = {
28     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
29 };
30 struct bbc_tm *gmt_to_bbc();
31 
32 volatile struct bbc *bbc = (struct bbc *)BBC_ADDR;
33 #ifdef LUNA2
34 volatile struct bbc2 *bbc2 = (struct bbc2 *)BBC_ADDR;
35 #endif
36 
37 int battery_clock;
38 int battery_chkfg;
39 
40 /*
41  * Machine-dependent clock routines.
42  *
43  * Startrtclock just checks battry backuped clock
44  * (when it does not work, starts it).
45  *
46  * Enablertclock sets flag for clock interrupt.
47  *
48  * Inittodr initializes the time of day hardware which provides
49  * date functions.
50  *
51  * Resettodr restores the time of day hardware after a time change.
52  *
53  */
54 
55 /*
56  * Start the real-time clock.
57  */
58 cpu_initclocks()
59 {
60 	static char *rtcstrings = "RTC";     /* For compat */
61 
62 	/* set flag for clockintr. */
63 	clock_on = 1;
64 
65 #ifdef LUNA2
66 	if (machineid == LUNA_II) {
67 		/* not yet */
68 		battery_chkfg = 1;
69 		battery_clock = 1;
70 		return;
71 	}
72 #endif
73 
74 	batterychk();
75 	if (!battery_clock)
76 	  return;
77 
78 	if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */
79 	  return;
80 
81 	printf("Initialize Battery Backup Clock.\n");
82 	bbc->cal_ctl |= BBC_WRT;
83 	bbc->cal_sec &= ~BBC_STOP;
84 	bbc->cal_hour |= BBC_KICK;
85 	bbc->cal_dow &= ~BBC_FRQ;
86 	bbc->cal_ctl &= ~BBC_WRT;
87 	DELAY(BBC_DELAY);
88 	bbc->cal_ctl |= BBC_WRT;
89 	bbc->cal_hour &= ~BBC_KICK;
90 	bbc->cal_ctl &= ~BBC_WRT;
91 	strcpy(bbc->nvram.nv_calclock, rtcstrings);
92 }
93 
94 void
95 setstatclockrate(newhz)
96         int newhz;
97 {
98 }
99 
100 microtime(tvp)
101         register struct timeval *tvp;
102 {
103         int s = splhigh();
104 
105         *tvp = time;
106         tvp->tv_usec += tick;
107         while (tvp->tv_usec > 1000000) {
108                 tvp->tv_sec++;
109                 tvp->tv_usec -= 1000000;
110         }
111         splx(s);
112 }
113 
114 /*
115  * Initialize the time of day register, based on the time base which is, e.g.
116  * from a filesystem.
117  */
118 inittodr(base)
119 	time_t base;
120 {
121 	u_long timbuf = base;	/* assume no battery clock exists */
122 
123 	/*
124 	 * bbc_to_gmt converts and stores the gmt in timbuf.
125 	 * If an error is detected in bbc_to_gmt, or if the filesystem
126 	 * time is more recent than the gmt time in the clock,
127 	 * then use the filesystem time and warn the user.
128  	 */
129 	if (!bbc_to_gmt(&timbuf) || timbuf < base) {
130 		printf("WARNING: bad date in battery clock\n");
131 		timbuf = base;
132 	}
133 	if (base < 5*SECYR) {
134 		printf("WARNING: preposterous time in file system");
135 		timbuf = 6*SECYR + 186*SECDAY + SECDAY/2;
136 		printf(" -- CHECK AND RESET THE DATE!\n");
137 	}
138 
139 	/* Battery clock does not store usec's, so forget about it. */
140 	time.tv_sec = timbuf;
141 }
142 
143 resettodr()
144 {
145 	register int i,s;
146 	register struct bbc_tm *tmptr;
147 
148 	tmptr = gmt_to_bbc(time.tv_sec);
149 
150 	s = splimp();
151 
152 	/* set bb-clock */
153 #ifdef LUNA2
154 	if (machineid == LUNA_II) {
155 		bbc2->cal_ctl_b |= BBC2_B_SET;
156 		bbc2->cal_sec = tmptr->tm_sec;
157 		bbc2->cal_min = tmptr->tm_min;
158 		bbc2->cal_hour =tmptr->tm_hour;
159 		bbc2->cal_day = tmptr->tm_mday;
160 		bbc2->cal_mon = tmptr->tm_mon;
161 		bbc2->cal_year = tmptr->tm_year;
162 		bbc2->cal_ctl_b &= ~BBC2_B_SET;
163 	} else
164 #endif
165 	{
166 		bbc->cal_ctl |= BBC_WRT;
167 		bbc->cal_sec = binary_to_bcd(tmptr->tm_sec);
168 		bbc->cal_min = binary_to_bcd(tmptr->tm_min);
169 		bbc->cal_hour = binary_to_bcd(tmptr->tm_hour);
170 		bbc->cal_day = binary_to_bcd(tmptr->tm_mday);
171 		bbc->cal_mon = binary_to_bcd(tmptr->tm_mon);
172 		bbc->cal_year = binary_to_bcd(tmptr->tm_year);
173 		bbc->cal_ctl &= ~BBC_WRT;
174 	}
175 
176 	splx(s);
177 }
178 
179 struct bbc_tm *
180 gmt_to_bbc(tim)
181 	long tim;
182 {
183 	register int i;
184 	register long hms, day;
185 	static struct bbc_tm rt;
186 
187 	day = tim / SECDAY;
188 	hms = tim % SECDAY;
189 
190 	/* Hours, minutes, seconds are easy */
191 	rt.tm_hour = hms / 3600;
192 	rt.tm_min  = (hms % 3600) / 60;
193 	rt.tm_sec  = (hms % 3600) % 60;
194 
195 	/* Number of years in days */
196 	for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
197 	  	day -= days_in_year(i);
198 	rt.tm_year = i;
199 
200 	/* Number of months in days left */
201 	if (leapyear(rt.tm_year))
202 		days_in_month(FEBRUARY) = 29;
203 	for (i = 1; day >= days_in_month(i); i++)
204 		day -= days_in_month(i);
205 	days_in_month(FEBRUARY) = 28;
206 	rt.tm_mon = i;
207 
208 	/* Days are what is left over (+1) from all that. */
209 	rt.tm_mday = day + 1;
210 
211 	return(&rt);
212 }
213 
214 bbc_to_gmt(timbuf)
215 	u_long *timbuf;
216 {
217 	register int i,s;
218 	register u_long tmp;
219 	int year, month, day, hour, min, sec;
220 
221         if (!battery_clock)
222 	   return(0);
223 
224 	s = splimp();
225 
226 	/* read bb-clock */
227 #ifdef LUNA2
228 	if (machineid == LUNA_II) {
229 		while (bbc2->cal_ctl_a & BBC2_A_UIP) {} /* wait (max 224 us) */
230 		bbc2->cal_ctl_b |= BBC2_B_SET;
231 		sec = bbc2->cal_sec;
232 		min = bbc2->cal_min;
233 		hour = bbc2->cal_hour;
234 		day = bbc2->cal_day;
235 		month = bbc2->cal_mon;
236 		year = bbc2->cal_year + 1900;
237 		bbc2->cal_ctl_b &= ~BBC2_B_SET;
238 	} else
239 #endif
240 	{
241 		bbc->cal_ctl |= BBC_RD;
242 		sec = bcd_to_binary(bbc->cal_sec);
243 		min = bcd_to_binary(bbc->cal_min);
244 		hour = bcd_to_binary(bbc->cal_hour);
245 		day = bcd_to_binary(bbc->cal_day);
246 		month = bcd_to_binary(bbc->cal_mon);
247 		year = bcd_to_binary(bbc->cal_year) + 1900;
248 		bbc->cal_ctl &= ~BBC_RD;
249 	}
250 
251 	splx(s);
252 
253 	range_test(hour, 0, 23);
254 	range_test(day, 1, 31);
255 	range_test(month, 1, 12);
256 
257 	if (year < 1970) {
258 		year += 100;
259 	}
260 
261 	tmp = 0;
262 
263 	for (i = STARTOFTIME; i < year; i++)
264 	    tmp += days_in_year(i);
265 	if (leapyear(year) && month > FEBRUARY)
266 	    tmp++;
267 
268 	for (i = 1; i < month; i++)
269 	    tmp += days_in_month(i);
270 
271 	tmp += (day - 1);
272 	tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
273 
274 	*timbuf = tmp;
275 	return(1);
276 }
277 
278 batterychk()
279 {
280 	static char btchkdata[] = "chk";
281 
282 #ifdef LUNA2
283 	if (machineid == LUNA_II) {
284 		/* not yet */
285 		battery_chkfg = 1;
286 		battery_clock = 1;
287 		return;
288 	}
289 #endif
290 	/* if already checked, return */
291 	if (battery_chkfg)
292 		return;
293 
294 	battery_chkfg = 1;
295 	if (badaddr((caddr_t)bbc, 2))
296 		return;
297 
298 	strcpy(bbc->nvram.nv_testwrite, btchkdata);
299 	if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) {
300 		printf("WARNING: calendar clock battery down\n");
301 		return;
302 	}
303 	battery_clock = 1;
304 	return;
305 }
306 
307 #define	LUNA1_HZ	60
308 
309 modify_clock_param()
310 {
311 	extern int	hz, tick, tickadj;
312 
313 	if (machineid == LUNA_I) {
314 		hz = LUNA1_HZ;
315 		tick = 1000000 / hz;
316 		tickadj = 30000 / (60 * hz);	/* can adjust 30ms in 60s */
317 	}
318 }
319