1 /* $NetBSD: footbridge_clock.c,v 1.18 2003/10/05 19:44:58 matt 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.18 2003/10/05 19:44:58 matt 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/device.h> 48 49 #include <machine/intr.h> 50 51 #include <arm/cpufunc.h> 52 53 #include <arm/footbridge/dc21285reg.h> 54 #include <arm/footbridge/footbridgevar.h> 55 #include <arm/footbridge/footbridge.h> 56 57 extern struct footbridge_softc *clock_sc; 58 extern u_int dc21285_fclk; 59 60 int clockhandler __P((void *)); 61 int statclockhandler __P((void *)); 62 static int load_timer __P((int, int)); 63 64 /* 65 * Statistics clock variance, in usec. Variance must be a 66 * power of two. Since this gives us an even number, not an odd number, 67 * we discard one case and compensate. That is, a variance of 1024 would 68 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 69 * This is symmetric about the point 512, or statvar/2, and thus averages 70 * to that value (assuming uniform random numbers). 71 */ 72 const int statvar = 1024; 73 int statmin; /* minimum stat clock count in ticks */ 74 int statcountperusec; /* number of ticks per usec at current stathz */ 75 int statprev; /* last value of we set statclock to */ 76 77 #if 0 78 static int clockmatch __P((struct device *parent, struct cfdata *cf, void *aux)); 79 static void clockattach __P((struct device *parent, struct device *self, void *aux)); 80 81 CFATTACH_DECL(footbridge_clock, sizeof(struct clock_softc), 82 clockmatch, clockattach, NULL, NULL); 83 84 /* 85 * int clockmatch(struct device *parent, void *match, void *aux) 86 * 87 * Just return ok for this if it is device 0 88 */ 89 90 static int 91 clockmatch(parent, cf, aux) 92 struct device *parent; 93 struct cfdata *cf; 94 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(parent, self, aux) 111 struct device *parent; 112 struct device *self; 113 void *aux; 114 { 115 struct clock_softc *sc = (struct clock_softc *)self; 116 union footbridge_attach_args *fba = aux; 117 118 sc->sc_iot = fba->fba_ca.ca_iot; 119 sc->sc_ioh = fba->fba_ca.ca_ioh; 120 121 clock_sc = sc; 122 123 /* Cannot do anything until cpu_initclocks() has been called */ 124 125 printf("\n"); 126 } 127 #endif 128 129 /* 130 * int clockhandler(struct clockframe *frame) 131 * 132 * Function called by timer 1 interrupts. 133 * This just clears the interrupt condition and calls hardclock(). 134 */ 135 136 int 137 clockhandler(aframe) 138 void *aframe; 139 { 140 struct clockframe *frame = aframe; 141 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 142 TIMER_1_CLEAR, 0); 143 hardclock(frame); 144 return(0); /* Pass the interrupt on down the chain */ 145 } 146 147 /* 148 * int statclockhandler(struct clockframe *frame) 149 * 150 * Function called by timer 2 interrupts. 151 * This just clears the interrupt condition and calls statclock(). 152 */ 153 154 int 155 statclockhandler(aframe) 156 void *aframe; 157 { 158 struct clockframe *frame = aframe; 159 int newint, r; 160 int currentclock ; 161 162 /* start the clock off again */ 163 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 164 TIMER_2_CLEAR, 0); 165 166 do { 167 r = random() & (statvar-1); 168 } while (r == 0); 169 newint = statmin + (r * statcountperusec); 170 171 /* fetch the current count */ 172 currentclock = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 173 TIMER_2_VALUE); 174 175 /* 176 * work out how much time has run, add another usec for time spent 177 * here 178 */ 179 r = ((statprev - currentclock) + statcountperusec); 180 181 if (r < newint) { 182 newint -= r; 183 r = 0; 184 } 185 else 186 printf("statclockhandler: Statclock overrun\n"); 187 188 189 /* 190 * update the clock to the new counter, this reloads the existing 191 * timer 192 */ 193 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 194 TIMER_2_LOAD, newint); 195 statprev = newint; 196 statclock(frame); 197 if (r) 198 /* 199 * We've completely overrun the previous interval, 200 * make sure we report the correct number of ticks. 201 */ 202 statclock(frame); 203 204 return(0); /* Pass the interrupt on down the chain */ 205 } 206 207 static int 208 load_timer(base, hz) 209 int base; 210 int hz; 211 { 212 unsigned int timer_count; 213 int control; 214 215 timer_count = dc21285_fclk / hz; 216 if (timer_count > TIMER_MAX_VAL * 16) { 217 control = TIMER_FCLK_256; 218 timer_count >>= 8; 219 } else if (timer_count > TIMER_MAX_VAL) { 220 control = TIMER_FCLK_16; 221 timer_count >>= 4; 222 } else 223 control = TIMER_FCLK; 224 225 control |= (TIMER_ENABLE | TIMER_MODE_PERIODIC); 226 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 227 base + TIMER_LOAD, timer_count); 228 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 229 base + TIMER_CONTROL, control); 230 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 231 base + TIMER_CLEAR, 0); 232 return(timer_count); 233 } 234 235 /* 236 * void setstatclockrate(int hz) 237 * 238 * Set the stat clock rate. The stat clock uses timer2 239 */ 240 241 void 242 setstatclockrate(hz) 243 int hz; 244 { 245 int statint; 246 int countpersecond; 247 int statvarticks; 248 249 /* statint == num in counter to drop by desired hz */ 250 statint = statprev = clock_sc->sc_statclock_count = 251 load_timer(TIMER_2_BASE, hz); 252 253 /* Get the total ticks a second */ 254 countpersecond = statint * hz; 255 256 /* now work out how many ticks per usec */ 257 statcountperusec = countpersecond / 1000000; 258 259 /* calculate a variance range of statvar */ 260 statvarticks = statcountperusec * statvar; 261 262 /* minimum is statint - 50% of variant */ 263 statmin = statint - (statvarticks / 2); 264 } 265 266 /* 267 * void cpu_initclocks(void) 268 * 269 * Initialise the clocks. 270 * 271 * Timer 1 is used for the main system clock (hardclock) 272 * Timer 2 is used for the statistics clock (statclock) 273 */ 274 275 void 276 cpu_initclocks() 277 { 278 /* stathz and profhz should be set to something, we have the timer */ 279 if (stathz == 0) 280 stathz = hz; 281 282 if (profhz == 0) 283 profhz = stathz * 5; 284 285 /* Report the clock frequencies */ 286 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 287 288 /* Setup timer 1 and claim interrupt */ 289 clock_sc->sc_clock_count = load_timer(TIMER_1_BASE, hz); 290 291 /* 292 * Use ticks per 256us for accuracy since ticks per us is often 293 * fractional e.g. @ 66MHz 294 */ 295 clock_sc->sc_clock_ticks_per_256us = 296 ((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000); 297 clock_sc->sc_clockintr = footbridge_intr_claim(IRQ_TIMER_1, IPL_CLOCK, 298 "tmr1 hard clk", clockhandler, 0); 299 300 if (clock_sc->sc_clockintr == NULL) 301 panic("%s: Cannot install timer 1 interrupt handler", 302 clock_sc->sc_dev.dv_xname); 303 304 /* If stathz is non-zero then setup the stat clock */ 305 if (stathz) { 306 /* Setup timer 2 and claim interrupt */ 307 setstatclockrate(stathz); 308 clock_sc->sc_statclockintr = footbridge_intr_claim(IRQ_TIMER_2, IPL_STATCLOCK, 309 "tmr2 stat clk", statclockhandler, 0); 310 if (clock_sc->sc_statclockintr == NULL) 311 panic("%s: Cannot install timer 2 interrupt handler", 312 clock_sc->sc_dev.dv_xname); 313 } 314 } 315 316 317 /* 318 * void microtime(struct timeval *tvp) 319 * 320 * Fill in the specified timeval struct with the current time 321 * accurate to the microsecond. 322 */ 323 324 void 325 microtime(tvp) 326 struct timeval *tvp; 327 { 328 int s; 329 int tm; 330 int deltatm; 331 static struct timeval oldtv; 332 333 if (clock_sc == NULL || clock_sc->sc_clock_count == 0) 334 return; 335 336 s = splhigh(); 337 338 tm = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 339 TIMER_1_VALUE); 340 341 deltatm = clock_sc->sc_clock_count - tm; 342 343 #ifdef DIAGNOSTIC 344 if (deltatm < 0) 345 panic("opps deltatm < 0 tm=%d deltatm=%d", tm, deltatm); 346 #endif 347 348 /* Fill in the timeval struct */ 349 *tvp = time; 350 tvp->tv_usec += ((deltatm << 8) / clock_sc->sc_clock_ticks_per_256us); 351 352 /* Make sure the micro seconds don't overflow. */ 353 while (tvp->tv_usec >= 1000000) { 354 tvp->tv_usec -= 1000000; 355 ++tvp->tv_sec; 356 } 357 358 /* Make sure the time has advanced. */ 359 if (tvp->tv_sec == oldtv.tv_sec && 360 tvp->tv_usec <= oldtv.tv_usec) { 361 tvp->tv_usec = oldtv.tv_usec + 1; 362 if (tvp->tv_usec >= 1000000) { 363 tvp->tv_usec -= 1000000; 364 ++tvp->tv_sec; 365 } 366 } 367 368 oldtv = *tvp; 369 (void)splx(s); 370 } 371 372 /* 373 * Use a timer to track microseconds, if the footbridge hasn't been setup we 374 * rely on an estimated loop, however footbridge is attached very early on. 375 */ 376 377 static int delay_clock_count = 0; 378 static int delay_count_per_usec = 0; 379 380 void 381 calibrate_delay(void) 382 { 383 delay_clock_count = load_timer(TIMER_3_BASE, 100); 384 delay_count_per_usec = delay_clock_count/10000; 385 #ifdef VERBOSE_DELAY_CALIBRATION 386 printf("delay calibration: delay_cc = %d, delay_c/us=%d\n", 387 delay_clock_count, delay_count_per_usec); 388 389 printf("0.."); 390 delay(1000000); 391 printf("1.."); 392 delay(1000000); 393 printf("2.."); 394 delay(1000000); 395 printf("3.."); 396 delay(1000000); 397 printf("4.."); 398 delay(1000000); 399 printf("5.."); 400 delay(1000000); 401 printf("6.."); 402 delay(1000000); 403 printf("7.."); 404 delay(1000000); 405 printf("8.."); 406 delay(1000000); 407 printf("9.."); 408 delay(1000000); 409 printf("10\n"); 410 #endif 411 } 412 413 int delaycount = 25000; 414 415 void 416 delay(n) 417 u_int n; 418 { 419 volatile u_int i; 420 uint32_t cur, last, delta, usecs; 421 422 if (n == 0) return; 423 424 425 /* 426 * not calibrated the timer yet, so try to live with this horrible 427 * loop! 428 */ 429 if (delay_clock_count == 0) 430 { 431 while (n-- > 0) { 432 for (i = delaycount; --i;); 433 } 434 return; 435 } 436 437 /* 438 * read the current value (do not reset it as delay is reentrant) 439 */ 440 last = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 441 TIMER_3_VALUE); 442 443 delta = usecs = 0; 444 445 while (n > usecs) 446 { 447 cur = bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_ioh, 448 TIMER_3_VALUE); 449 if (last < cur) 450 /* timer has wrapped */ 451 delta += ((delay_clock_count - cur) + last); 452 else 453 delta += (last - cur); 454 455 if (cur == 0) 456 { 457 /* 458 * reset the timer, note that if something blocks us for more 459 * than 1/100s we may delay for too long, but I believe that 460 * is fairly unlikely. 461 */ 462 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_ioh, 463 TIMER_3_CLEAR, 0); 464 } 465 last = cur; 466 467 if (delta >= delay_count_per_usec) 468 { 469 usecs += delta / delay_count_per_usec; 470 delta %= delay_count_per_usec; 471 } 472 } 473 } 474 475 /* End of footbridge_clock.c */ 476