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