xref: /netbsd-src/sys/arch/next68k/next68k/clock.c (revision d48f14661dda8638fee055ba15d35bdfb29b9fa8)
1 /*	$NetBSD: clock.c,v 1.9 2005/12/11 12:18:29 christos 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.9 2005/12/11 12:18:29 christos 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(void)
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(time_t base)
95 {
96 	int badbase = 0;
97 
98 	if (base < 5*SECYR) {
99 		printf("WARNING: preposterous time in file system");
100 		base = 6*SECYR + 186*SECDAY + SECDAY/2;
101 		badbase = 1;
102 	}
103 
104 	if ((time.tv_sec = getsecs()) == 0) {
105 		printf("WARNING: bad date in battery clock");
106 
107 		/*
108 		 * Believe the time in the file system for lack of
109 		 * anything better, resetting the clock.
110 		 */
111 
112 		time.tv_sec = base;
113 		if (!badbase)
114 			resettodr();
115 	} else {
116 		int deltat = time.tv_sec - base;
117 
118 		if (deltat < 0)
119 			deltat = -deltat;
120 		if (deltat < 2 * SECDAY)
121 			return;
122 		printf("WARNING: clock %s %d days\n",
123 		       time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
124 	}
125 }
126 
127 void
128 resettodr(void)
129 {
130 	setsecs(time.tv_sec);
131 }
132 
133 int clock_intr(void *);
134 
135 int
136 clock_intr(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(void)
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(int newhz)
194 {
195 
196 	/* XXX should we do something here? XXX */
197 }
198 
199 /* @@@ update this to use the usec timer
200  * Darrin B Jewell <jewell@mit.edu>  Sun Feb  8 05:01:02 1998
201  */
202 
203 
204 /*
205  * Return the best possible estimate of the time in the timeval
206  * to which tvp points.  We do this by returning the current time
207  * plus the amount of time since the last clock interrupt (clock.c:clkread).
208  *
209  * Check that this time is no less than any previously-reported time,
210  * which could happen around the time of a clock adjustment.  Just for fun,
211  * we guarantee that the time will be greater than the value obtained by a
212  * previous call.
213  */
214 
215 void
216 microtime(struct timeval *tvp)
217 {
218 	int s;
219 	static struct timeval lasttime;
220 
221 	s = splhigh();
222 	*tvp = time;
223 	tvp->tv_usec++;
224 	while (tvp->tv_usec >= 1000000) {
225 		tvp->tv_sec++;
226 		tvp->tv_usec -= 1000000;
227 	}
228 	if (tvp->tv_sec == lasttime.tv_sec &&
229 	    tvp->tv_usec <= lasttime.tv_usec &&
230 	    (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) {
231 		tvp->tv_sec++;
232 		tvp->tv_usec -= 1000000;
233 	}
234 	lasttime = *tvp;
235 	splx(s);
236 }
237