xref: /netbsd/sys/arch/mips/mips/mips_mcclock.c (revision 6550d01e)
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