1 /* $NetBSD: ifpga_clock.c,v 1.3 2002/01/30 03:59:41 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 2001 ARM Ltd 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the company may not be used to endorse or promote 16 * products derived from this software without specific prior written 17 * permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 23 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 25 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * The IFPGA has three timers. Timer 0 is clocked by the system bus clock, 34 * while timers 1 and 2 are clocked at 24MHz. To keep things simple here, 35 * we use timers 1 and 2 only. All three timers are 16-bit counters that 36 * are programmable in either periodic mode or in one-shot mode. 37 */ 38 39 /* Include header files */ 40 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/kernel.h> 45 #include <sys/time.h> 46 #include <sys/device.h> 47 48 #include <arm/cpufunc.h> 49 #include <machine/intr.h> 50 #include <evbarm/ifpga/irqhandler.h> /* XXX XXX XXX */ 51 52 #include <evbarm/ifpga/ifpgavar.h> 53 #include <evbarm/ifpga/ifpgamem.h> 54 #include <evbarm/ifpga/ifpgareg.h> 55 56 /* 57 * Statistics clock interval and variance, in usec. Variance must be a 58 * power of two. Since this gives us an even number, not an odd number, 59 * we discard one case and compensate. That is, a variance of 1024 would 60 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 61 * This is symmetric about the point 512, or statvar/2, and thus averages 62 * to that value (assuming uniform random numbers). 63 */ 64 static int statvar = 1024 / 4; /* {stat,prof}clock variance */ 65 static int statmin; /* statclock interval - variance/2 */ 66 static int profmin; /* profclock interval - variance/2 */ 67 static int timer2min; /* current, from above choices */ 68 static int statprev; /* previous value in stat timer */ 69 70 #define TIMER_1_CLEAR (IFPGA_TIMER1_BASE + TIMERx_CLR) 71 #define TIMER_1_LOAD (IFPGA_TIMER1_BASE + TIMERx_LOAD) 72 #define TIMER_1_VALUE (IFPGA_TIMER1_BASE + TIMERx_VALUE) 73 #define TIMER_1_CTRL (IFPGA_TIMER1_BASE + TIMERx_CTRL) 74 75 #define TIMER_2_CLEAR (IFPGA_TIMER2_BASE + TIMERx_CLR) 76 #define TIMER_2_LOAD (IFPGA_TIMER2_BASE + TIMERx_LOAD) 77 #define TIMER_2_VALUE (IFPGA_TIMER2_BASE + TIMERx_VALUE) 78 #define TIMER_2_CTRL (IFPGA_TIMER2_BASE + TIMERx_CTRL) 79 80 #define COUNTS_PER_SEC (IFPGA_TIMER1_FREQ / 16) 81 82 extern struct ifpga_softc *clock_sc; 83 84 static int clock_started = 0; 85 86 static int load_timer(int, int); 87 88 static __inline u_int 89 getclock(void) 90 { 91 return bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 92 TIMER_1_VALUE); 93 } 94 95 static __inline u_int 96 getstatclock(void) 97 { 98 return bus_space_read_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 99 TIMER_2_VALUE); 100 } 101 102 /* 103 * int clockhandler(struct clockframe *frame) 104 * 105 * Function called by timer 1 interrupts. 106 * This just clears the interrupt condition and calls hardclock(). 107 */ 108 109 static int 110 clockhandler(void *fr) 111 { 112 struct clockframe *frame = (struct clockframe *)fr; 113 114 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 115 TIMER_1_CLEAR, 0); 116 hardclock(frame); 117 return 0; /* Pass the interrupt on down the chain */ 118 } 119 120 121 /* 122 * int statclockhandler(struct clockframe *frame) 123 * 124 * Function called by timer 2 interrupts. 125 * Add some random jitter to the clock, and then call statclock(). 126 */ 127 128 static int 129 statclockhandler(void *fr) 130 { 131 struct clockframe *frame = (struct clockframe *) fr; 132 int newint, r, var; 133 134 var = statvar; 135 do { 136 r = random() & (var - 1); 137 } while (r == 0); 138 newint = timer2min + r; 139 140 if (newint & ~0x0000ffff) 141 panic("statclockhandler: statclock variance too large"); 142 143 /* 144 * The timer was automatically reloaded with the previous latch 145 * value at the time of the interrupts. Compensate now for the 146 * amount of time that has run off since then, plus one tick 147 * roundoff. This should keep us closer to the mean. 148 */ 149 150 r = (statprev - getstatclock() + 1); 151 if (r < newint) { 152 newint -= r; 153 r = 0; 154 } 155 else 156 printf("statclockhandler: Statclock overrun\n"); 157 158 statprev = load_timer(IFPGA_TIMER2_BASE, newint); 159 statclock(frame); 160 if (r) 161 /* 162 * We've completely overrun the previous interval, 163 * make sure we report the correct number of ticks. 164 */ 165 statclock(frame); 166 167 return 0; /* Pass the interrupt on down the chain */ 168 } 169 170 static int 171 load_timer(int base, int intvl) 172 { 173 int control; 174 175 if (intvl & ~0x0000ffff) 176 panic("clock: Invalid interval\n"); 177 178 control = (TIMERx_CTRL_ENABLE | TIMERx_CTRL_MODE_PERIODIC | 179 TIMERx_CTRL_PRESCALE_DIV16); 180 181 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 182 base + TIMERx_LOAD, intvl); 183 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 184 base + TIMERx_CTRL, control); 185 bus_space_write_4(clock_sc->sc_iot, clock_sc->sc_tmr_ioh, 186 base + TIMERx_CLR, 0); 187 return intvl; 188 } 189 190 /* 191 * void setstatclockrate(int hz) 192 * 193 * We assume that hz is either stathz or profhz, and that neither will 194 * change after being set by cpu_initclocks(). We could recalculate the 195 * intervals here, but that would be a pain. 196 */ 197 198 void 199 setstatclockrate(int hz) 200 { 201 if (hz == stathz) 202 timer2min = statmin; 203 else 204 timer2min = profmin; 205 } 206 207 /* 208 * void cpu_initclocks(void) 209 * 210 * Initialise the clocks. 211 */ 212 213 void 214 cpu_initclocks() 215 { 216 int intvl; 217 int statint; 218 int profint; 219 int minint; 220 221 if (hz < 50 || COUNTS_PER_SEC % hz) { 222 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 223 hz = 100; 224 tick = 1000000 / hz; 225 } 226 227 if (stathz == 0) 228 stathz = hz; 229 else if (stathz < 50 || COUNTS_PER_SEC % stathz) { 230 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 231 stathz = 100; 232 } 233 234 if (profhz == 0) 235 profhz = stathz * 5; 236 else if (profhz < stathz || COUNTS_PER_SEC % profhz) { 237 printf("cannot get %d Hz profclock; using %d Hz\n", profhz, 238 stathz); 239 profhz = stathz; 240 } 241 242 intvl = COUNTS_PER_SEC / hz; 243 statint = COUNTS_PER_SEC / stathz; 244 profint = COUNTS_PER_SEC / profhz; 245 minint = statint / 2 + 100; 246 while (statvar > minint) 247 statvar >>= 1; 248 249 /* Adjust interval counts, per note above. */ 250 intvl--; 251 statint--; 252 profint--; 253 254 /* Calculate the base reload values. */ 255 statmin = statint - (statvar >> 1); 256 profmin = profint - (statvar >> 1); 257 timer2min = statmin; 258 statprev = statint; 259 260 /* Report the clock frequencies */ 261 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 262 263 /* Setup timer 1 and claim interrupt */ 264 clock_sc->sc_clockintr = intr_claim(IFPGA_TIMER1_IRQ, IPL_CLOCK, 265 "tmr1 hard clk", clockhandler, 0); 266 if (clock_sc->sc_clockintr == NULL) 267 panic("%s: Cannot install timer 1 interrupt handler\n", 268 clock_sc->sc_dev.dv_xname); 269 270 clock_sc->sc_clock_count 271 = load_timer(IFPGA_TIMER1_BASE, intvl); 272 273 /* 274 * Use ticks per 256us for accuracy since ticks per us is often 275 * fractional e.g. @ 66MHz 276 */ 277 clock_sc->sc_clock_ticks_per_256us = 278 ((((clock_sc->sc_clock_count * hz) / 1000) * 256) / 1000); 279 280 clock_started = 1; 281 282 /* Set up timer 2 as statclk/profclk. */ 283 clock_sc->sc_statclockintr = intr_claim(IFPGA_TIMER2_IRQ, 284 IPL_STATCLOCK, "tmr2 stat clk", statclockhandler, 0); 285 if (clock_sc->sc_statclockintr == NULL) 286 panic("%s: Cannot install timer 2 interrupt handler\n", 287 clock_sc->sc_dev.dv_xname); 288 load_timer(IFPGA_TIMER2_BASE, statint); 289 } 290 291 292 /* 293 * void microtime(struct timeval *tvp) 294 * 295 * Fill in the specified timeval struct with the current time 296 * accurate to the microsecond. 297 */ 298 299 void 300 microtime(struct timeval *tvp) 301 { 302 int s; 303 int tm; 304 int deltatm; 305 static struct timeval oldtv; 306 307 if (clock_sc == NULL || clock_sc->sc_clock_count == 0) 308 return; 309 310 s = splhigh(); 311 312 tm = getclock(); 313 314 deltatm = clock_sc->sc_clock_count - tm; 315 316 #ifdef DIAGNOSTIC 317 if (deltatm < 0) 318 panic("opps deltatm < 0 tm=%d deltatm=%d\n", tm, deltatm); 319 #endif 320 321 /* Fill in the timeval struct */ 322 *tvp = time; 323 tvp->tv_usec += ((deltatm << 8) / clock_sc->sc_clock_ticks_per_256us); 324 325 /* Make sure the micro seconds don't overflow. */ 326 while (tvp->tv_usec >= 1000000) { 327 tvp->tv_usec -= 1000000; 328 ++tvp->tv_sec; 329 } 330 331 /* Make sure the time has advanced. */ 332 if (tvp->tv_sec == oldtv.tv_sec && 333 tvp->tv_usec <= oldtv.tv_usec) { 334 tvp->tv_usec = oldtv.tv_usec + 1; 335 if (tvp->tv_usec >= 1000000) { 336 tvp->tv_usec -= 1000000; 337 ++tvp->tv_sec; 338 } 339 } 340 341 oldtv = *tvp; 342 (void)splx(s); 343 } 344 345 /* 346 * Estimated loop for n microseconds 347 */ 348 349 /* Need to re-write this to use the timers */ 350 351 /* One day soon I will actually do this */ 352 353 int delaycount = 50; 354 355 void 356 delay(u_int n) 357 { 358 if (clock_started) { 359 u_int starttime; 360 u_int curtime; 361 362 starttime = getclock(); 363 364 n *= IFPGA_TIMER1_FREQ / 1000000; 365 366 do { 367 curtime = getclock(); 368 } while (n > (curtime - starttime)); 369 } else { 370 volatile u_int i; 371 372 if (n == 0) return; 373 while (n-- > 0) { 374 /* XXX - Seriously gross hack */ 375 if (cputype == CPU_ID_SA110) 376 for (i = delaycount; --i;) 377 ; 378 else 379 for (i = 8; --i;) 380 ; 381 } 382 } 383 } 384