tsc.c revision 619
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 and Don Ahn.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	from: @(#)clock.c	7.2 (Berkeley) 5/12/91
37 *	$Id$
38 */
39
40/*
41 * Primitive clock interrupt routines.
42 */
43#include "param.h"
44#include "systm.h"
45#include "time.h"
46#include "kernel.h"
47#include "machine/segments.h"
48#include "i386/isa/icu.h"
49#include "i386/isa/isa.h"
50#include "i386/isa/rtc.h"
51#include "i386/isa/timerreg.h"
52
53#define DAYST 119
54#define DAYEN 303
55
56/* X-tals being what they are, it's nice to be able to fudge this one... */
57/* Note, the name changed here from XTALSPEED to TIMER_FREQ rgrimes 4/26/93 */
58#ifndef TIMER_FREQ
59#define	TIMER_FREQ	1193182	/* XXX - should be in isa.h */
60#endif
61
62startrtclock() {
63	int s;
64
65	findcpuspeed();		/* use the clock (while it's free)
66					to find the cpu speed */
67	/* initialize 8253 clock */
68	outb(TIMER_MODE, TIMER_SEL0|TIMER_RATEGEN|TIMER_16BIT);
69
70	/* Correct rounding will buy us a better precision in timekeeping */
71	outb (IO_TIMER1, (TIMER_FREQ+hz/2)/hz);
72	outb (IO_TIMER1, ((TIMER_FREQ+hz/2)/hz)/256);
73
74	/* initialize brain-dead battery powered clock */
75	outb (IO_RTC, RTC_STATUSA);
76	outb (IO_RTC+1, 0x26);
77	outb (IO_RTC, RTC_STATUSB);
78	outb (IO_RTC+1, 2);
79
80	outb (IO_RTC, RTC_DIAG);
81	if (s = inb (IO_RTC+1))
82		printf("RTC BIOS diagnostic error %b\n", s, RTCDG_BITS);
83	outb (IO_RTC, RTC_DIAG);
84	outb (IO_RTC+1, 0);
85}
86
87unsigned int delaycount;	/* calibrated loop variable (1 millisecond) */
88
89#define FIRST_GUESS	0x2000
90findcpuspeed()
91{
92	unsigned char low;
93	unsigned int remainder;
94
95	/* Put counter in count down mode */
96	outb(IO_TIMER1+3, 0x34);
97	outb(IO_TIMER1, 0xff);
98	outb(IO_TIMER1, 0xff);
99	delaycount = FIRST_GUESS;
100	spinwait(1);
101	/* Read the value left in the counter */
102	low 	= inb(IO_TIMER1);	/* least siginifcant */
103	remainder = inb(IO_TIMER1);	/* most significant */
104	remainder = (remainder<<8) + low ;
105	/* Formula for delaycount is :
106	 *  (loopcount * timer clock speed)/ (counter ticks * 1000)
107	 */
108	delaycount = (FIRST_GUESS * (TIMER_FREQ/1000)) / (0xffff-remainder);
109}
110
111
112/* convert 2 digit BCD number */
113bcd(i)
114int i;
115{
116	return ((i/16)*10 + (i%16));
117}
118
119/* convert years to seconds (from 1970) */
120unsigned long
121ytos(y)
122int y;
123{
124	int i;
125	unsigned long ret;
126
127	ret = 0;
128	for(i = 1970; i < y; i++) {
129		if (i % 4) ret += 365*24*60*60;
130		else ret += 366*24*60*60;
131	}
132	return ret;
133}
134
135/* convert months to seconds */
136unsigned long
137mtos(m,leap)
138int m,leap;
139{
140	int i;
141	unsigned long ret;
142
143	ret = 0;
144	for(i=1;i<m;i++) {
145		switch(i){
146		case 1: case 3: case 5: case 7: case 8: case 10: case 12:
147			ret += 31*24*60*60; break;
148		case 4: case 6: case 9: case 11:
149			ret += 30*24*60*60; break;
150		case 2:
151			if (leap) ret += 29*24*60*60;
152			else ret += 28*24*60*60;
153		}
154	}
155	return ret;
156}
157
158
159/*
160 * Initialize the time of day register, based on the time base which is, e.g.
161 * from a filesystem.
162 */
163inittodr(base)
164	time_t base;
165{
166	unsigned long sec;
167	int leap,day_week,t,yd;
168	int sa,s;
169
170	/* do we have a realtime clock present? (otherwise we loop below) */
171	sa = rtcin(RTC_STATUSA);
172	if (sa == 0xff || sa == 0) return;
173
174	/* ready for a read? */
175	while ((sa&RTCSA_TUP) == RTCSA_TUP)
176		sa = rtcin(RTC_STATUSA);
177
178	sec = bcd(rtcin(RTC_YEAR)) + 1900;
179	if (sec < 1970)
180		sec += 100;
181	leap = !(sec % 4); sec = ytos(sec); /* year    */
182	yd = mtos(bcd(rtcin(RTC_MONTH)),leap); sec += yd;	/* month   */
183	t = (bcd(rtcin(RTC_DAY))-1) * 24*60*60; sec += t; yd += t; /* date    */
184	day_week = rtcin(RTC_WDAY);				/* day     */
185	sec += bcd(rtcin(RTC_HRS)) * 60*60;			/* hour    */
186	sec += bcd(rtcin(RTC_MIN)) * 60;			/* minutes */
187	sec += bcd(rtcin(RTC_SEC));				/* seconds */
188
189	/* XXX off by one? Need to calculate DST on SUNDAY */
190	/* Perhaps we should have the RTC hold GMT time to save */
191	/* us the bother of converting. */
192	yd = yd / (24*60*60);
193	if ((yd >= DAYST) && ( yd <= DAYEN)) {
194		sec -= 60*60;
195	}
196	sec += tz.tz_minuteswest * 60;
197
198	time.tv_sec = sec;
199}
200
201#ifdef garbage
202/*
203 * Initialze the time of day register, based on the time base which is, e.g.
204 * from a filesystem.
205 */
206test_inittodr(base)
207	time_t base;
208{
209
210	outb(IO_RTC,9); /* year    */
211	printf("%d ",bcd(inb(IO_RTC+1)));
212	outb(IO_RTC,8); /* month   */
213	printf("%d ",bcd(inb(IO_RTC+1)));
214	outb(IO_RTC,7); /* day     */
215	printf("%d ",bcd(inb(IO_RTC+1)));
216	outb(IO_RTC,4); /* hour    */
217	printf("%d ",bcd(inb(IO_RTC+1)));
218	outb(IO_RTC,2); /* minutes */
219	printf("%d ",bcd(inb(IO_RTC+1)));
220	outb(IO_RTC,0); /* seconds */
221	printf("%d\n",bcd(inb(IO_RTC+1)));
222
223	time.tv_sec = base;
224}
225#endif
226
227/*
228 * Restart the clock.
229 */
230resettodr()
231{
232}
233
234/*
235 * Wire clock interrupt in.
236 */
237#define V(s)	__CONCAT(V, s)
238extern V(clk)();
239enablertclock() {
240	setidt(ICU_OFFSET+0, &V(clk), SDT_SYS386IGT, SEL_KPL);
241	INTREN(IRQ0);
242}
243
244/*
245 * Delay for some number of milliseconds.
246 */
247void
248spinwait(millisecs)
249	int millisecs;
250{
251	DELAY(1000 * millisecs);
252}
253