Home | History | Annotate | Line # | Download | only in mips
      1 /* $NetBSD: mips_mcclock.c,v 1.21 2024/09/08 09:36:49 rillig Exp $ */
      2 
      3 /*
      4  * Copyright (c) 1997 Jonathan Stone (hereinafter referred to as the author)
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  * 3. All advertising materials mentioning features or use of this software
     16  *    must display the following acknowledgement:
     17  *      This product includes software developed by Jonathan Stone for
     18  *      the NetBSD Project.
     19  * 4. The name of the author may not be used to endorse or promote products
     20  *    derived from this software without specific prior written permission.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
     23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
     26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
     36 
     37 __KERNEL_RCSID(0, "$NetBSD: mips_mcclock.c,v 1.21 2024/09/08 09:36:49 rillig Exp $");
     38 
     39 #include <sys/param.h>
     40 #include <sys/systm.h>
     41 #include <sys/device.h>
     42 
     43 #include <dev/clock_subr.h>
     44 #include <dev/ic/mc146818reg.h>
     45 #include <dev/dec/mcclockvar.h>
     46 #include <dev/dec/mcclock_pad32.h>
     47 
     48 #include <mips/cpu.h>			/* MIPS_HAS_CLOCK */
     49 #include <mips/locore.h>		/* mips_cp0_cause_read() */
     50 #include <mips/mips/mips_mcclock.h>
     51 
     52 
     53 unsigned mips_mc_cpuspeed(void *, int, int (*)(void *, int));
     54 int mips_mcclock_tickloop(void *, int);
     55 unsigned mips_mcclock_to_mhz(unsigned iters);
     56 
     57 
     58 /*
     59  * Compute MHz and DELAY() constants using the default
     60  * polling function.
     61  */
     62 unsigned
     63 mc_cpuspeed(vaddr_t mcclock_addr, int cpuintmask)
     64 {
     65 	return mips_mc_cpuspeed((void *)mcclock_addr, cpuintmask,
     66 	           mips_mcclock_tickloop);
     67 }
     68 
     69 
     70 /*
     71  * Estimate CPU cycle speed by counting cycles (actually executions of a
     72  * one-line loop) between two adjacent ticks of an mc146818 clock.
     73  * Return loop iteration count so hand-calibrated  MD  code can
     74  * estimate clock speed from cycles.
     75  *
     76  * Runs before CPU is attached (so we can print CPU speed)  which is
     77  * before the clock is attached, so we can't use the normal clock driver.
     78  */
     79 unsigned
     80 mips_mc_cpuspeed(void *mcclock_addr, int clockmask, int (*tickpollfn)(void *mcclock_addr, int clockmask))
     81 {
     82 	int s;
     83 	int iters = 0;
     84 	int saved_rega, saved_regb;
     85 	volatile struct mcclock_pad32_clockdatum *clk = (void *)mcclock_addr;
     86 
     87 	/*
     88 	 * Block all interrupts, including clock ticks.
     89 	 */
     90 	s = splhigh();
     91 
     92 	/*
     93 	 * Enable periodic interrupts on the mc146818,
     94 	 * and set it up for 256Hz (4ms) interrupts.
     95 	 * Save any state we change so we can restore it on exit.
     96 	 */
     97 	saved_rega = clk[MC_REGA].datum;
     98 	saved_regb = clk[MC_REGB].datum;
     99 
    100 #if 0
    101 	mcclock_addr->rega = (saved_rega & ~MC_BASE_RESET) | MC_RATE_256_Hz;
    102 	mcclock_addr->regb = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE;
    103 #else
    104 	clk[MC_REGA].datum = MC_BASE_32_KHz | MC_RATE_256_Hz;
    105 	clk[MC_REGB].datum = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE| MC_REGB_SQWE;
    106 #endif
    107 	/* count loop iterations between ticks */
    108 	iters = (*tickpollfn)(mcclock_addr, clockmask);
    109 
    110 	/* Restore mcclock registers */
    111 	clk[MC_REGA].datum = saved_rega;
    112 	clk[MC_REGB].datum = saved_regb;
    113 
    114 	splx(s);
    115 
    116 	/*
    117 	 * Compute approximate CPU speed in MHz, and an
    118 	 * appropriate base for  DELAY() and delay(), from
    119 	 * the number of completed iterations.
    120 	 */
    121 	mips_options.mips_cpu_mhz = mips_mcclock_to_mhz(iters);
    122 
    123 #if defined(DEBUG)
    124 	printf("mcclock: iters %d computed MHz %d, instrs per usec=%d\n",
    125 	       iters, mips_options.mips_cpu_mhz, cpuspeed);
    126 #endif
    127 	return (iters);
    128 }
    129 
    130 
    131 /*
    132  * Poll mcclock chip for the next tick interrupt and count
    133  * instructions until the subsequent tick.
    134  *
    135  * XXX Assumes the mcclock chip has exclusive use of a CPU interrupt line.
    136  * XXX Assumes bus access to clock registers is cheap (not a function call).
    137  *  MD alternatives must be used where this doesn't hold.
    138  */
    139 
    140 int
    141 mips_mcclock_tickloop(void *mcclock_addr, int clockmask)
    142 {
    143 	int iters;
    144 	volatile int junk;
    145 	volatile struct mcclock_pad32_clockdatum *clk = mcclock_addr;
    146 
    147 	/* clear any old pending interrupts */
    148 	junk = clk[MC_REGC].datum;
    149 	junk++;	junk++;	junk++;	junk++;
    150 
    151 	/* Poll clock interrupt, waiting for next tick to happen. */
    152 	while ((mips_cp0_cause_read() & clockmask) == 0)
    153 		;
    154 
    155 	/* Ack the mc146818 interrupt caused by starting tick. */
    156 	junk = clk[MC_REGC].datum;
    157 
    158 	junk++;	junk++;	junk++;	junk++;
    159 
    160 	/* Count loops until next tick-interrupt request occurs (4ms). */
    161 	if (MIPS_HAS_CLOCK)
    162 		iters = mips_mcclock_loop_with_clock(clockmask);
    163 	else
    164 		iters = mips_mcclock_loop_without_clock(clockmask);
    165 
    166 	/* Ack the interrupt from the just-gone-off tick */
    167 	junk = clk[MC_REGC].datum;
    168 
    169 	return (iters);
    170 }
    171 
    172 
    173 /*
    174  * mips_mcclock_to_mhz(iters) -- convert an mcclock cycles-per-tick count
    175  * 	to a CPU speed in MHz.
    176  *
    177  * Side Effects:
    178  * 	set the global variables "cpuspeed", used by DELAY() and delay()
    179  *	as an instructions-per-microsecond multiplier, to a value appropriate
    180  *	for the estimated clock speed.
    181  */
    182 unsigned
    183 mips_mcclock_to_mhz(unsigned iters)
    184 {
    185 	unsigned mhz = 0;
    186 
    187 	/* XXX KN01? */
    188 
    189 	/*
    190 	 * Measured thresholds for Digital systems from Sean Davidson.
    191 	 *
    192 	 * r3000-core DECstations values fit to:
    193 	 *     iters per 4ms tick = 425 * MHz)
    194 	 *     instructions per MHz = kHz * 575
    195 	 * with about 2 MHz slop to allow for variation.
    196 	 */
    197 
    198 #ifdef MIPS3_PLUS
    199 	if (CPUISMIPS3) {
    200 		if (iters < 18100) {
    201 			/* error */
    202 			printf("mcclock loop count %d too low for r4000\n",
    203 			       iters);
    204 			mhz = 45;
    205 			cpuspeed = 20;	/* XXX */
    206 		} else if (iters < 21000) {
    207 			mhz = 50;
    208 			cpuspeed = 25;	/* XXX */
    209 		} else if (iters < 25315) {
    210 			mhz = 60;
    211 			cpuspeed = 27;	/* XXX */
    212 		} else if (iters < 28497) {
    213 			mhz = 67;
    214 			cpuspeed = 33;	/* XXX */
    215 		} else if (iters < 31500) {
    216 			mhz = 75;
    217 			cpuspeed = 38;	/* XXX */
    218 		}
    219 	}
    220 #endif /* MIPS3_PLUS */
    221 
    222 #ifdef MIPS1
    223 	if (!CPUISMIPS3) {
    224 		if (iters < 5100) {
    225 			/* assume memory-bound DS 2100 */
    226 			mhz = 12;	/* 12.5 MHz? */
    227 			cpuspeed = 8;
    228 		} else if (iters < 6700) {
    229 			/* assume memory-bound DS3100 */
    230 			mhz = 15;
    231 			cpuspeed = 8;
    232 		} else if (iters < 8800) {
    233 			mhz = 20;
    234 			cpuspeed = 11;
    235 		} else if (iters < 11300) {
    236 			mhz = 25;
    237 			cpuspeed = 13;
    238 		} else if (iters < 14000) {
    239 			mhz = 33;
    240 			cpuspeed = 19;
    241 		} else if (iters < 15000) {
    242 			mhz = 36;
    243 			cpuspeed = 21;
    244 		} else if (iters < 16000) {
    245 			mhz = 40;
    246 			cpuspeed = 23;
    247 		} else if (iters < 18800) {
    248 			mhz = 45;
    249 			cpuspeed = 25;
    250 		} else if (iters < 21000) {
    251 			mhz = 50;
    252 			cpuspeed = 29;
    253 		} else if (iters < 26000) {
    254 			mhz = 60;
    255 			cpuspeed = 35;
    256 		} else {
    257 			/* XXX */
    258 			mhz = 70;
    259 			cpuspeed = 40;
    260 		}
    261 	}
    262 #endif	/* MIPS1 */
    263 
    264 	return (mhz);
    265 }
    266