xref: /netbsd/sys/arch/sandpoint/isa/isaclock.c (revision bf9ec67e)
1 /*	$NetBSD: isaclock.c,v 1.2 2001/07/22 15:04:00 wiz Exp $	*/
2 
3 /*-
4  * Copyright (c) 1993, 1994 Charles M. Hannum.
5  * Copyright (c) 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * William Jolitz and Don Ahn.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  * 4. Neither the name of the University nor the names of its contributors
24  *    may be used to endorse or promote products derived from this software
25  *    without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37  * SUCH DAMAGE.
38  *
39  *	@(#)clock.c	7.2 (Berkeley) 5/12/91
40  */
41 /*
42  * Mach Operating System
43  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
44  * All Rights Reserved.
45  *
46  * Permission to use, copy, modify and distribute this software and its
47  * documentation is hereby granted, provided that both the copyright
48  * notice and this permission notice appear in all copies of the
49  * software, derivative works or modified versions, and any portions
50  * thereof, and that both notices appear in supporting documentation.
51  *
52  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
53  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
54  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
55  *
56  * Carnegie Mellon requests users of this software to return to
57  *
58  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
59  *  School of Computer Science
60  *  Carnegie Mellon University
61  *  Pittsburgh PA 15213-3890
62  *
63  * any improvements or extensions that they make and grant Carnegie Mellon
64  * the rights to redistribute these changes.
65  */
66 /*
67   Copyright 1988, 1989 by Intel Corporation, Santa Clara, California.
68 
69 		All Rights Reserved
70 
71 Permission to use, copy, modify, and distribute this software and
72 its documentation for any purpose and without fee is hereby
73 granted, provided that the above copyright notice appears in all
74 copies and that both the copyright notice and this permission notice
75 appear in supporting documentation, and that the name of Intel
76 not be used in advertising or publicity pertaining to distribution
77 of the software without specific, written prior permission.
78 
79 INTEL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
80 INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
81 IN NO EVENT SHALL INTEL BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
82 CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
83 LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
84 NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
85 WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
86 */
87 
88 /*
89  * Primitive clock interrupt routines.
90  */
91 #include <sys/param.h>
92 #include <sys/systm.h>
93 #include <sys/callout.h>
94 #include <sys/time.h>
95 #include <sys/kernel.h>
96 #include <sys/device.h>
97 
98 #include <machine/cpu.h>
99 #include <machine/intr.h>
100 #include <machine/pio.h>
101 
102 #include <dev/isa/isareg.h>
103 #include <dev/isa/isavar.h>
104 #include <dev/ic/mc146818reg.h>
105 #include <dev/ic/i8253reg.h>
106 #include <sandpoint/isa/nvram.h>
107 #include <sandpoint/isa/spkrreg.h>
108 
109 extern void disable_intr(void);	/* In locore.S */
110 extern void enable_intr(void);	/* In locore.S */
111 
112 void	sysbeepstop __P((void *));
113 void	sysbeep __P((int, int));
114 void	rtcinit __P((void));
115 int	rtcget __P((mc_todregs *));
116 void	rtcput __P((mc_todregs *));
117 static int yeartoday __P((int));
118 int 	hexdectodec __P((int));
119 int	dectohexdec __P((int));
120 
121 __inline u_int mc146818_read __P((void *, u_int));
122 __inline void mc146818_write __P((void *, u_int, u_int));
123 
124 #define	SECMIN	((unsigned)60)			/* seconds per minute */
125 #define	SECHOUR	((unsigned)(60*SECMIN))		/* seconds per hour */
126 #define	SECDAY	((unsigned)(24*SECHOUR))	/* seconds per day */
127 #define	SECYR	((unsigned)(365*SECDAY))	/* seconds per common year */
128 
129 __inline u_int
130 mc146818_read(sc, reg)
131 	void *sc;					/* XXX use it? */
132 	u_int reg;
133 {
134 
135 	isa_outb(IO_RTC, (u_char)reg);
136 	return (isa_inb(IO_RTC+1));
137 }
138 
139 __inline void
140 mc146818_write(sc, reg, datum)
141 	void *sc;					/* XXX use it? */
142 	u_int reg, datum;
143 {
144 
145 	isa_outb(IO_RTC, reg);
146 	isa_outb(IO_RTC+1, datum);
147 }
148 
149 static int beeping;
150 
151 void
152 sysbeepstop(arg)
153 	void *arg;
154 {
155 	/* disable counter 2 */
156 	disable_intr();
157 	isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) & ~PIT_SPKR);
158 	enable_intr();
159 	beeping = 0;
160 }
161 
162 void
163 sysbeep(pitch, period)
164 	int pitch, period;
165 {
166 	static struct callout sysbeep_ch = CALLOUT_INITIALIZER;
167 	static int last_pitch;
168 
169 	if (beeping)
170 		callout_stop(&sysbeep_ch);
171 	if (pitch == 0 || period == 0) {
172 		sysbeepstop(0);
173 		last_pitch = 0;
174 		return;
175 	}
176 	if (!beeping || last_pitch != pitch) {
177 		disable_intr();
178 		isa_outb(IO_TIMER1 + TIMER_MODE,
179 			 TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
180 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) % 256);
181 		isa_outb(IO_TIMER1 + TIMER_CNTR2, TIMER_DIV(pitch) / 256);
182 		isa_outb(PITAUX_PORT, isa_inb(PITAUX_PORT) | PIT_SPKR);	/* enable counter 2 */
183 		enable_intr();
184 	}
185 	last_pitch = pitch;
186 	beeping = 1;
187 	callout_reset(&sysbeep_ch, period, sysbeepstop, NULL);
188 }
189 
190 void
191 rtcinit()
192 {
193 	static int first_rtcopen_ever = 1;
194 
195 	if (!first_rtcopen_ever)
196 		return;
197 	first_rtcopen_ever = 0;
198 
199 	mc146818_write(NULL, MC_REGA,			/* XXX softc */
200 	    MC_BASE_32_KHz | MC_RATE_1024_Hz);
201 	mc146818_write(NULL, MC_REGB, MC_REGB_24HR);	/* XXX softc */
202 }
203 
204 int
205 rtcget(regs)
206 	mc_todregs *regs;
207 {
208 
209 	rtcinit();
210 	if ((mc146818_read(NULL, MC_REGD) & MC_REGD_VRT) == 0) /* XXX softc */
211 		return (-1);
212 	MC146818_GETTOD(NULL, regs);			/* XXX softc */
213 	return (0);
214 }
215 
216 void
217 rtcput(regs)
218 	mc_todregs *regs;
219 {
220 
221 	rtcinit();
222 	MC146818_PUTTOD(NULL, regs);			/* XXX softc */
223 }
224 
225 static int month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
226 
227 static int
228 yeartoday(year)
229 	int year;
230 {
231 
232 	return ((year % 4) ? 365 : 366);
233 }
234 
235 int
236 hexdectodec(n)
237 	int n;
238 {
239 
240 	return (((n >> 4) & 0x0f) * 10 + (n & 0x0f));
241 }
242 
243 int
244 dectohexdec(n)
245 	int n;
246 {
247 
248 	return ((u_char)(((n / 10) << 4) & 0xf0) | ((n % 10) & 0x0f));
249 }
250 
251 static int timeset;
252 
253 /*
254  * Initialize the time of day register, based on the time base which is, e.g.
255  * from a filesystem.
256  */
257 void
258 inittodr(base)
259 	time_t base;
260 {
261 	mc_todregs rtclk;
262 	time_t n;
263 	int sec, min, hr, dom, mon, yr;
264 	int i, days = 0;
265 	int s;
266 
267 	/*
268 	 * We mostly ignore the suggested time and go for the RTC clock time
269 	 * stored in the CMOS RAM.  If the time can't be obtained from the
270 	 * CMOS, or if the time obtained from the CMOS is 5 or more years
271 	 * less than the suggested time, we used the suggested time.  (In
272 	 * the latter case, it's likely that the CMOS battery has died.)
273 	 */
274 
275 	if (base < 15*SECYR) {	/* if before 1985, something's odd... */
276 		printf("WARNING: preposterous time in file system\n");
277 		/* read the system clock anyway */
278 		base = 17*SECYR + 186*SECDAY + SECDAY/2;
279 	}
280 
281 	s = splclock();
282 	if (rtcget(&rtclk)) {
283 		splx(s);
284 		printf("WARNING: invalid time in clock chip\n");
285 		goto fstime;
286 	}
287 	splx(s);
288 
289 	sec = hexdectodec(rtclk[MC_SEC]);
290 	min = hexdectodec(rtclk[MC_MIN]);
291 	hr = hexdectodec(rtclk[MC_HOUR]);
292 	dom = hexdectodec(rtclk[MC_DOM]);
293 	mon = hexdectodec(rtclk[MC_MONTH]);
294 	yr = hexdectodec(rtclk[MC_YEAR]);
295 	yr = (yr < 70) ? yr+100 : yr;
296 
297 	n = sec + 60 * min + 3600 * hr;
298 	n += (dom - 1) * 3600 * 24;
299 
300 	if (yeartoday(yr) == 366)
301 		month[1] = 29;
302 	for (i = mon - 2; i >= 0; i--)
303 		days += month[i];
304 	month[1] = 28;
305 	for (i = 70; i < yr; i++)
306 		days += yeartoday(i);
307 	n += days * 3600 * 24;
308 
309 	n += rtc_offset * 60;
310 
311 	if (base < n - 5*SECYR)
312 		printf("WARNING: file system time much less than clock time\n");
313 	else if (base > n + 5*SECYR) {
314 		printf("WARNING: clock time much less than file system time\n");
315 		printf("WARNING: using file system time\n");
316 		goto fstime;
317 	}
318 
319 	timeset = 1;
320 	time.tv_sec = n;
321 	time.tv_usec = 0;
322 	return;
323 
324 fstime:
325 	timeset = 1;
326 	time.tv_sec = base;
327 	time.tv_usec = 0;
328 	printf("WARNING: CHECK AND RESET THE DATE!\n");
329 }
330 
331 /*
332  * Reset the clock.
333  */
334 void
335 resettodr()
336 {
337 	mc_todregs rtclk;
338 	time_t n;
339 	int diff, i, j;
340 	int s;
341 
342 	/*
343 	 * We might have been called by boot() due to a crash early
344 	 * on.  Don't reset the clock chip in this case.
345 	 */
346 	if (!timeset)
347 		return;
348 
349 	s = splclock();
350 	if (rtcget(&rtclk))
351 		memset(&rtclk, 0, sizeof(rtclk));
352 	splx(s);
353 
354 	diff = rtc_offset * 60;
355 	n = (time.tv_sec - diff) % (3600 * 24);   /* hrs+mins+secs */
356 	rtclk[MC_SEC] = dectohexdec(n % 60);
357 	n /= 60;
358 	rtclk[MC_MIN] = dectohexdec(n % 60);
359 	rtclk[MC_HOUR] = dectohexdec(n / 60);
360 
361 	n = (time.tv_sec - diff) / (3600 * 24);	/* days */
362 	rtclk[MC_DOW] = (n + 4) % 7;  /* 1/1/70 is Thursday */
363 
364 	for (j = 1970, i = yeartoday(j); n >= i; j++, i = yeartoday(j))
365 		n -= i;
366 
367 	rtclk[MC_YEAR] = dectohexdec(j - 1900);
368 
369 	if (i == 366)
370 		month[1] = 29;
371 	for (i = 0; n >= month[i]; i++)
372 		n -= month[i];
373 	month[1] = 28;
374 	rtclk[MC_MONTH] = dectohexdec(++i);
375 
376 	rtclk[MC_DOM] = dectohexdec(++n);
377 
378 	s = splclock();
379 	rtcput(&rtclk);
380 	splx(s);
381 }
382