Home | History | Annotate | Line # | Download | only in mac68k
      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
    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
    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
    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
    189 setstatclockrate(int rateinhz)
    190 {
    191 }
    192 
    193 void
    194 disablertclock(void)
    195 {
    196 	/* disable clock interrupt */
    197 	via_reg(VIA1, vIER) = V1IF_T1;
    198 }
    199 
    200 static u_int
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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