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