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 */
cpu_initclocks()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
setstatclockrate(newhz)95 setstatclockrate(newhz)
96 int newhz;
97 {
98 }
99
microtime(tvp)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 */
inittodr(base)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
resettodr()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 *
gmt_to_bbc(tim)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
bbc_to_gmt(timbuf)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
batterychk()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
modify_clock_param()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