xref: /original-bsd/sys/pmax/pmax/clock.c (revision 753853ba)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 The Regents of the University of California.
4  * 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 and Ralph Campbell.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: clock.c 1.18 91/01/21$
13  *
14  *	@(#)clock.c	7.2 (Berkeley) 02/29/92
15  */
16 
17 #include "param.h"
18 #include "kernel.h"
19 
20 #include "../include/machConst.h"
21 #include "clockreg.h"
22 
23 /*
24  * Machine-dependent clock routines.
25  *
26  * Startrtclock restarts the real-time clock, which provides
27  * hardclock interrupts to kern_clock.c.
28  *
29  * Inittodr initializes the time of day hardware which provides
30  * date functions.  Its primary function is to use some file
31  * system information in case the hardare clock lost state.
32  *
33  * Resettodr restores the time of day hardware after a time change.
34  */
35 
36 /*
37  * Start the real-time clock.
38  */
39 startrtclock()
40 {
41 	register volatile struct chiptime *c;
42 	extern int tickadj;
43 
44 	tick = 15625;		/* number of micro-seconds between interrupts */
45 	hz = 1000000 / 15625;	/* about 64 */
46 	tickadj = 240000 / (60000000 / 15625);
47 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
48 	c->rega = REGA_TIME_BASE | SELECTED_RATE;
49 	c->regb = REGB_PER_INT_ENA | REGB_DATA_MODE | REGB_HOURS_FORMAT;
50 }
51 
52 /*
53  * This code is defunct after 2099.
54  * Will Unix still be here then??
55  */
56 static short dayyr[12] = {
57 	0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
58 };
59 
60 /*
61  * Initialze the time of day register, based on the time base which is, e.g.
62  * from a filesystem.  Base provides the time to within six months,
63  * and the time of year clock (if any) provides the rest.
64  */
65 inittodr(base)
66 	time_t base;
67 {
68 	register volatile struct chiptime *c;
69 	register int days, yr;
70 	int sec, min, hour, day, mon, year;
71 	long deltat, badbase = 0;
72 	int s;
73 
74 	if (base < 5*SECYR) {
75 		printf("WARNING: preposterous time in file system\n");
76 		/* read the system clock anyway */
77 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
78 		badbase = 1;
79 	}
80 
81 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
82 	/* don't read clock registers while they are being updated */
83 	s = splclock();
84 	while ((c->rega & REGA_UIP) == 1)
85 		;
86 	sec = c->sec;
87 	min = c->min;
88 	hour = c->hour;
89 	day = c->day;
90 	mon = c->mon;
91 	year = c->year + 19;
92 	splx(s);
93 
94 	/* simple sanity checks */
95 	if (year < 70 || mon < 1 || mon > 12 || day < 1 || day > 31 ||
96 	    hour > 23 || min > 59 || sec > 59) {
97 		printf("WARNING: preposterous clock chip time");
98 		/*
99 		 * Believe the time in the file system for lack of
100 		 * anything better, resetting the TODR.
101 		 */
102 		time.tv_sec = base;
103 		if (!badbase)
104 			resettodr();
105 		return (0);
106 	}
107 	days = 0;
108 	for (yr = 70; yr < year; yr++)
109 		days += LEAPYEAR(yr) ? 366 : 365;
110 	days += dayyr[mon - 1] + day - 1;
111 	if (LEAPYEAR(yr) && mon > 2)
112 		days++;
113 	/* now have days since Jan 1, 1970; the rest is easy... */
114 	time.tv_sec = days * SECDAY + hour * 3600 + min * 60 + sec;
115 
116 	if (!badbase) {
117 		/*
118 		 * See if we gained/lost two or more days;
119 		 * if so, assume something is amiss.
120 		 */
121 		deltat = time.tv_sec - base;
122 		if (deltat < 0)
123 			deltat = -deltat;
124 		if (deltat < 2 * SECDAY)
125 			return;
126 		printf("WARNING: clock %s %d days",
127 		    time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
128 	}
129 	printf(" -- CHECK AND RESET THE DATE!\n");
130 }
131 
132 /*
133  * Reset the TODR based on the time value; used when the TODR
134  * has a preposterous value and also when the time is reset
135  * by the stime system call.  Also called when the TODR goes past
136  * TODRZERO + 100*(SECYEAR+2*SECDAY) (e.g. on Jan 2 just after midnight)
137  * to wrap the TODR around.
138  */
139 resettodr()
140 {
141 	register volatile struct chiptime *c;
142 	register int t, t2, t3;
143 	int s;
144 
145 	/* compute the year */
146 	t2 = time.tv_sec / SECDAY;
147 	t = 69;
148 	while (t2 >= 0) {	/* whittle off years */
149 		t3 = t2;
150 		t++;
151 		t2 -= LEAPYEAR(t) ? 366 : 365;
152 	}
153 
154 	c = (volatile struct chiptime *)MACH_CLOCK_ADDR;
155 	s = splclock();
156 	c->regb |= REGB_SET_TIME;
157 	c->year = t - 19;
158 
159 	/* t3 = month + day; separate */
160 	t = LEAPYEAR(t);
161 	for (t2 = 1; t2 < 12; t2++)
162 		if (t3 < dayyr[t2] + (t && t2 > 1))
163 			break;
164 
165 	/* t2 is month */
166 	c->mon = t2;
167 	t3 = t3 - dayyr[t2 - 1] + 1;
168 	if (t && t2 > 2)
169 		t3--;
170 	c->day = t3;
171 
172 	/* the rest is easy */
173 	t = time.tv_sec % SECDAY;
174 	c->hour = t / 3600;
175 	t %= 3600;
176 	c->min = t / 60;
177 	c->sec = t % 60;
178 	c->regb &= ~REGB_SET_TIME;
179 	MachEmptyWriteBuffer();
180 	splx(s);
181 }
182