Sat Sep 20 14:53:37 2008 UTC ()
Fix kernel boot issue on cats.

The delay(9) loop, used before the clock device is probed and a hardware timer
is available, was out by a factor of 625.

This wasn't an issue until revision 1.45 of sys/dev/ic/pckbc.c which switched
to using delay(9) when polling the keyboard controller.

Cats attaches the console (and pckbc) before the clock has been probed, and so
the delay loop code is used causing issue with the keyboard polling.


(chris)
diff -r1.24 -r1.25 src/sys/arch/arm/footbridge/footbridge_clock.c

cvs diff -r1.24 -r1.25 src/sys/arch/arm/footbridge/footbridge_clock.c (switch to unified diff)

--- src/sys/arch/arm/footbridge/footbridge_clock.c 2007/12/03 15:33:17 1.24
+++ src/sys/arch/arm/footbridge/footbridge_clock.c 2008/09/20 14:53:37 1.25
@@ -1,409 +1,415 @@ @@ -1,409 +1,415 @@
1/* $NetBSD: footbridge_clock.c,v 1.24 2007/12/03 15:33:17 ad Exp $ */ 1/* $NetBSD: footbridge_clock.c,v 1.25 2008/09/20 14:53:37 chris Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 1997 Mark Brinicombe. 4 * Copyright (c) 1997 Mark Brinicombe.
5 * Copyright (c) 1997 Causality Limited. 5 * Copyright (c) 1997 Causality Limited.
6 * All rights reserved. 6 * All rights reserved.
7 * 7 *
8 * Redistribution and use in source and binary forms, with or without 8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions 9 * modification, are permitted provided that the following conditions
10 * are met: 10 * are met:
11 * 1. Redistributions of source code must retain the above copyright 11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer. 12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright 13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the 14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution. 15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software 16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement: 17 * must display the following acknowledgement:
18 * This product includes software developed by Mark Brinicombe 18 * This product includes software developed by Mark Brinicombe
19 * for the NetBSD Project. 19 * for the NetBSD Project.
20 * 4. The name of the company nor the name of the author may be used to 20 * 4. The name of the company nor the name of the author may be used to
21 * endorse or promote products derived from this software without specific 21 * endorse or promote products derived from this software without specific
22 * prior written permission. 22 * prior written permission.
23 * 23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 27 * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 28 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 29 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 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 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 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE. 34 * SUCH DAMAGE.
35 */ 35 */
36 36
37#include <sys/cdefs.h> 37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: footbridge_clock.c,v 1.24 2007/12/03 15:33:17 ad Exp $"); 38__KERNEL_RCSID(0, "$NetBSD: footbridge_clock.c,v 1.25 2008/09/20 14:53:37 chris Exp $");
39 39
40/* Include header files */ 40/* Include header files */
41 41
42#include <sys/types.h> 42#include <sys/types.h>
43#include <sys/param.h> 43#include <sys/param.h>
44#include <sys/systm.h> 44#include <sys/systm.h>
45#include <sys/kernel.h> 45#include <sys/kernel.h>
46#include <sys/time.h> 46#include <sys/time.h>
47#include <sys/timetc.h> 47#include <sys/timetc.h>
48#include <sys/device.h> 48#include <sys/device.h>
49 49
50#include <machine/intr.h> 50#include <machine/intr.h>
51 51
52#include <arm/cpufunc.h> 52#include <arm/cpufunc.h>
53 53
54#include <arm/footbridge/dc21285reg.h> 54#include <arm/footbridge/dc21285reg.h>
55#include <arm/footbridge/footbridgevar.h> 55#include <arm/footbridge/footbridgevar.h>
56#include <arm/footbridge/footbridge.h> 56#include <arm/footbridge/footbridge.h>
57 57
58extern struct footbridge_softc *clock_sc; 58extern struct footbridge_softc *clock_sc;
59extern u_int dc21285_fclk; 59extern u_int dc21285_fclk;
60 60
61int clockhandler(void *); 61int clockhandler(void *);
62int statclockhandler(void *); 62int statclockhandler(void *);
63static int load_timer(int, int); 63static int load_timer(int, int);
64 64
65/* 65/*
66 * Statistics clock variance, in usec. Variance must be a 66 * Statistics clock variance, in usec. Variance must be a
67 * power of two. Since this gives us an even number, not an odd number, 67 * power of two. Since this gives us an even number, not an odd number,
68 * we discard one case and compensate. That is, a variance of 1024 would 68 * we discard one case and compensate. That is, a variance of 1024 would
69 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 69 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023].
70 * This is symmetric about the point 512, or statvar/2, and thus averages 70 * This is symmetric about the point 512, or statvar/2, and thus averages
71 * to that value (assuming uniform random numbers). 71 * to that value (assuming uniform random numbers).
72 */ 72 */
73const int statvar = 1024; 73const int statvar = 1024;
74int statmin; /* minimum stat clock count in ticks */ 74int statmin; /* minimum stat clock count in ticks */
75int statcountperusec; /* number of ticks per usec at current stathz */ 75int statcountperusec; /* number of ticks per usec at current stathz */
76int statprev; /* last value of we set statclock to */ 76int statprev; /* last value of we set statclock to */
77 77
78void footbridge_tc_init(void); 78void footbridge_tc_init(void);
79 79
80#if 0 80#if 0
81static int clockmatch(struct device *parent, struct cfdata *cf, void *aux); 81static int clockmatch(struct device *parent, struct cfdata *cf, void *aux);
82static void clockattach(struct device *parent, struct device *self, void *aux); 82static void clockattach(struct device *parent, struct device *self, void *aux);
83 83
84CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc), 84CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc),
85 clockmatch, clockattach, NULL, NULL); 85 clockmatch, clockattach, NULL, NULL);
86 86
87/* 87/*
88 * int clockmatch(struct device *parent, void *match, void *aux) 88 * int clockmatch(struct device *parent, void *match, void *aux)
89 * 89 *
90 * Just return ok for this if it is device 0 90 * Just return ok for this if it is device 0
91 */  91 */
92  92
93static int 93static int
94clockmatch(struct device *parent, struct cfdata *cf, void *aux) 94clockmatch(struct device *parent, struct cfdata *cf, void *aux)
95{ 95{
96 union footbridge_attach_args *fba = aux; 96 union footbridge_attach_args *fba = aux;
97 97
98 if (strcmp(fba->fba_ca.ca_name, "clk") == 0) 98 if (strcmp(fba->fba_ca.ca_name, "clk") == 0)
99 return 1; 99 return 1;
100 return 0; 100 return 0;
101} 101}
102 102
103 103
104/* 104/*
105 * void clockattach(struct device *parent, struct device *dev, void *aux) 105 * void clockattach(struct device *parent, struct device *dev, void *aux)
106 * 106 *
107 */ 107 */
108  108
109static void 109static void
110clockattach(struct device *parent, struct device *self, void *aux) 110clockattach(struct device *parent, struct device *self, void *aux)
111{ 111{
112 struct clock_softc *sc = (struct clock_softc *)self; 112 struct clock_softc *sc = (struct clock_softc *)self;
113 union footbridge_attach_args *fba = aux; 113 union footbridge_attach_args *fba = aux;
114 114
115 sc->sc_iot = fba->fba_ca.ca_iot; 115 sc->sc_iot = fba->fba_ca.ca_iot;
116 sc->sc_ioh = fba->fba_ca.ca_ioh; 116 sc->sc_ioh = fba->fba_ca.ca_ioh;
117 117
118 clock_sc = sc; 118 clock_sc = sc;
119 119
120 /* Cannot do anything until cpu_initclocks() has been called */ 120 /* Cannot do anything until cpu_initclocks() has been called */
121  121
122 printf("\n"); 122 printf("\n");
123} 123}
124#endif 124#endif
125 125
126/* 126/*
127 * int clockhandler(struct clockframe *frame) 127 * int clockhandler(struct clockframe *frame)
128 * 128 *
129 * Function called by timer 1 interrupts. 129 * Function called by timer 1 interrupts.
130 * This just clears the interrupt condition and calls hardclock(). 130 * This just clears the interrupt condition and calls hardclock().
131 */ 131 */
132 132
133int 133int
134clockhandler(void *aframe) 134clockhandler(void *aframe)
135{ 135{
136 struct clockframe *frame = aframe; 136 struct clockframe *frame = aframe;
137 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 137 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
138 TIMER_1_CLEAR, 0); 138 TIMER_1_CLEAR, 0);
139 hardclock(frame); 139 hardclock(frame);
140 return 0; /* Pass the interrupt on down the chain */ 140 return 0; /* Pass the interrupt on down the chain */
141} 141}
142 142
143/* 143/*
144 * int statclockhandler(struct clockframe *frame) 144 * int statclockhandler(struct clockframe *frame)
145 * 145 *
146 * Function called by timer 2 interrupts. 146 * Function called by timer 2 interrupts.
147 * This just clears the interrupt condition and calls statclock(). 147 * This just clears the interrupt condition and calls statclock().
148 */ 148 */
149  149
150int 150int
151statclockhandler(void *aframe) 151statclockhandler(void *aframe)
152{ 152{
153 struct clockframe *frame = aframe; 153 struct clockframe *frame = aframe;
154 int newint, r; 154 int newint, r;
155 int currentclock ; 155 int currentclock ;
156 156
157 /* start the clock off again */ 157 /* start the clock off again */
158 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 158 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
159 TIMER_2_CLEAR, 0); 159 TIMER_2_CLEAR, 0);
160 160
161 do { 161 do {
162 r = random() & (statvar-1); 162 r = random() & (statvar-1);
163 } while (r == 0); 163 } while (r == 0);
164 newint = statmin + (r * statcountperusec); 164 newint = statmin + (r * statcountperusec);
165  165
166 /* fetch the current count */ 166 /* fetch the current count */
167 currentclock = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 167 currentclock = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
168 TIMER_2_VALUE); 168 TIMER_2_VALUE);
169 169
170 /*  170 /*
171 * work out how much time has run, add another usec for time spent 171 * work out how much time has run, add another usec for time spent
172 * here 172 * here
173 */ 173 */
174 r = ((statprev - currentclock) + statcountperusec); 174 r = ((statprev - currentclock) + statcountperusec);
175 175
176 if (r < newint) { 176 if (r < newint) {
177 newint -= r; 177 newint -= r;
178 r = 0; 178 r = 0;
179 } 179 }
180 else  180 else
181 printf("statclockhandler: Statclock overrun\n"); 181 printf("statclockhandler: Statclock overrun\n");
182 182
183 183
184 /*  184 /*
185 * update the clock to the new counter, this reloads the existing 185 * update the clock to the new counter, this reloads the existing
186 * timer 186 * timer
187 */ 187 */
188 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 188 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
189 TIMER_2_LOAD, newint); 189 TIMER_2_LOAD, newint);
190 statprev = newint; 190 statprev = newint;
191 statclock(frame); 191 statclock(frame);
192 if (r) 192 if (r)
193 /* 193 /*
194 * We've completely overrun the previous interval, 194 * We've completely overrun the previous interval,
195 * make sure we report the correct number of ticks.  195 * make sure we report the correct number of ticks.
196 */ 196 */
197 statclock(frame); 197 statclock(frame);
198 198
199 return 0; /* Pass the interrupt on down the chain */ 199 return 0; /* Pass the interrupt on down the chain */
200} 200}
201 201
202static int 202static int
203load_timer(int base, int herz) 203load_timer(int base, int herz)
204{ 204{
205 unsigned int timer_count; 205 unsigned int timer_count;
206 int control; 206 int control;
207 207
208 timer_count = dc21285_fclk / herz; 208 timer_count = dc21285_fclk / herz;
209 if (timer_count > TIMER_MAX_VAL * 16) { 209 if (timer_count > TIMER_MAX_VAL * 16) {
210 control = TIMER_FCLK_256; 210 control = TIMER_FCLK_256;
211 timer_count >>= 8; 211 timer_count >>= 8;
212 } else if (timer_count > TIMER_MAX_VAL) { 212 } else if (timer_count > TIMER_MAX_VAL) {
213 control = TIMER_FCLK_16; 213 control = TIMER_FCLK_16;
214 timer_count >>= 4; 214 timer_count >>= 4;
215 } else 215 } else
216 control = TIMER_FCLK; 216 control = TIMER_FCLK;
217 217
218 control |= (TIMER_ENABLE | TIMER_MODE_PERIODIC); 218 control |= (TIMER_ENABLE | TIMER_MODE_PERIODIC);
219 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 219 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
220 base + TIMER_LOAD, timer_count); 220 base + TIMER_LOAD, timer_count);
221 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 221 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
222 base + TIMER_CONTROL, control); 222 base + TIMER_CONTROL, control);
223 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 223 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
224 base + TIMER_CLEAR, 0); 224 base + TIMER_CLEAR, 0);
225 return timer_count; 225 return timer_count;
226} 226}
227 227
228/* 228/*
229 * void setstatclockrate(int herz) 229 * void setstatclockrate(int herz)
230 * 230 *
231 * Set the stat clock rate. The stat clock uses timer2 231 * Set the stat clock rate. The stat clock uses timer2
232 */ 232 */
233 233
234void 234void
235setstatclockrate(int herz) 235setstatclockrate(int herz)
236{ 236{
237 int statint; 237 int statint;
238 int countpersecond; 238 int countpersecond;
239 int statvarticks; 239 int statvarticks;
240 240
241 /* statint == num in counter to drop by desired herz */ 241 /* statint == num in counter to drop by desired herz */
242 statint = statprev = clock_sc->sc_statclock_count = 242 statint = statprev = clock_sc->sc_statclock_count =
243 load_timer(TIMER_2_BASE, herz); 243 load_timer(TIMER_2_BASE, herz);
244  244
245 /* Get the total ticks a second */ 245 /* Get the total ticks a second */
246 countpersecond = statint * herz; 246 countpersecond = statint * herz;
247  247
248 /* now work out how many ticks per usec */ 248 /* now work out how many ticks per usec */
249 statcountperusec = countpersecond / 1000000; 249 statcountperusec = countpersecond / 1000000;
250 250
251 /* calculate a variance range of statvar */ 251 /* calculate a variance range of statvar */
252 statvarticks = statcountperusec * statvar; 252 statvarticks = statcountperusec * statvar;
253  253
254 /* minimum is statint - 50% of variant */ 254 /* minimum is statint - 50% of variant */
255 statmin = statint - (statvarticks / 2); 255 statmin = statint - (statvarticks / 2);
256} 256}
257 257
258/* 258/*
259 * void cpu_initclocks(void) 259 * void cpu_initclocks(void)
260 * 260 *
261 * Initialise the clocks. 261 * Initialise the clocks.
262 * 262 *
263 * Timer 1 is used for the main system clock (hardclock) 263 * Timer 1 is used for the main system clock (hardclock)
264 * Timer 2 is used for the statistics clock (statclock) 264 * Timer 2 is used for the statistics clock (statclock)
265 */ 265 */
266  266
267void 267void
268cpu_initclocks(void) 268cpu_initclocks(void)
269{ 269{
270 /* stathz and profhz should be set to something, we have the timer */ 270 /* stathz and profhz should be set to something, we have the timer */
271 if (stathz == 0) 271 if (stathz == 0)
272 stathz = hz; 272 stathz = hz;
273 273
274 if (profhz == 0) 274 if (profhz == 0)
275 profhz = stathz * 5; 275 profhz = stathz * 5;
276 276
277 /* Report the clock frequencies */ 277 /* Report the clock frequencies */
278 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 278 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz);
279 279
280 /* Setup timer 1 and claim interrupt */ 280 /* Setup timer 1 and claim interrupt */
281 clock_sc->sc_clock_count = load_timer(TIMER_1_BASE, hz); 281 clock_sc->sc_clock_count = load_timer(TIMER_1_BASE, hz);
282 282
283 /* 283 /*
284 * Use ticks per 256us for accuracy since ticks per us is often 284 * Use ticks per 256us for accuracy since ticks per us is often
285 * fractional e.g. @ 66MHz 285 * fractional e.g. @ 66MHz
286 */ 286 */
287 clock_sc->sc_clock_ticks_per_256us = 287 clock_sc->sc_clock_ticks_per_256us =
288 ((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000); 288 ((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000);
289 clock_sc->sc_clockintr = footbridge_intr_claim(IRQ_TIMER_1, IPL_CLOCK, 289 clock_sc->sc_clockintr = footbridge_intr_claim(IRQ_TIMER_1, IPL_CLOCK,
290 "tmr1 hard clk", clockhandler, 0); 290 "tmr1 hard clk", clockhandler, 0);
291 291
292 if (clock_sc->sc_clockintr == NULL) 292 if (clock_sc->sc_clockintr == NULL)
293 panic("%s: Cannot install timer 1 interrupt handler", 293 panic("%s: Cannot install timer 1 interrupt handler",
294 clock_sc->sc_dev.dv_xname); 294 clock_sc->sc_dev.dv_xname);
295 295
296 /* If stathz is non-zero then setup the stat clock */ 296 /* If stathz is non-zero then setup the stat clock */
297 if (stathz) { 297 if (stathz) {
298 /* Setup timer 2 and claim interrupt */ 298 /* Setup timer 2 and claim interrupt */
299 setstatclockrate(stathz); 299 setstatclockrate(stathz);
300 clock_sc->sc_statclockintr = footbridge_intr_claim(IRQ_TIMER_2, IPL_HIGH, 300 clock_sc->sc_statclockintr = footbridge_intr_claim(IRQ_TIMER_2, IPL_HIGH,
301 "tmr2 stat clk", statclockhandler, 0); 301 "tmr2 stat clk", statclockhandler, 0);
302 if (clock_sc->sc_statclockintr == NULL) 302 if (clock_sc->sc_statclockintr == NULL)
303 panic("%s: Cannot install timer 2 interrupt handler", 303 panic("%s: Cannot install timer 2 interrupt handler",
304 clock_sc->sc_dev.dv_xname); 304 clock_sc->sc_dev.dv_xname);
305 } 305 }
306 306
307 footbridge_tc_init(); 307 footbridge_tc_init();
308} 308}
309 309
310static uint32_t 310static uint32_t
311fclk_get_count(struct timecounter *tc) 311fclk_get_count(struct timecounter *tc)
312{ 312{
313 return (TIMER_MAX_VAL - 313 return (TIMER_MAX_VAL -
314 bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 314 bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
315 TIMER_3_VALUE)); 315 TIMER_3_VALUE));
316} 316}
317 317
318void 318void
319footbridge_tc_init(void) 319footbridge_tc_init(void)
320{ 320{
321 static struct timecounter fb_tc = { 321 static struct timecounter fb_tc = {
322 .tc_get_timecount = fclk_get_count, 322 .tc_get_timecount = fclk_get_count,
323 .tc_counter_mask = TIMER_MAX_VAL, 323 .tc_counter_mask = TIMER_MAX_VAL,
324 .tc_name = "dc21285_fclk", 324 .tc_name = "dc21285_fclk",
325 .tc_quality = 100 325 .tc_quality = 100
326 }; 326 };
327 fb_tc.tc_frequency = dc21285_fclk; 327 fb_tc.tc_frequency = dc21285_fclk;
328 tc_init(&fb_tc); 328 tc_init(&fb_tc);
329} 329}
330 330
331/* 331/*
332 * Use a timer to track microseconds, if the footbridge hasn't been setup we 332 * Use a timer to track microseconds, if the footbridge hasn't been setup we
333 * rely on an estimated loop, however footbridge is attached very early on. 333 * rely on an estimated loop, however footbridge is attached very early on.
334 */ 334 */
335 335
336static int delay_count_per_usec = 0; 336static int delay_count_per_usec = 0;
337 337
338void 338void
339calibrate_delay(void) 339calibrate_delay(void)
340{ 340{
341 /* 341 /*
342 * For all current footbridge hardware, the fclk runs at a 342 * For all current footbridge hardware, the fclk runs at a
343 * rate that is sufficiently slow enough that we don't need to 343 * rate that is sufficiently slow enough that we don't need to
344 * use a prescaler. A prescaler would be needed if the fclk 344 * use a prescaler. A prescaler would be needed if the fclk
345 * could wrap within 2 hardclock periods (2 * HZ). With 345 * could wrap within 2 hardclock periods (2 * HZ). With
346 * normal values of HZ (100 and higher), this is unlikely to 346 * normal values of HZ (100 and higher), this is unlikely to
347 * ever happen. 347 * ever happen.
348 * 348 *
349 * We let TIMER 3 just run free, at the freqeuncy supplied by 349 * We let TIMER 3 just run free, at the freqeuncy supplied by
350 * dc21285_fclk. 350 * dc21285_fclk.
351 */ 351 */
352 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 352 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh,
353 TIMER_3_BASE + TIMER_CONTROL, TIMER_ENABLE); 353 TIMER_3_BASE + TIMER_CONTROL, TIMER_ENABLE);
354 delay_count_per_usec = dc21285_fclk / 1000000; 354 delay_count_per_usec = dc21285_fclk / 1000000;
355 if (dc21285_fclk % 1000000) 355 if (dc21285_fclk % 1000000)
356 delay_count_per_usec += 1; 356 delay_count_per_usec += 1;
357} 357}
358 358
359void 359void
360delay(unsigned n) 360delay(unsigned n)
361{ 361{
362 uint32_t cur, last, delta, usecs; 362 uint32_t cur, last, delta, usecs;
363 363
364 if (n == 0) 364 if (n == 0)
365 return; 365 return;
366 366
367 /*  367 /*
368 * not calibrated the timer yet, so try to live with this horrible 368 * not calibrated the timer yet, so try to live with this horrible
369 * loop! 369 * loop!
370 * 370 *
371 * Note: a much better solution might be to have the timers 371 * Note: a much better solution might be to have the timers
372 * get get calibrated out of mach_init. Of course, the 372 * get get calibrated out of mach_init. Of course, the
373 * clock_sc needs to be set up, so we can read/write the clock 373 * clock_sc needs to be set up, so we can read/write the clock
374 * registers. 374 * registers.
375 */ 375 */
376 if (!delay_count_per_usec) 376 if (!delay_count_per_usec)
377 { 377 {
378 int delaycount = 25000; 378 /*
 379 * the loop below has a core of 6 instructions
 380 * StrongArms top out at 233Mhz, so one instruction takes
 381 * 0.004 us, and 6 take 0.025 us, so we need to loop 40
 382 * times to make one usec
 383 */
 384 int delaycount = 40;
379 volatile int i; 385 volatile int i;
380 386
381 while (n-- > 0) { 387 while (n-- > 0) {
382 for (i = delaycount; --i;); 388 for (i = delaycount; --i;);
383 } 389 }
384 return;  390 return;
385 } 391 }
386 392
387 last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 393 last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
388 TIMER_3_VALUE); 394 TIMER_3_VALUE);
389 delta = usecs = 0; 395 delta = usecs = 0;
390  396
391 while (n > usecs) { 397 while (n > usecs) {
392 cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 398 cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh,
393 TIMER_3_VALUE); 399 TIMER_3_VALUE);
394 if (last < cur) 400 if (last < cur)
395 /* timer has wrapped */ 401 /* timer has wrapped */
396 delta += ((TIMER_MAX_VAL - cur) + last); 402 delta += ((TIMER_MAX_VAL - cur) + last);
397 else 403 else
398 delta += (last - cur); 404 delta += (last - cur);
399 405
400 last = cur; 406 last = cur;
401 407
402 while (delta >= delay_count_per_usec) { 408 while (delta >= delay_count_per_usec) {
403 delta -= delay_count_per_usec; 409 delta -= delay_count_per_usec;
404 usecs++; 410 usecs++;
405 } 411 }
406 } 412 }
407} 413}
408 414
409/* End of footbridge_clock.c */ 415/* End of footbridge_clock.c */