xref: /netbsd/sys/arch/mac68k/mac68k/clock.c (revision bf9ec67e)
1 /*	$NetBSD: clock.c,v 1.39 1999/11/05 19:14:56 scottr Exp $	*/
2 
3 /*
4  * Copyright (c) 1988 University of Utah.
5  * Copyright (c) 1982, 1990 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * the Systems Programming Group of the University of Utah Computer
10  * Science Department.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. All advertising materials mentioning features or use of this software
21  *    must display the following acknowledgement:
22  *	This product includes software developed by the University of
23  *	California, Berkeley and its contributors.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  */
40 /*-
41  * Copyright (C) 1993	Allen K. Briggs, Chris P. Caputo,
42  *			Michael L. Finch, Bradley A. Grantham, and
43  *			Lawrence A. Kesteloot
44  * All rights reserved.
45  *
46  * Redistribution and use in source and binary forms, with or without
47  * modification, are permitted provided that the following conditions
48  * are met:
49  * 1. Redistributions of source code must retain the above copyright
50  *    notice, this list of conditions and the following disclaimer.
51  * 2. Redistributions in binary form must reproduce the above copyright
52  *    notice, this list of conditions and the following disclaimer in the
53  *    documentation and/or other materials provided with the distribution.
54  * 3. All advertising materials mentioning features or use of this software
55  *    must display the following acknowledgement:
56  *	This product includes software developed by the Alice Group.
57  * 4. The names of the Alice Group or any of its members may not be used
58  *    to endorse or promote products derived from this software without
59  *    specific prior written permission.
60  *
61  * THIS SOFTWARE IS PROVIDED BY THE ALICE GROUP ``AS IS'' AND ANY EXPRESS OR
62  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
63  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
64  * IN NO EVENT SHALL THE ALICE GROUP BE LIABLE FOR ANY DIRECT, INDIRECT,
65  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
66  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
67  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
68  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
69  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
70  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
71  *
72  */
73 /*
74  *
75  * from: Utah $Hdr: clock.c 1.18 91/01/21$
76  *
77  *	@(#)clock.c   7.6 (Berkeley) 5/7/91
78  */
79 
80 #include <sys/param.h>
81 #include <sys/device.h>
82 #include <sys/kernel.h>
83 #include <sys/systm.h>
84 
85 #include <machine/autoconf.h>
86 #include <machine/psl.h>
87 #include <machine/cpu.h>
88 #include <machine/limits.h>
89 
90 #if defined(GPROF) && defined(PROFTIMER)
91 #include <sys/gprof.h>
92 #endif
93 
94 #include <mac68k/mac68k/pram.h>
95 #include <mac68k/mac68k/clockreg.h>
96 #include <machine/viareg.h>
97 
98 #ifdef DEBUG
99 int	clock_debug = 0;
100 #endif
101 
102 void	rtclock_intr __P((void));
103 
104 #define	DIFF19041970	2082844800
105 #define	DIFF19701990	630720000
106 #define	DIFF19702010	1261440000
107 
108 /*
109  * Mac II machine-dependent clock routines.
110  */
111 
112 /*
113  * Start the real-time clock; i.e. set timer latches and boot timer.
114  *
115  * We use VIA1 timer 1.
116  */
117 void
118 startrtclock()
119 {
120 /*
121  * BARF MF startrt clock is called twice in init_main, configure,
122  * the reason why is doced in configure
123  */
124 	/* be certain clock interrupts are off */
125 	via_reg(VIA1, vIER) = V1IF_T1;
126 
127 	/* set timer latch */
128 	via_reg(VIA1, vACR) |= ACR_T1LATCH;
129 
130 	/* set VIA timer 1 latch to 60 Hz (100 Hz) */
131 	via_reg(VIA1, vT1L) = CLK_INTL;
132 	via_reg(VIA1, vT1LH) = CLK_INTH;
133 
134 	/* set VIA timer 1 counter started for 60(100) Hz */
135 	via_reg(VIA1, vT1C) = CLK_INTL;
136 	via_reg(VIA1, vT1CH) = CLK_INTH;
137 }
138 
139 void
140 enablertclock()
141 {
142 	/* clear then enable clock interrupt. */
143 	via_reg(VIA1, vIFR) |= V1IF_T1;
144 	via_reg(VIA1, vIER) = 0x80 | V1IF_T1;
145 }
146 
147 void
148 cpu_initclocks()
149 {
150 	enablertclock();
151 }
152 
153 void
154 setstatclockrate(rateinhz)
155 	int rateinhz;
156 {
157 }
158 
159 void
160 disablertclock()
161 {
162 	/* disable clock interrupt */
163 	via_reg(VIA1, vIER) = V1IF_T1;
164 }
165 
166 /*
167  * Returns number of usec since last clock tick/interrupt.
168  *
169  * Check high byte twice to prevent missing a roll-over.
170  * (race condition?)
171  */
172 u_long
173 clkread()
174 {
175 	int high, high2, low;
176 
177 	high = via_reg(VIA1, vT1CH);
178 	low = via_reg(VIA1, vT1C);
179 
180 	high2 = via_reg(VIA1, vT1CH);
181 	if (high != high2)
182 		high = high2;
183 
184 	/* return count left in timer / 1.27 */
185 	/* return((CLK_INTERVAL - (high << 8) - low) / CLK_SPEED); */
186 	return ((CLK_INTERVAL - (high << 8) - low) * 10000 / 12700);
187 }
188 
189 
190 #ifdef PROFTIMER
191 /*
192  * Here, we have implemented code that causes VIA2's timer to count
193  * the profiling clock.  Following the HP300's lead, this reduces
194  * the impact on other tasks, since locore turns off the profiling clock
195  * on context switches.  If need be, the profiling clock's resolution can
196  * be cranked higher than the real-time clock's resolution, to prevent
197  * aliasing and allow higher accuracy.
198  */
199 int     profint = PRF_INTERVAL;	/* Clock ticks between interrupts */
200 int     profinthigh;
201 int     profintlow;
202 int     profscale = 0;		/* Scale factor from sys clock to prof clock */
203 char    profon = 0;		/* Is profiling clock on? */
204 
205 /* profon values - do not change, locore.s assumes these values */
206 #define	PRF_NONE	0x00
207 #define	PRF_USER	0x01
208 #define	PRF_KERNEL	0x80
209 
210 void
211 initprofclock()
212 {
213 	/* profile interval must be even divisor of system clock interval */
214 	if (profint > CLK_INTERVAL)
215 		profint = CLK_INTERVAL;
216 	else
217 		if (CLK_INTERVAL % profint != 0)
218 			/* try to intelligently fix clock interval */
219 			profint = CLK_INTERVAL / (CLK_INTERVAL / profint);
220 
221 	profscale = CLK_INTERVAL / profint;
222 
223 	profinthigh = profint >> 8;
224 	profintlow = profint & 0xff;
225 }
226 
227 void
228 startprofclock()
229 {
230 	via_reg(VIA2, vT1L) = (profint - 1) & 0xff;
231 	via_reg(VIA2, vT1LH) = (profint - 1) >> 8;
232 	via_reg(VIA2, vACR) |= ACR_T1LATCH;
233 	via_reg(VIA2, vT1C) = (profint - 1) & 0xff;
234 	via_reg(VIA2, vT1CH) = (profint - 1) >> 8;
235 }
236 
237 void
238 stopprofclock()
239 {
240 	via_reg(VIA2, vT1L) = 0;
241 	via_reg(VIA2, vT1LH) = 0;
242 	via_reg(VIA2, vT1C) = 0;
243 	via_reg(VIA2, vT1CH) = 0;
244 }
245 
246 #ifdef GPROF
247 /*
248  * BARF: we should check this:
249  *
250  * profclock() is expanded in line in lev6intr() unless profiling kernel.
251  * Assumes it is called with clock interrupts blocked.
252  */
253 void
254 profclock(pclk)
255 	clockframe *pclk;
256 {
257 	/*
258 	 * Came from user mode.
259 	 * If this process is being profiled record the tick.
260 	 */
261 	if (USERMODE(pclk->ps)) {
262 		if (p->p_stats.p_prof.pr_scale)
263 			addupc_task(&curproc, pclk->pc, 1);
264 	}
265 	/*
266 	 * Came from kernel (supervisor) mode.
267 	 * If we are profiling the kernel, record the tick.
268 	 */
269 	else
270 		if (profiling < 2) {
271 			int s = pclk->pc - s_lowpc;
272 
273 			if (s < s_textsize)
274 				kcount[s / (HISTFRACTION * sizeof(*kcount))]++;
275 		}
276 	/*
277 	 * Kernel profiling was on but has been disabled.
278 	 * Mark as no longer profiling kernel and if all profiling done,
279 	 * disable the clock.
280 	 */
281 	if (profiling && (profon & PRF_KERNEL)) {
282 		profon &= ~PRF_KERNEL;
283 		if (profon == PRF_NONE)
284 			stopprofclock();
285 	}
286 }
287 #endif
288 #endif
289 
290 static u_long	ugmt_2_pramt __P((u_long));
291 static u_long	pramt_2_ugmt __P((u_long));
292 
293 /*
294  * Convert GMT to Mac PRAM time, using rtc_offset
295  * GMT bias adjustment is done elsewhere.
296  */
297 static u_long
298 ugmt_2_pramt(t)
299 	u_long t;
300 {
301 	/* don't know how to open a file properly. */
302 	/* assume compiled timezone is correct. */
303 
304 	return (t = t + DIFF19041970 - 60 * rtc_offset);
305 }
306 
307 /*
308  * Convert a Mac PRAM time value to GMT, using rtc_offset
309  * GMT bias adjustment is done elsewhere.
310  */
311 static u_long
312 pramt_2_ugmt(t)
313 	u_long t;
314 {
315 	return (t = t - DIFF19041970 + 60 * rtc_offset);
316 }
317 
318 /*
319  * Time from the booter.
320  */
321 u_long	macos_boottime;
322 
323 /*
324  * Bias in minutes east from GMT (also from booter).
325  */
326 long	macos_gmtbias;
327 
328 /*
329  * Flag for whether or not we can trust the PRAM.  If we don't
330  * trust it, we don't write to it, and we take the MacOS value
331  * that is passed from the booter (which will only be a second
332  * or two off by now).
333  */
334 int	mac68k_trust_pram = 1;
335 
336 /*
337  * Set global GMT time register, using a file system time base for comparison
338  * and sanity checking.
339  */
340 void
341 inittodr(base)
342 	time_t base;
343 {
344 	u_long timbuf;
345 
346 	timbuf = pramt_2_ugmt(pram_readtime());
347 	if ((timbuf - (macos_boottime + 60 * rtc_offset)) > 10 * 60) {
348 #if DIAGNOSTIC
349 		printf(
350 		    "PRAM time does not appear to have been read correctly.\n");
351 		printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n",
352 		    timbuf, macos_boottime + 60 * rtc_offset);
353 #endif
354 		timbuf = macos_boottime;
355 		mac68k_trust_pram = 0;
356 	}
357 #ifdef DIAGNOSTIC
358 	else
359 		printf("PRAM: 0x%lx, macos_boottime: 0x%lx.\n",
360 		    timbuf, macos_boottime);
361 #endif
362 
363 	/*
364 	 * GMT bias is passed in from Booter
365 	 * To get GMT, *subtract* GMTBIAS from *our* time
366 	 * (gmtbias is in minutes, mult by 60)
367 	 */
368 	timbuf -= macos_gmtbias * 60;
369 
370 	if (base < 5 * SECYR) {
371 		printf("WARNING: file system time earlier than 1975\n");
372 		printf(" -- CHECK AND RESET THE DATE!\n");
373 		base = 21 * SECYR;	/* 1991 is our sane date */
374 	}
375 	/*
376 	 * Check sanity against the year 2010.  Let's hope NetBSD/mac68k
377 	 * doesn't run that long!
378 	 */
379 	if (base > 40 * SECYR) {
380 		printf("WARNING: file system time later than 2010\n");
381 		printf(" -- CHECK AND RESET THE DATE!\n");
382 		base = 21 * SECYR;	/* 1991 is our sane date */
383 	}
384 	if (timbuf < base) {
385 		printf(
386 		    "WARNING: Battery clock has earlier time than UNIX fs.\n");
387 		if (((u_long) base) < (40 * SECYR))
388 			timbuf = base;
389 	}
390 	time.tv_sec = timbuf;
391 	time.tv_usec = 0;
392 }
393 
394 /*
395  * Set battery backed clock to a new time, presumably after someone has
396  * changed system time.
397  */
398 void
399 resettodr()
400 {
401 	if (mac68k_trust_pram)
402 		/*
403 		 * GMT bias is passed in from the Booter.
404 		 * To get *our* time, add GMTBIAS to GMT.
405 		 * (gmtbias is in minutes, multiply by 60).
406 		 */
407 		pram_settime(ugmt_2_pramt(time.tv_sec + macos_gmtbias * 60));
408 #ifdef DEBUG
409 	else if (clock_debug)
410 		printf("NetBSD/mac68k does not trust itself to try and write "
411 		    "to the PRAM on this system.\n");
412 #endif
413 }
414 
415 
416 /*
417  * The Macintosh timers decrement once every 1.2766 microseconds.
418  * MGFH2, p. 180
419  */
420 #define	CLK_RATE	12766
421 
422 #define	DELAY_CALIBRATE	(0xffffff << 7)	/* Large value for calibration */
423 
424 u_int		delay_factor = DELAY_CALIBRATE;
425 volatile int	delay_flag = 1;
426 
427 int		_delay __P((u_int));
428 static void	delay_timer1_irq __P((void *));
429 
430 static void
431 delay_timer1_irq(dummy)
432 	void *dummy;
433 {
434 	delay_flag = 0;
435 }
436 
437 /*
438  * Calibrate delay_factor with VIA1 timer T1.
439  */
440 void
441 mac68k_calibrate_delay()
442 {
443 	u_int sum, n;
444 
445 	(void)spl0();
446 
447 	/* Disable VIA1 timer 1 interrupts and set up service routine */
448 	via_reg(VIA1, vIER) = V1IF_T1;
449 	via1_register_irq(VIA1_T1, delay_timer1_irq, NULL);
450 
451 	/* Set the timer for one-shot mode, then clear and enable interrupts */
452 	via_reg(VIA1, vACR) &= ~ACR_T1LATCH;
453 	via_reg(VIA1, vIFR) = V1IF_T1;	/* (this is needed for IIsi) */
454 	via_reg(VIA1, vIER) = 0x80 | V1IF_T1;
455 
456 #ifdef DEBUG
457 	if (clock_debug)
458 		printf("mac68k_calibrate_delay(): entering timing loop\n");
459 #endif
460 
461 	for (sum = 0, n = 8; n > 0; n--) {
462 		delay_flag = 1;
463 		via_reg(VIA1, vT1C) = 0;	/* 1024 clock ticks */
464 		via_reg(VIA1, vT1CH) = 4;	/* (approx 1.3 msec) */
465 		sum += ((delay_factor >> 7) - _delay(1));
466 	}
467 
468 	/* Disable timer interrupts and reset service routine */
469 	via_reg(VIA1, vIER) = V1IF_T1;
470 	via1_register_irq(VIA1_T1, (void (*)(void *))rtclock_intr, NULL);
471 
472 	/*
473 	 * If this weren't integer math, the following would look
474 	 * a lot prettier.  It should really be something like
475 	 * this:
476 	 *	delay_factor = ((sum / 8) / (1024 * 1.2766)) * 128;
477 	 * That is, average the sum, divide by the number of usec,
478 	 * and multiply by a scale factor of 128.
479 	 *
480 	 * We can accomplish the same thing by simplifying and using
481 	 * shifts, being careful to avoid as much loss of precision
482 	 * as possible.  (If the sum exceeds UINT_MAX/10000, we need
483 	 * to rearrange the calculation slightly to do this.)
484 	 */
485 	if (sum > (UINT_MAX / 10000))	/* This is a _fast_ machine! */
486 		delay_factor = (((sum >> 3) * 10000) / CLK_RATE) >> 3;
487 	else
488 		delay_factor = (((sum * 10000) >> 3) / CLK_RATE) >> 3;
489 
490 	/* Reset the delay_flag for normal use */
491 	delay_flag = 1;
492 
493 #ifdef DEBUG
494 	if (clock_debug)
495 		printf("mac68k_calibrate_delay(): delay_factor calibrated\n");
496 #endif
497 
498 	(void)splhigh();
499 }
500