xref: /netbsd-src/sys/arch/next68k/next68k/clock.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: clock.c,v 1.6 2003/01/18 06:09:54 thorpej Exp $	*/
2 /*
3  * Copyright (c) 1998 Darrin B. Jewell
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Darrin B. Jewell
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/tty.h>
37 
38 #include <machine/psl.h>
39 #include <machine/bus.h>
40 #include <machine/cpu.h>
41 
42 #include <next68k/dev/clockreg.h>
43 #include <next68k/dev/intiovar.h>
44 
45 #include <next68k/next68k/rtc.h>
46 #include <next68k/next68k/isr.h>
47 
48 /* @@@ This is pretty bogus and will need fixing once
49  * things are working better.
50  * -- jewell@mit.edu
51  */
52 
53 /*
54  * Note that the value of delay_divisor is roughly
55  * 2048 / cpuspeed (where cpuspeed is in MHz) on 68020
56  * and 68030 systems.  See clock.c for the delay
57  * calibration algorithm.
58  */
59 int	cpuspeed;		  /* relative cpu speed; XXX skewed on 68040 */
60 int	delay_divisor = 2048/25;  /* delay constant */
61 
62 /*
63  * Calibrate the delay constant.
64  */
65 void
66 next68k_calibrate_delay()
67 {
68   extern int delay_divisor;
69 
70   /* @@@ write this once we know how to read
71    * a real time clock
72    */
73 
74   /*
75    * Sanity check the delay_divisor value.  If we totally lost,
76    * assume a 25MHz CPU;
77    */
78   if (delay_divisor == 0)
79     delay_divisor = 2048 / 25;
80 
81   /* Calculate CPU speed. */
82   cpuspeed = 2048 / delay_divisor;
83 }
84 
85 #define	SECDAY		(24 * 60 * 60)
86 #define	SECYR		(SECDAY * 365)
87 
88 /*
89  * Set up the system's time, given a `reasonable' time value.
90  */
91 void
92 inittodr(base)
93         time_t base;
94 {
95   int badbase = 0;
96 
97   if (base < 5*SECYR) {
98     printf("WARNING: preposterous time in file system");
99     base = 6*SECYR + 186*SECDAY + SECDAY/2;
100     badbase = 1;
101   }
102 
103   if ((time.tv_sec = getsecs()) == 0) {
104     printf("WARNING: bad date in battery clock");
105     /*
106      * Believe the time in the file system for lack of
107      * anything better, resetting the clock.
108      */
109     time.tv_sec = base;
110     if (!badbase)
111       resettodr();
112   } else {
113     int deltat = time.tv_sec - base;
114 
115     if (deltat < 0)
116       deltat = -deltat;
117     if (deltat < 2 * SECDAY)
118       return;
119     printf("WARNING: clock %s %d days\n",
120            time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
121   }
122 }
123 
124 void
125 resettodr()
126 {
127   setsecs(time.tv_sec);
128 }
129 
130 int clock_intr __P((void *));
131 
132 int
133 clock_intr(arg)
134      void *arg;
135 {
136 	volatile struct timer_reg *timer;
137 	int whilecount = 0;
138 
139 	if (!INTR_OCCURRED(NEXT_I_TIMER)) {
140 		return(0);
141 	}
142 
143 	do {
144 		static int in_hardclock = 0;
145 		int s;
146 
147 		timer = (volatile struct timer_reg *)IIOV(NEXT_P_TIMER);
148 		timer->csr |= TIMER_REG_UPDATE;
149 
150 		if (! in_hardclock) {
151 			in_hardclock = 1;
152 			s = splclock ();
153 			hardclock(arg);
154 			splx(s);
155 			in_hardclock = 0;
156 		}
157 		if (whilecount++ > 10)
158 			panic ("whilecount");
159 	} while (INTR_OCCURRED(NEXT_I_TIMER));
160 	return(1);
161 }
162 
163 /*
164  * Set up the real-time and statistics clocks.  Leave stathz 0 only
165  * if no alternative timer is available.
166  *
167  * The frequencies of these clocks must be an even number of microseconds.
168  */
169 void
170 cpu_initclocks()
171 {
172 	int s, cnt;
173 	volatile struct timer_reg *timer;
174 
175 	rtc_init();
176 	hz = 100;
177 	s = splclock();
178 	timer = (volatile struct timer_reg *)IIOV(NEXT_P_TIMER);
179 	cnt = 1000000/hz;          /* usec timer */
180 	timer->csr = 0;
181 	timer->msb = (cnt >> 8);
182 	timer->lsb = cnt;
183 	timer->csr = TIMER_REG_ENABLE|TIMER_REG_UPDATE;
184 	isrlink_autovec(clock_intr, NULL, NEXT_I_IPL(NEXT_I_TIMER), 0, NULL);
185 	INTR_ENABLE(NEXT_I_TIMER);
186 	splx(s);
187 }
188 
189 
190 void
191 setstatclockrate(newhz)
192 	int newhz;
193 {
194 
195 	/* XXX should we do something here? XXX */
196 }
197 
198 /* @@@ update this to use the usec timer
199  * Darrin B Jewell <jewell@mit.edu>  Sun Feb  8 05:01:02 1998
200  */
201 
202 
203 /*
204  * Return the best possible estimate of the time in the timeval
205  * to which tvp points.  We do this by returning the current time
206  * plus the amount of time since the last clock interrupt (clock.c:clkread).
207  *
208  * Check that this time is no less than any previously-reported time,
209  * which could happen around the time of a clock adjustment.  Just for fun,
210  * we guarantee that the time will be greater than the value obtained by a
211  * previous call.
212  */
213 
214 void
215 microtime(tvp)
216 	register struct timeval *tvp;
217 {
218 	int s = splhigh();
219 	static struct timeval lasttime;
220 
221 	*tvp = time;
222 	tvp->tv_usec++;
223 	while (tvp->tv_usec >= 1000000) {
224 		tvp->tv_sec++;
225 		tvp->tv_usec -= 1000000;
226 	}
227 	if (tvp->tv_sec == lasttime.tv_sec &&
228 	    tvp->tv_usec <= lasttime.tv_usec &&
229 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
230 		tvp->tv_sec++;
231 		tvp->tv_usec -= 1000000;
232 	}
233 	lasttime = *tvp;
234 	splx(s);
235 }
236