xref: /original-bsd/sys/luna68k/luna68k/clock.c (revision 07303858)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 OMRON Corporation.
4  * Copyright (c) 1982, 1990, 1992 The Regents of the University of California.
5  * 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	7.6 (Berkeley) 03/17/93
17  */
18 
19 #include <sys/param.h>
20 #include <sys/kernel.h>
21 
22 #include <luna68k/luna68k/clockreg.h>
23 
24 extern int clock_on;
25 
26 static int month_days[12] = {
27     31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
28 };
29 struct bbc_tm *gmt_to_bbc();
30 
31 volatile struct bbc *bbc = (struct bbc *)BBC_ADDR;
32 
33 int battery_clock;
34 int battery_chkfg;
35 
36 /*
37  * Machine-dependent clock routines.
38  *
39  * Startrtclock just checks battry backuped clock
40  * (when it does not work, starts it).
41  *
42  * Enablertclock sets flag for clock interrupt.
43  *
44  * Inittodr initializes the time of day hardware which provides
45  * date functions.
46  *
47  * Resettodr restores the time of day hardware after a time change.
48  *
49  */
50 
51 /*
52  * Start the real-time clock.
53  */
54 cpu_initclocks()
55 {
56 	static char *rtcstrings = "RTC";     /* For compat */
57 
58 	/* set flag for clockintr. */
59 	clock_on = 1;
60 
61 	batterychk();
62 	if (!battery_clock)
63 	  return;
64 
65 	if (!strncmp(bbc->nvram.nv_calclock, rtcstrings, sizeof(rtcstrings))) /* Okey */
66 	  return;
67 
68 	printf("Initialize Battery Backup Clock.\n");
69 	bbc->cal_ctl |= BBC_WRT;
70 	bbc->cal_sec &= ~BBC_STOP;
71 	bbc->cal_hour |= BBC_KICK;
72 	bbc->cal_dow &= ~BBC_FRQ;
73 	bbc->cal_ctl &= ~BBC_WRT;
74 	DELAY(BBC_DELAY);
75 	bbc->cal_ctl |= BBC_WRT;
76 	bbc->cal_hour &= ~BBC_KICK;
77 	bbc->cal_ctl &= ~BBC_WRT;
78 	strcpy(bbc->nvram,rtcstrings);
79 }
80 
81 void
82 setstatclockrate(newhz)
83         int newhz;
84 {
85 }
86 
87 microtime(tvp)
88         register struct timeval *tvp;
89 {
90         int s = splhigh();
91 
92         *tvp = time;
93         tvp->tv_usec += tick;
94         while (tvp->tv_usec > 1000000) {
95                 tvp->tv_sec++;
96                 tvp->tv_usec -= 1000000;
97         }
98         splx(s);
99 }
100 
101 /*
102  * Initialize the time of day register, based on the time base which is, e.g.
103  * from a filesystem.
104  */
105 inittodr(base)
106 	time_t base;
107 {
108 	u_long timbuf = base;	/* assume no battery clock exists */
109 
110 	/*
111 	 * bbc_to_gmt converts and stores the gmt in timbuf.
112 	 * If an error is detected in bbc_to_gmt, or if the filesystem
113 	 * time is more recent than the gmt time in the clock,
114 	 * then use the filesystem time and warn the user.
115  	 */
116 	if (!bbc_to_gmt(&timbuf) || timbuf < base) {
117 		printf("WARNING: bad date in battery clock\n");
118 		timbuf = base;
119 	}
120 	if (base < 5*SECYR) {
121 		printf("WARNING: preposterous time in file system");
122 		timbuf = 6*SECYR + 186*SECDAY + SECDAY/2;
123 		printf(" -- CHECK AND RESET THE DATE!\n");
124 	}
125 
126 	/* Battery clock does not store usec's, so forget about it. */
127 	time.tv_sec = timbuf;
128 }
129 
130 resettodr()
131 {
132 	register int i,s;
133 	register struct bbc_tm *tmptr;
134 
135 	tmptr = gmt_to_bbc(time.tv_sec);
136 
137 	s = splimp();
138 
139 	/* set bb-clock */
140 	bbc->cal_ctl |= BBC_WRT;
141 	bbc->cal_sec = binary_to_bcd(tmptr->tm_sec);
142 	bbc->cal_min = binary_to_bcd(tmptr->tm_min);
143 	bbc->cal_hour = binary_to_bcd(tmptr->tm_hour);
144 	bbc->cal_day = binary_to_bcd(tmptr->tm_mday);
145 	bbc->cal_mon = binary_to_bcd(tmptr->tm_mon);
146 	bbc->cal_year = binary_to_bcd(tmptr->tm_year);
147 	bbc->cal_ctl &= ~BBC_WRT;
148 
149 	splx(s);
150 }
151 
152 struct bbc_tm *
153 gmt_to_bbc(tim)
154 	long tim;
155 {
156 	register int i;
157 	register long hms, day;
158 	static struct bbc_tm rt;
159 
160 	day = tim / SECDAY;
161 	hms = tim % SECDAY;
162 
163 	/* Hours, minutes, seconds are easy */
164 	rt.tm_hour = hms / 3600;
165 	rt.tm_min  = (hms % 3600) / 60;
166 	rt.tm_sec  = (hms % 3600) % 60;
167 
168 	/* Number of years in days */
169 	for (i = STARTOFTIME - 1900; day >= days_in_year(i); i++)
170 	  	day -= days_in_year(i);
171 	rt.tm_year = i;
172 
173 	/* Number of months in days left */
174 	if (leapyear(rt.tm_year))
175 		days_in_month(FEBRUARY) = 29;
176 	for (i = 1; day >= days_in_month(i); i++)
177 		day -= days_in_month(i);
178 	days_in_month(FEBRUARY) = 28;
179 	rt.tm_mon = i;
180 
181 	/* Days are what is left over (+1) from all that. */
182 	rt.tm_mday = day + 1;
183 
184 	return(&rt);
185 }
186 
187 bbc_to_gmt(timbuf)
188 	u_long *timbuf;
189 {
190 	register int i,s;
191 	register u_long tmp;
192 	int year, month, day, hour, min, sec;
193 
194         if (!battery_clock)
195 	   return(0);
196 
197 	s = splimp();
198 
199 	/* read bb-clock */
200 	bbc->cal_ctl |= BBC_RD;
201 	sec = bcd_to_binary(bbc->cal_sec);
202 	min = bcd_to_binary(bbc->cal_min);
203 	hour = bcd_to_binary(bbc->cal_hour);
204 	day = bcd_to_binary(bbc->cal_day);
205 	month = bcd_to_binary(bbc->cal_mon);
206 	year = bcd_to_binary(bbc->cal_year) + 1900;
207 	bbc->cal_ctl &= ~BBC_RD;
208 
209 	splx(s);
210 
211 	range_test(hour, 0, 23);
212 	range_test(day, 1, 31);
213 	range_test(month, 1, 12);
214 	range_test(year, STARTOFTIME, 2000);
215 
216 	tmp = 0;
217 
218 	for (i = STARTOFTIME; i < year; i++)
219 	    tmp += days_in_year(i);
220 	if (leapyear(year) && month > FEBRUARY)
221 	    tmp++;
222 
223 	for (i = 1; i < month; i++)
224 	    tmp += days_in_month(i);
225 
226 	tmp += (day - 1);
227 	tmp = ((tmp * 24 + hour) * 60 + min) * 60 + sec;
228 
229 	*timbuf = tmp;
230 	return(1);
231 }
232 
233 batterychk()
234 {
235 	static char btchkdata[] = "chk";
236 
237 	/* if already checked, return */
238 	if (battery_chkfg)
239 		return;
240 
241 	battery_chkfg = 1;
242 	if (badaddr((caddr_t)bbc, 2))
243 		return;
244 
245 	strcpy(bbc->nvram.nv_testwrite, btchkdata);
246 	if (strncmp(bbc->nvram.nv_testwrite, btchkdata, sizeof(btchkdata))) {
247 		printf("WARNING: calendar clock battery down\n");
248 		return;
249 	}
250 	battery_clock = 1;
251 	return;
252 }
253