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