xref: /netbsd/sys/arch/mips/mips/mips_mcclock.c (revision bf9ec67e)
1 /* $NetBSD: mips_mcclock.c,v 1.11 2002/03/05 15:54:33 simonb 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.11 2002/03/05 15:54:33 simonb Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 
43 #include <dev/ic/mc146818reg.h>
44 #include <dev/dec/mcclockvar.h>
45 #include <dev/dec/mcclock_pad32.h>
46 
47 #include <mips/cpu.h>			/* MIPS_HAS_CLOCK */
48 #include <mips/locore.h>		/* mips_cp0_cause_read() */
49 #include <mips/mips/mips_mcclock.h>
50 
51 
52 unsigned mips_mc_cpuspeed(void *, int, int (*)(void *, int));
53 int mips_mcclock_tickloop(void *, int);
54 unsigned mips_mcclock_to_mhz(unsigned iters);
55 
56 
57 /*
58  * Compute MHz and DELAY() constants using the default
59  * polling function.
60  */
61 unsigned
62 mc_cpuspeed(mcclock_addr, cpuintmask)
63 	vaddr_t mcclock_addr;
64     	int cpuintmask;
65 {
66 	return mips_mc_cpuspeed((void *)mcclock_addr, cpuintmask,
67 	           mips_mcclock_tickloop);
68 }
69 
70 
71 /*
72  * Estimate CPU cycle speed by counting cycles (acutally executions of a
73  * one-line loop) between two adjacent ticks of an mc146818 clock.
74  * Return loop iteration count so hand-calibrated  MD  code can
75  * estimate clock speed from cycles.
76  *
77  * Runs before CPU is attached (so we can print CPU speed)  which is
78  * before the clock is attached, so we can't use the normal clock driver.
79  */
80 unsigned
81 mips_mc_cpuspeed(mcclock_addr, clockmask, tickpollfn)
82 	void *mcclock_addr;
83 	int clockmask;
84 	int (*tickpollfn)(void *mcclock_addr, int clockmask);
85 {
86 	int s;
87 	int iters = 0;
88 	int saved_rega, saved_regb;
89 	volatile struct mcclock_pad32_clockdatum *clk = (void *)mcclock_addr;
90 
91 	/*
92 	 * Block all interrupts, including clock ticks.
93 	 */
94 	s = splhigh();
95 
96 	/*
97 	 * Enable periodic interrupst on the mc146818,
98 	 * and set it up for 256Hz (4ms) interrupts.
99 	 * Save any state we change so we can restore it on exit.
100 	 */
101 	saved_rega = clk[MC_REGA].datum;
102 	saved_regb = clk[MC_REGB].datum;
103 
104 #if 0
105 	mcclock_addr->rega = (saved_rega & ~MC_BASE_RESET) | MC_RATE_256_Hz;
106 	mcclock_addr->regb = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE;
107 #else
108 	clk[MC_REGA].datum = MC_BASE_32_KHz | MC_RATE_256_Hz;
109 	clk[MC_REGB].datum = MC_REGB_BINARY|MC_REGB_24HR|MC_REGB_PIE| MC_REGB_SQWE;
110 #endif
111 	/* count loop iterations between ticks */
112 	iters = (*tickpollfn)(mcclock_addr, clockmask);
113 
114 	/* Restore mcclock registers */
115 	clk[MC_REGA].datum = saved_rega;
116 	clk[MC_REGB].datum = saved_regb;
117 
118 	splx(s);
119 
120 	/*
121 	 * Compute approximate CPU speed in MHz, and an
122 	 * appropriate base for  DELAY() and delay(), from
123 	 * the number of completed iterations.
124 	 */
125 	cpu_mhz = mips_mcclock_to_mhz(iters);
126 
127 #if defined(DEBUG)
128 	printf("mcclock: iters %d computed MHz %d, instrs per usec=%d\n",
129 	       iters, cpu_mhz, cpuspeed);
130 #endif
131 	return (iters);
132 }
133 
134 
135 /*
136  * Poll mcclock chip for the next tick interrupt and count
137  * instructions until the subsequent tick.
138  *
139  * XXX Assumes the mcclock chip has exclusive use of a CPU interrupt line.
140  * XXX Assumes bus access to clock registers is cheap (not a function call).
141  *  MD alternatives must be used where this doesn't hold.
142  */
143 
144 int
145 mips_mcclock_tickloop(mcclock_addr, clockmask)
146 	void *mcclock_addr;
147 	int clockmask;
148 {
149 	int iters = 0;
150 	volatile int junk;
151 	volatile struct mcclock_pad32_clockdatum *clk = mcclock_addr;
152 
153 	/* clear any old pending interrupts */
154 	junk = clk[MC_REGC].datum;
155 	junk++;	junk++;	junk++;	junk++;
156 
157 	/* Poll clock interrupt, waiting for next tick to happen. */
158 	while ((mips_cp0_cause_read() & clockmask) == 0)
159 		;
160 
161 	/* Ack the mc146818 interrupt caused by starting tick. */
162 	junk = clk[MC_REGC].datum;
163 
164 	junk++;	junk++;	junk++;	junk++;
165 
166 	/* Count loops until next tick-interrupt request occurs (4ms). */
167 	if (MIPS_HAS_CLOCK) {
168 		while ((mips_cp0_cause_read() & clockmask) == 0) {
169 			__asm __volatile ("nop; nop; nop; nop");
170 			iters++;
171 		}
172 	} else {
173 		while ((mips_cp0_cause_read() & clockmask) == 0) {
174 			__asm __volatile ("nop; nop;");
175 			iters++;
176 		}
177 	}
178 
179 	/* Ack the  interrupt from the just-gone-off tick */
180 	junk = clk[MC_REGC].datum;
181 
182 	return (iters);
183 }
184 
185 
186 /*
187  * mips_mcclock_to_mhz(iters) -- convert an mcclock cycles-per-tick count
188  * 	to a CPU speed in MHz.
189  *
190  * Side Effects:
191  * 	set the global variables "cpuspeed", used by DELAY() and delay()
192  *	as an instructions-per-microsecond multiplier, to an value appropriate
193  *	for the estimated clock speed.
194  */
195 unsigned
196 mips_mcclock_to_mhz(unsigned iters)
197 {
198 	unsigned mhz = 0;
199 
200 	/* XXX KN01? */
201 
202 	/*
203 	 * Measured thresholds for Digital systems from Sean Davidson.
204 	 *
205 	 * r3000-core DECstations values fit to:
206 	 *     iters per 4ms tick = 425 * MHz)
207 	 *     instructions per mhz = kHz * 575
208 	 * with about 2 Mhz slop to allow for variation.
209 	 */
210 
211 #ifdef MIPS3_PLUS
212 	if (CPUISMIPS3) {
213 		if (iters < 18100) {
214 			/* error */
215 			printf("mcclock loop count %d too low for r4000\n",
216 			       iters);
217 			mhz = 45;
218 			cpuspeed = 20;	/* XXX */
219 		} else if (iters < 21000) {
220 			mhz = 50;
221 			cpuspeed = 25;	/* XXX */
222 		} else if (iters < 25315) {
223 			mhz = 60;
224 			cpuspeed = 27;	/* XXX */
225 		} else if (iters < 28497) {
226 			mhz = 67;
227 			cpuspeed = 33;	/* XXX */
228 		} else if (iters < 31500) {
229 			mhz = 75;
230 			cpuspeed = 38;	/* XXX */
231 		}
232 	}
233 #endif /* MIPS3_PLUS */
234 
235 #ifdef MIPS1
236 	if (!CPUISMIPS3) {
237 		if (iters < 5100) {
238 			/* assume memory-bound DS 2100 */
239 			mhz = 12;	/* 12.5 MHz? */
240 			cpuspeed = 8;
241 		} else if (iters < 6700) {
242 			/* assume memory-bound DS3100 */
243 			mhz = 15;
244 			cpuspeed = 8;
245 		} else if (iters < 8800) {
246 			mhz = 20;
247 			cpuspeed = 11;
248 		} else if (iters < 11300) {
249 			mhz = 25;
250 			cpuspeed = 13;
251 		} else if (iters < 14000) {
252 			mhz = 33;
253 			cpuspeed = 19;
254 		} else if (iters < 15000) {
255 			mhz = 36;
256 			cpuspeed = 21;
257 		} else if (iters < 16000) {
258 			mhz = 40;
259 			cpuspeed = 23;
260 		} else if (iters < 18800) {
261 			mhz = 45;
262 			cpuspeed = 25;
263 		} else if (iters < 21000) {
264 			mhz = 50;
265 			cpuspeed = 29;
266 		} else if (iters < 26000) {
267 			mhz = 60;
268 			cpuspeed = 35;
269 		} else {
270 			/* XXX */
271 			mhz = 70;
272 			cpuspeed = 40;
273 		}
274 	}
275 #endif	/* MIPS1 */
276 
277 	return (mhz);
278 }
279