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