1 /*
2 * Copyright (c) 1988 University of Utah.
3 * Copyright (c) 1992, 1993
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * the Systems Programming Group of the University of Utah Computer
8 * Science Department, Ralph Campbell, and Kazumasa Utashiro of
9 * Software Research Associates, Inc.
10 *
11 * %sccs.include.redist.c%
12 *
13 * from: Utah $Hdr: clock.c 1.18 91/01/21$
14 *
15 * @(#)clock.c 8.1 (Berkeley) 06/11/93
16 */
17
18 #include <machine/adrsmap.h>
19
20 #include <sys/param.h>
21 #include <sys/kernel.h>
22
23 #include <news3400/news3400/clockreg.h>
24
25 /*
26 * Machine-dependent clock routines.
27 *
28 * Startrtclock restarts the real-time clock, which provides
29 * hardclock interrupts to kern_clock.c.
30 *
31 * Inittodr initializes the time of day hardware which provides
32 * date functions. Its primary function is to use some file
33 * system information in case the hardare clock lost state.
34 *
35 * Resettodr restores the time of day hardware after a time change.
36 */
37
38 /*
39 * We assume newhz is either stathz or profhz, and that neither will
40 * change after being set up above. Could recalculate intervals here
41 * but that would be a drag.
42 */
43 void
setstatclockrate(newhz)44 setstatclockrate(newhz)
45 int newhz;
46 {
47
48 /* KU:XXX do something! */
49 }
50
51 /*
52 * Set up the real-time and statistics clocks. Leave stathz 0 only if
53 * no alternative timer is available.
54 */
cpu_initclocks()55 cpu_initclocks()
56 {
57
58 /*
59 * Start the real-time clock.
60 */
61 *(char *)ITIMER = IOCLOCK / 6144 / 100 - 1;
62
63 /*
64 * Enable the real-time clock.
65 */
66 *(char *)INTEN0 |= (char)INTEN0_TIMINT;
67 }
68
69 /*
70 * This code is defunct after 2099.
71 * Will Unix still be here then??
72 */
73 static short dayyr[12] = {
74 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
75 };
76
77 #define bcd_to_int(BCD) (i = BCD, (((i) >> 4) & 0xf) * 10 + ((i) & 0xf))
78 #define int_to_bcd(INT) (i = INT, ((((i) / 10) % 10) << 4) + (i) % 10)
79
80 /*
81 * Initialze the time of day register, based on the time base which is, e.g.
82 * from a filesystem. Base provides the time to within six months,
83 * and the time of year clock (if any) provides the rest.
84 */
inittodr(base)85 inittodr(base)
86 time_t base;
87 {
88 register volatile u_char *rtc_port = (u_char *)RTC_PORT;
89 register volatile u_char *rtc_data = (u_char *)DATA_PORT;
90 register int days, yr;
91 int sec, min, hour, week, day, mon, year;
92 long deltat, badbase = 0;
93 register u_int i;
94
95 if (base < 5*SECYR) {
96 printf("WARNING: preposterous time in file system\n");
97 /* read the system clock anyway */
98 base = 6*SECYR + 186*SECDAY + SECDAY/2;
99 badbase = 1;
100 }
101
102 *rtc_port = READ_CLOCK;
103 sec = bcd_to_int(*rtc_data++);
104 min = bcd_to_int(*rtc_data++);
105 hour = bcd_to_int(*rtc_data++);
106 week = bcd_to_int(*rtc_data++);
107 day = bcd_to_int(*rtc_data++);
108 mon = bcd_to_int(*rtc_data++);
109 year = bcd_to_int(*rtc_data++);
110 *rtc_port = 0;
111
112 /* simple sanity checks */
113 if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
114 hour > 23 || min > 59 || sec > 59) {
115 printf("WARNING: preposterous clock chip time\n");
116 /*
117 * Believe the time in the file system for lack of
118 * anything better, resetting the TODR.
119 */
120 time.tv_sec = base;
121 if (!badbase)
122 resettodr();
123 return (0);
124 }
125 days = 0;
126 for (yr = 70; yr < year; yr++)
127 days += LEAPYEAR(yr) ? 366 : 365;
128 days += dayyr[mon - 1] + day - 1;
129 if (LEAPYEAR(yr) && mon > 2)
130 days++;
131 /* now have days since Jan 1, 1970; the rest is easy... */
132 time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
133
134 if (!badbase) {
135 /*
136 * See if we gained/lost two or more days;
137 * if so, assume something is amiss.
138 */
139 deltat = time.tv_sec - base;
140 if (deltat < 0)
141 deltat = -deltat;
142 if (deltat < 2 * SECDAY)
143 return;
144 printf("WARNING: clock %s %d days",
145 time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
146 }
147 printf(" -- CHECK AND RESET THE DATE!\n");
148 }
149
150 /*
151 * Reset the TODR based on the time value; used when the TODR
152 * has a preposterous value and also when the time is reset
153 * by the stime system call. Also called when the TODR goes past
154 * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
155 * to wrap the TODR around.
156 */
resettodr()157 resettodr()
158 {
159 register volatile u_char *rtc_port = (u_char *)RTC_PORT;
160 register volatile u_char *rtc_data = (u_char *)DATA_PORT;
161 int sec, min, hour, week, day, mon, year;
162 register int t, t2, t3;
163 register int i;
164
165 /* compute the year */
166 t2 = time.tv_sec / SECDAY;
167 t = 69;
168 while (t2 >= 0) { /* whittle off years */
169 t3 = t2;
170 t++;
171 t2 -= LEAPYEAR(t) ? 366 : 365;
172 }
173
174 year = t;
175
176 /* t3 = month + day; separate */
177 t = LEAPYEAR(t);
178 for (t2 = 1; t2 < 12; t2++)
179 if (t3 < dayyr[t2] + (t && t2 > 1))
180 break;
181
182 /* t2 is month */
183 mon = t2;
184 t3 = t3 - dayyr[t2 - 1] + 1;
185 if (t && t2 > 2)
186 t3--;
187 day = t3;
188
189 week = 0;
190
191 /* the rest is easy */
192 t = time.tv_sec % SECDAY;
193 hour = t / 3600;
194 t %= 3600;
195 min = t / 60;
196 sec = t % 60;
197
198 *rtc_port = SET_CLOCK;
199 *rtc_data++ = int_to_bcd(sec);
200 *rtc_data++ = int_to_bcd(min);
201 *rtc_data++ = int_to_bcd(hour);
202 *rtc_data++ = int_to_bcd(week);
203 *rtc_data++ = int_to_bcd(day);
204 *rtc_data++ = int_to_bcd(mon);
205 *rtc_data = int_to_bcd(year);
206 *rtc_port = 0;
207 }
208