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.diff -r1.24 -r1.25 src/sys/arch/arm/footbridge/footbridge_clock.c
(chris)
--- 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 | |||
58 | extern struct footbridge_softc *clock_sc; | 58 | extern struct footbridge_softc *clock_sc; | |
59 | extern u_int dc21285_fclk; | 59 | extern u_int dc21285_fclk; | |
60 | 60 | |||
61 | int clockhandler(void *); | 61 | int clockhandler(void *); | |
62 | int statclockhandler(void *); | 62 | int statclockhandler(void *); | |
63 | static int load_timer(int, int); | 63 | static 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 | */ | |
73 | const int statvar = 1024; | 73 | const int statvar = 1024; | |
74 | int statmin; /* minimum stat clock count in ticks */ | 74 | int statmin; /* minimum stat clock count in ticks */ | |
75 | int statcountperusec; /* number of ticks per usec at current stathz */ | 75 | int statcountperusec; /* number of ticks per usec at current stathz */ | |
76 | int statprev; /* last value of we set statclock to */ | 76 | int statprev; /* last value of we set statclock to */ | |
77 | 77 | |||
78 | void footbridge_tc_init(void); | 78 | void footbridge_tc_init(void); | |
79 | 79 | |||
80 | #if 0 | 80 | #if 0 | |
81 | static int clockmatch(struct device *parent, struct cfdata *cf, void *aux); | 81 | static int clockmatch(struct device *parent, struct cfdata *cf, void *aux); | |
82 | static void clockattach(struct device *parent, struct device *self, void *aux); | 82 | static void clockattach(struct device *parent, struct device *self, void *aux); | |
83 | 83 | |||
84 | CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc), | 84 | CFATTACH_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 | |||
93 | static int | 93 | static int | |
94 | clockmatch(struct device *parent, struct cfdata *cf, void *aux) | 94 | clockmatch(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 | |||
109 | static void | 109 | static void | |
110 | clockattach(struct device *parent, struct device *self, void *aux) | 110 | clockattach(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 | |||
133 | int | 133 | int | |
134 | clockhandler(void *aframe) | 134 | clockhandler(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 | |||
150 | int | 150 | int | |
151 | statclockhandler(void *aframe) | 151 | statclockhandler(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 | |||
202 | static int | 202 | static int | |
203 | load_timer(int base, int herz) | 203 | load_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 | |||
234 | void | 234 | void | |
235 | setstatclockrate(int herz) | 235 | setstatclockrate(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 | |||
267 | void | 267 | void | |
268 | cpu_initclocks(void) | 268 | cpu_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 | |||
310 | static uint32_t | 310 | static uint32_t | |
311 | fclk_get_count(struct timecounter *tc) | 311 | fclk_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 | |||
318 | void | 318 | void | |
319 | footbridge_tc_init(void) | 319 | footbridge_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 | |||
336 | static int delay_count_per_usec = 0; | 336 | static int delay_count_per_usec = 0; | |
337 | 337 | |||
338 | void | 338 | void | |
339 | calibrate_delay(void) | 339 | calibrate_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 | |||
359 | void | 359 | void | |
360 | delay(unsigned n) | 360 | delay(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 */ |