xref: /csrg-svn/sys/i386/isa/clock.c (revision 49573)
1 /*-
2  * Copyright (c) 1990 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * William Jolitz.
7  *
8  * Added stuff to read the cmos clock on startup - Don Ahn
9  *
10  * %sccs.include.386.c%
11  *
12  *	@(#)clock.c	5.5 (Berkeley) 05/09/91
13  */
14 
15 /*
16  * Primitive clock interrupt routines.
17  */
18 #include "param.h"
19 #include "time.h"
20 #include "kernel.h"
21 #include "machine/segments.h"
22 #include "i386/isa/icu.h"
23 #include "i386/isa/isa.h"
24 #include "i386/isa/rtc.h"
25 
26 #define DAYST 119
27 #define DAYEN 303
28 
29 startrtclock() {
30 	int s;
31 
32 	/* initialize 8253 clock */
33 	outb (IO_TIMER1+3, 0x36);
34 	outb (IO_TIMER1, 1193182/hz);
35 	outb (IO_TIMER1, (1193182/hz)/256);
36 
37 #ifdef notdef
38 	/* NMI fail safe 1/4 sec  */
39 	/* initialize 8253 clock */
40 	outb(0x461,0);
41 	outb (IO_TIMER2+3, 0x30);
42 	outb (IO_TIMER2, 298300*40);
43 	outb (IO_TIMER2, (298300*40)/256);
44 	outb(0x461,4);
45 printf("armed ");
46 #endif
47 
48 	/* initialize brain-dead battery powered clock */
49 	outb (IO_RTC, RTC_STATUSA);
50 	outb (IO_RTC+1, 0x26);
51 	outb (IO_RTC, RTC_STATUSB);
52 	outb (IO_RTC+1, 2);
53 
54 	/*outb (IO_RTC, RTC_STATUSD);
55 	if((inb(IO_RTC+1) & 0x80) == 0)
56 		printf("rtc lost power\n");
57 	outb (IO_RTC, RTC_STATUSD);
58 	outb (IO_RTC+1, 0x80);*/
59 
60 	outb (IO_RTC, RTC_DIAG);
61 	if (s = inb (IO_RTC+1))
62 		printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
63 	outb (IO_RTC, RTC_DIAG);
64 	outb (IO_RTC+1, 0);
65 }
66 
67 #ifdef ARGOx
68 reprimefailsafe(){
69 	outb(0x461,0);
70 	outb (IO_TIMER2+3, 0x30);
71 	outb (IO_TIMER2, 298300*40);
72 	outb (IO_TIMER2, (298300*40)/256);
73 	outb(0x461,4);
74 }
75 #endif
76 
77 /* convert 2 digit BCD number */
78 bcd(i)
79 int i;
80 {
81 	return ((i/16)*10 + (i%16));
82 }
83 
84 /* convert years to seconds (from 1970) */
85 unsigned long
86 ytos(y)
87 int y;
88 {
89 	int i;
90 	unsigned long ret;
91 
92 	ret = 0; y = y - 70;
93 	for(i=0;i<y;i++) {
94 		if (i % 4) ret += 365*24*60*60;
95 		else ret += 366*24*60*60;
96 	}
97 	return ret;
98 }
99 
100 /* convert months to seconds */
101 unsigned long
102 mtos(m,leap)
103 int m,leap;
104 {
105 	int i;
106 	unsigned long ret;
107 
108 	ret = 0;
109 	for(i=1;i<m;i++) {
110 		switch(i){
111 		case 1: case 3: case 5: case 7: case 8: case 10: case 12:
112 			ret += 31*24*60*60; break;
113 		case 4: case 6: case 9: case 11:
114 			ret += 30*24*60*60; break;
115 		case 2:
116 			if (leap) ret += 29*24*60*60;
117 			else ret += 28*24*60*60;
118 		}
119 	}
120 	return ret;
121 }
122 
123 
124 /*
125  * Initialize the time of day register, based on the time base which is, e.g.
126  * from a filesystem.
127  */
128 inittodr(base)
129 	time_t base;
130 {
131 	unsigned long sec;
132 	int leap,day_week,t,yd;
133 int sa,s;
134 
135 	/* do we have a realtime clock present? (otherwise we loop below) */
136 	sa = rtcin(RTC_STATUSA);
137 	if (sa == 0xff || sa == 0) return;
138 
139 	/* ready for a read? */
140 	while ((sa&RTCSA_TUP) == RTCSA_TUP)
141 		sa = rtcin(RTC_STATUSA);
142 
143 	sec = bcd(rtcin(RTC_YEAR));
144 	leap = !(sec % 4); sec += ytos(sec); /* year    */
145 	yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd;	/* month   */
146 	t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date    */
147 	day_week = rtcin(RTC_WDAY);				/* day     */
148 	sec += bcd(rtcin(RTC_HRS)) * 60*60;			/* hour    */
149 	sec += bcd(rtcin(RTC_MIN)) * 60;			/* minutes */
150 	sec += bcd(rtcin(RTC_SEC));				/* seconds */
151 	sec -= 24*60*60; /* XXX why ??? */
152 
153 #ifdef notdef
154 	/* XXX off by one? Need to calculate DST on SUNDAY */
155 	/* Perhaps we should have the RTC hold GMT time to save */
156 	/* us the bother of converting. */
157 	yd = yd / 24*60*60;
158 	if ((yd >= DAYST) && ( yd <= DAYEN)) {
159 		sec -= 60*60;
160 	}
161 #endif
162 	sec += tz.tz_minuteswest * 60;
163 
164 	time.tv_sec = sec;
165 }
166 
167 #ifdef garbage
168 /*
169  * Initialze the time of day register, based on the time base which is, e.g.
170  * from a filesystem.
171  */
172 test_inittodr(base)
173 	time_t base;
174 {
175 
176 	outb(IO_RTC,9); /* year    */
177 	printf("%d ",bcd(inb(IO_RTC+1)));
178 	outb(IO_RTC,8); /* month   */
179 	printf("%d ",bcd(inb(IO_RTC+1)));
180 	outb(IO_RTC,7); /* day     */
181 	printf("%d ",bcd(inb(IO_RTC+1)));
182 	outb(IO_RTC,4); /* hour    */
183 	printf("%d ",bcd(inb(IO_RTC+1)));
184 	outb(IO_RTC,2); /* minutes */
185 	printf("%d ",bcd(inb(IO_RTC+1)));
186 	outb(IO_RTC,0); /* seconds */
187 	printf("%d\n",bcd(inb(IO_RTC+1)));
188 
189 	time.tv_sec = base;
190 }
191 #endif
192 
193 #ifdef notdef
194 /*
195  * retreve a value from realtime clock
196  */
197 u_char rtcin(n) {
198 	u_char val;
199 
200 	/*outb(IO_RTC, RTC_STATUSA);
201 	do val = inb(IO_RTC+1) ; while (val&0x80);*/
202 
203 	outb(IO_RTC,n);
204 	DELAY(100);
205 	if (inb(IO_RTC) != n) {
206 		outb(IO_RTC,n);
207 		DELAY(100);
208 	}
209 	do val = inb(IO_RTC+1) ; while (val != inb(IO_RTC+1));
210 	return (val);
211 }
212 #endif
213 
214 /*
215  * Restart the clock.
216  */
217 resettodr()
218 {
219 }
220 
221 #define V(s)	__CONCAT(V, s)
222 extern V(clk)();
223 enablertclock() {
224 	INTREN(IRQ0);
225 	setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
226 	splnone();
227 }
228