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