1/* $NetBSD: ifpga_clock.c,v 1.16 2020/05/29 12:30:39 rin 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 (1Mhz for Integrator CP). To 35 * keep things simple here, we use timers 1 and 2 only. All three timers 36 * are 16-bit counters that are programmable in either periodic mode or in 37 * one-shot mode. 38 */ 39 40/* Include header files */ 41 42#include <sys/cdefs.h> 43__KERNEL_RCSID(0, "$NetBSD: ifpga_clock.c,v 1.16 2020/05/29 12:30:39 rin Exp $"); 44 45#include <sys/types.h> 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/kernel.h> 49#include <sys/atomic.h> 50#include <sys/time.h> 51#include <sys/timetc.h> 52#include <sys/device.h> 53 54#include <arm/cpufunc.h> 55#include <machine/intr.h> 56 57#include <evbarm/ifpga/ifpgavar.h> 58#include <evbarm/ifpga/ifpgamem.h> 59#include <evbarm/ifpga/ifpgareg.h> 60 61/* 62 * Statistics clock interval and variance, in usec. Variance must be a 63 * power of two. Since this gives us an even number, not an odd number, 64 * we discard one case and compensate. That is, a variance of 1024 would 65 * give us offsets in [0..1023]. Instead, we take offsets in [1..1023]. 66 * This is symmetric about the point 512, or statvar/2, and thus averages 67 * to that value (assuming uniform random numbers). 68 */ 69static int statvar = 1024 / 4; /* {stat,prof}clock variance */ 70static int statmin; /* statclock interval - variance/2 */ 71static int profmin; /* profclock interval - variance/2 */ 72static int timer2min; /* current, from above choices */ 73static int statprev; /* previous value in stat timer */ 74 75#define TIMER_1_CLEAR (IFPGA_TIMER1_BASE + TIMERx_CLR) 76#define TIMER_1_LOAD (IFPGA_TIMER1_BASE + TIMERx_LOAD) 77#define TIMER_1_VALUE (IFPGA_TIMER1_BASE + TIMERx_VALUE) 78#define TIMER_1_CTRL (IFPGA_TIMER1_BASE + TIMERx_CTRL) 79 80#define TIMER_2_CLEAR (IFPGA_TIMER2_BASE + TIMERx_CLR) 81#define TIMER_2_LOAD (IFPGA_TIMER2_BASE + TIMERx_LOAD) 82#define TIMER_2_VALUE (IFPGA_TIMER2_BASE + TIMERx_VALUE) 83#define TIMER_2_CTRL (IFPGA_TIMER2_BASE + TIMERx_CTRL) 84 85#define COUNTS_PER_SEC (IFPGA_TIMER1_FREQ / 16) 86 87static u_int ifpga_get_timecount(struct timecounter *); 88 89static struct timecounter ifpga_timecounter = { 90 .tc_get_timecount = ifpga_get_timecount, 91 .tc_counter_mask = 0xffffffff, 92 .tc_frequency = COUNTS_PER_SEC, 93 .tc_name = "ifpga", 94 .tc_quality = 100, 95}; 96 97static volatile uint32_t ifpga_base; 98 99extern struct ifpga_softc *ifpga_sc; 100extern device_t ifpga_dev; 101 102static int clock_started = 0; 103 104static int load_timer(int, int); 105 106static inline u_int 107getclock(void) 108{ 109 return bus_space_read_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 110 TIMER_1_VALUE); 111} 112 113static inline u_int 114getstatclock(void) 115{ 116 return bus_space_read_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 117 TIMER_2_VALUE); 118} 119 120/* 121 * int clockhandler(struct clockframe *frame) 122 * 123 * Function called by timer 1 interrupts. 124 * This just clears the interrupt condition and calls hardclock(). 125 */ 126 127static int 128clockhandler(void *fr) 129{ 130 struct clockframe *frame = (struct clockframe *)fr; 131 132 bus_space_write_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 133 TIMER_1_CLEAR, 0); 134 135 atomic_add_32(&ifpga_base, ifpga_sc->sc_clock_count); 136 137 hardclock(frame); 138 return 0; /* Pass the interrupt on down the chain */ 139} 140 141 142/* 143 * int statclockhandler(struct clockframe *frame) 144 * 145 * Function called by timer 2 interrupts. 146 * Add some random jitter to the clock, and then call statclock(). 147 */ 148 149static int 150statclockhandler(void *fr) 151{ 152 struct clockframe *frame = (struct clockframe *) fr; 153 int newint, r, var; 154 155 var = statvar; 156 do { 157 r = random() & (var - 1); 158 } while (r == 0); 159 newint = timer2min + r; 160 161 if (newint & ~0x0000ffff) 162 panic("statclockhandler: statclock variance too large"); 163 164 /* 165 * The timer was automatically reloaded with the previous latch 166 * value at the time of the interrupts. Compensate now for the 167 * amount of time that has run off since then, plus one tick 168 * roundoff. This should keep us closer to the mean. 169 */ 170 171 r = (statprev - getstatclock() + 1); 172 if (r < newint) { 173 newint -= r; 174 r = 0; 175 } 176 else 177 printf("statclockhandler: Statclock overrun\n"); 178 179 statprev = load_timer(IFPGA_TIMER2_BASE, newint); 180 statclock(frame); 181 if (r) 182 /* 183 * We've completely overrun the previous interval, 184 * make sure we report the correct number of ticks. 185 */ 186 statclock(frame); 187 188 return 0; /* Pass the interrupt on down the chain */ 189} 190 191static int 192load_timer(int base, int intvl) 193{ 194 int control; 195 196 if (intvl & ~0x0000ffff) 197 panic("clock: Invalid interval"); 198 199#if defined(INTEGRATOR_CP) 200 control = (TIMERx_CTRL_ENABLE | TIMERx_CTRL_MODE_PERIODIC | 201 TIMERx_CTRL_PRESCALE_DIV16 | TIMERx_CTRL_RAISE_IRQ); 202#else 203 control = (TIMERx_CTRL_ENABLE | TIMERx_CTRL_MODE_PERIODIC | 204 TIMERx_CTRL_PRESCALE_DIV16); 205#endif 206 207 bus_space_write_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 208 base + TIMERx_LOAD, intvl); 209 bus_space_write_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 210 base + TIMERx_CTRL, control); 211 bus_space_write_4(ifpga_sc->sc_iot, ifpga_sc->sc_tmr_ioh, 212 base + TIMERx_CLR, 0); 213 return intvl; 214} 215 216/* 217 * void setstatclockrate(int hz) 218 * 219 * We assume that hz is either stathz or profhz, and that neither will 220 * change after being set by cpu_initclocks(). We could recalculate the 221 * intervals here, but that would be a pain. 222 */ 223 224void 225setstatclockrate(int new_hz) 226{ 227 if (new_hz == stathz) 228 timer2min = statmin; 229 else 230 timer2min = profmin; 231} 232 233/* 234 * void cpu_initclocks(void) 235 * 236 * Initialise the clocks. 237 */ 238 239void 240cpu_initclocks(void) 241{ 242 int intvl; 243 int statint; 244 int profint; 245 int minint; 246 247 if (hz < 50 || COUNTS_PER_SEC % hz) { 248 printf("cannot get %d Hz clock; using 100 Hz\n", hz); 249 hz = 100; 250 tick = 1000000 / hz; 251 } 252 253 if (stathz == 0) 254 stathz = hz; 255 else if (stathz < 50 || COUNTS_PER_SEC % stathz) { 256 printf("cannot get %d Hz statclock; using 100 Hz\n", stathz); 257 stathz = 100; 258 } 259 260 if (profhz == 0) 261 profhz = stathz * 5; 262 else if (profhz < stathz || COUNTS_PER_SEC % profhz) { 263 printf("cannot get %d Hz profclock; using %d Hz\n", profhz, 264 stathz); 265 profhz = stathz; 266 } 267 268 intvl = COUNTS_PER_SEC / hz; 269 statint = COUNTS_PER_SEC / stathz; 270 profint = COUNTS_PER_SEC / profhz; 271 minint = statint / 2 + 100; 272 while (statvar > minint) 273 statvar >>= 1; 274 275 /* Adjust interval counts, per note above. */ 276 intvl--; 277 statint--; 278 profint--; 279 280 /* Calculate the base reload values. */ 281 statmin = statint - (statvar >> 1); 282 profmin = profint - (statvar >> 1); 283 timer2min = statmin; 284 statprev = statint; 285 286 /* Report the clock frequencies */ 287 printf("clock: hz=%d stathz = %d profhz = %d\n", hz, stathz, profhz); 288 289 /* Setup timer 1 and claim interrupt */ 290 ifpga_sc->sc_clockintr = ifpga_intr_establish(IFPGA_TIMER1_IRQ, 291 IPL_CLOCK, clockhandler, 0); 292 if (ifpga_sc->sc_clockintr == NULL) 293 panic("%s: Cannot install timer 1 interrupt handler", 294 device_xname(ifpga_dev)); 295 296 ifpga_sc->sc_clock_count 297 = load_timer(IFPGA_TIMER1_BASE, intvl); 298 299 /* 300 * Use ticks per 256us for accuracy since ticks per us is often 301 * fractional e.g. @ 66MHz 302 */ 303 ifpga_sc->sc_clock_ticks_per_256us = 304 ((((ifpga_sc->sc_clock_count * hz) / 1000) * 256) / 1000); 305 306 clock_started = 1; 307 308 /* Set up timer 2 as statclk/profclk. */ 309 ifpga_sc->sc_statclockintr = ifpga_intr_establish(IFPGA_TIMER2_IRQ, 310 IPL_HIGH, statclockhandler, 0); 311 if (ifpga_sc->sc_statclockintr == NULL) 312 panic("%s: Cannot install timer 2 interrupt handler", 313 device_xname(ifpga_dev)); 314 load_timer(IFPGA_TIMER2_BASE, statint); 315 316 tc_init(&ifpga_timecounter); 317} 318 319static u_int 320ifpga_get_timecount(struct timecounter *tc) 321{ 322 u_int base, counter; 323 324 do { 325 base = ifpga_base; 326 counter = getclock(); 327 } while (base != ifpga_base); 328 329 return base - counter; 330} 331 332/* 333 * Estimated loop for n microseconds 334 */ 335 336/* Need to re-write this to use the timers */ 337 338/* One day soon I will actually do this */ 339 340int delaycount = 50; 341 342void 343delay(u_int n) 344{ 345 if (clock_started) { 346 u_int starttime; 347 u_int curtime; 348 u_int delta = 0; 349 u_int count_max = ifpga_sc->sc_clock_count; 350 351 starttime = getclock(); 352 353 n *= IFPGA_TIMER1_FREQ / 1000000; 354 355 do { 356 n -= delta; 357 curtime = getclock(); 358 delta = curtime - starttime; 359 if (curtime < starttime) 360 delta += count_max; 361 starttime = curtime; 362 } while (n > delta); 363 } else { 364 volatile u_int i; 365 366 if (n == 0) return; 367 while (n-- > 0) { 368 /* XXX - Seriously gross hack */ 369 if (cputype == CPU_ID_SA110) 370 for (i = delaycount; --i;) 371 ; 372 else 373 for (i = 8; --i;) 374 ; 375 } 376 } 377} 378