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