1 /* $NetBSD: mips_mcclock.c,v 1.18 2009/03/16 23:11:12 dsl 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.18 2009/03/16 23:11:12 dsl 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 (acutally 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 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, 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 an 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