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