xref: /netbsd-src/sys/arch/next68k/next68k/clock.c (revision 4472dbe5e3bd91ef2540bada7a7ca7384627ff9b)
1 /*	$NetBSD: clock.c,v 1.3 2000/01/19 02:52:20 msaitoh 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/cpu.h>
40 
41 #include <next68k/dev/clockreg.h>
42 
43 /* @@@ This is pretty bogus and will need fixing once
44  * things are working better.
45  * -- jewell@mit.edu
46  */
47 
48 /*
49  * Note that the value of delay_divisor is roughly
50  * 2048 / cpuspeed (where cpuspeed is in MHz) on 68020
51  * and 68030 systems.  See clock.c for the delay
52  * calibration algorithm.
53  */
54 int	cpuspeed;		  /* relative cpu speed; XXX skewed on 68040 */
55 int	delay_divisor = 2048/25;  /* delay constant */
56 
57 /*
58  * Calibrate the delay constant.
59  */
60 void
61 next68k_calibrate_delay()
62 {
63   extern int delay_divisor;
64 
65   /* @@@ write this once we know how to read
66    * a real time clock
67    */
68 
69   /*
70    * Sanity check the delay_divisor value.  If we totally lost,
71    * assume a 25MHz CPU;
72    */
73   if (delay_divisor == 0)
74     delay_divisor = 2048 / 25;
75 
76   /* Calculate CPU speed. */
77   cpuspeed = 2048 / delay_divisor;
78 }
79 
80 #define	SECDAY		(24 * 60 * 60)
81 #define	SECYR		(SECDAY * 365)
82 
83 /*
84  * Set up the system's time, given a `reasonable' time value.
85  */
86 void
87 inittodr(base)
88         time_t base;
89 {
90   int badbase = 0;
91 
92   if (base < 5*SECYR) {
93     printf("WARNING: preposterous time in file system");
94     base = 6*SECYR + 186*SECDAY + SECDAY/2;
95     badbase = 1;
96   }
97 
98   if ((time.tv_sec = getsecs()) == 0) {
99     printf("WARNING: bad date in battery clock");
100     /*
101      * Believe the time in the file system for lack of
102      * anything better, resetting the clock.
103      */
104     time.tv_sec = base;
105     if (!badbase)
106       resettodr();
107   } else {
108     int deltat = time.tv_sec - base;
109 
110     if (deltat < 0)
111       deltat = -deltat;
112     if (deltat < 2 * SECDAY)
113       return;
114     printf("WARNING: clock %s %d days\n",
115            time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
116   }
117 }
118 
119 void
120 resettodr()
121 {
122   setsecs(time.tv_sec);
123 }
124 
125 int clock_intr __P((void *));
126 
127 int
128 clock_intr(arg)
129      void *arg;
130 {
131   if (!INTR_OCCURRED(NEXT_I_TIMER)) return(0);
132 
133 	{
134 		volatile struct timer_reg *timer = IIOV(NEXT_P_TIMER);
135 		timer->csr |= TIMER_UPDATE;
136 	}
137 
138 	hardclock(arg);
139 
140   return(1);
141 }
142 
143 /*
144  * Set up the real-time and statistics clocks.  Leave stathz 0 only
145  * if no alternative timer is available.
146  *
147  * The frequencies of these clocks must be an even number of microseconds.
148  */
149 void
150 cpu_initclocks()
151 {
152   rtc_init();
153 
154   hz = 100;
155 
156   {
157     int s;
158     s = splclock();
159 
160     {
161       volatile struct timer_reg *timer = IIOV(NEXT_P_TIMER);
162       int cnt = 1000000/hz;          /* usec timer */
163       timer->csr = 0;
164       timer->msb = (cnt>>8);
165       timer->lsb = cnt;
166       timer->csr = TIMER_ENABLE|TIMER_UPDATE;
167     }
168 
169     isrlink_autovec(clock_intr, NULL, NEXT_I_IPL(NEXT_I_TIMER), 0);
170     INTR_ENABLE(NEXT_I_TIMER);
171 
172     splx(s);
173   }
174 }
175 
176 
177 void
178 setstatclockrate(newhz)
179 	int newhz;
180 {
181 
182 	/* XXX should we do something here? XXX */
183 }
184 
185 /* @@@ update this to use the usec timer
186  * Darrin B Jewell <jewell@mit.edu>  Sun Feb  8 05:01:02 1998
187  */
188 
189 
190 /*
191  * Return the best possible estimate of the time in the timeval
192  * to which tvp points.  We do this by returning the current time
193  * plus the amount of time since the last clock interrupt (clock.c:clkread).
194  *
195  * Check that this time is no less than any previously-reported time,
196  * which could happen around the time of a clock adjustment.  Just for fun,
197  * we guarantee that the time will be greater than the value obtained by a
198  * previous call.
199  */
200 
201 void
202 microtime(tvp)
203 	register struct timeval *tvp;
204 {
205 	int s = splhigh();
206 	static struct timeval lasttime;
207 
208 	*tvp = time;
209 	tvp->tv_usec;
210 	while (tvp->tv_usec >= 1000000) {
211 		tvp->tv_sec++;
212 		tvp->tv_usec -= 1000000;
213 	}
214 	if (tvp->tv_sec == lasttime.tv_sec &&
215 	    tvp->tv_usec <= lasttime.tv_usec &&
216 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
217 		tvp->tv_sec++;
218 		tvp->tv_usec -= 1000000;
219 	}
220 	lasttime = *tvp;
221 	splx(s);
222 }
223