1 /* $OpenBSD: agtimer.c,v 1.11 2019/10/05 11:27:02 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/queue.h> 22 #include <sys/malloc.h> 23 #include <sys/device.h> 24 #include <sys/kernel.h> 25 #include <sys/timetc.h> 26 #include <sys/evcount.h> 27 28 #include <machine/intr.h> 29 #include <machine/bus.h> 30 #include <machine/fdt.h> 31 32 #include <dev/ofw/fdt.h> 33 #include <dev/ofw/openfirm.h> 34 35 /* registers */ 36 #define GTIMER_CNTV_CTL_ENABLE (1 << 0) 37 #define GTIMER_CNTV_CTL_IMASK (1 << 1) 38 #define GTIMER_CNTV_CTL_ISTATUS (1 << 2) 39 40 #define TIMER_FREQUENCY 24 * 1000 * 1000 /* ARM core clock */ 41 int32_t agtimer_frequency = TIMER_FREQUENCY; 42 43 u_int agtimer_get_timecount(struct timecounter *); 44 45 static struct timecounter agtimer_timecounter = { 46 agtimer_get_timecount, NULL, 0x7fffffff, 0, "agtimer", 0, NULL 47 }; 48 49 struct agtimer_pcpu_softc { 50 uint64_t pc_nexttickevent; 51 uint64_t pc_nextstatevent; 52 u_int32_t pc_ticks_err_sum; 53 }; 54 55 struct agtimer_softc { 56 struct device sc_dev; 57 int sc_node; 58 59 struct agtimer_pcpu_softc sc_pstat[MAXCPUS]; 60 61 u_int32_t sc_ticks_err_cnt; 62 u_int32_t sc_ticks_per_second; 63 u_int32_t sc_ticks_per_intr; 64 u_int32_t sc_statvar; 65 u_int32_t sc_statmin; 66 67 #ifdef AMPTIMER_DEBUG 68 struct evcount sc_clk_count; 69 struct evcount sc_stat_count; 70 #endif 71 void *sc_ih; 72 }; 73 74 int agtimer_match(struct device *, void *, void *); 75 void agtimer_attach(struct device *, struct device *, void *); 76 uint64_t agtimer_readcnt64(void); 77 int agtimer_intr(void *); 78 void agtimer_cpu_initclocks(void); 79 void agtimer_delay(u_int); 80 void agtimer_setstatclockrate(int stathz); 81 void agtimer_set_clockrate(int32_t new_frequency); 82 void agtimer_startclock(void); 83 84 struct cfattach agtimer_ca = { 85 sizeof (struct agtimer_softc), agtimer_match, agtimer_attach 86 }; 87 88 struct cfdriver agtimer_cd = { 89 NULL, "agtimer", DV_DULL 90 }; 91 92 uint64_t 93 agtimer_readcnt64(void) 94 { 95 uint64_t val0, val1; 96 97 /* 98 * Work around Cortex-A73 errata 858921, where there is a 99 * one-cycle window where the read might return the old value 100 * for the low 32 bits and the new value for the high 32 bits 101 * upon roll-over of the low 32 bits. 102 */ 103 __asm volatile("isb" : : : "memory"); 104 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val0)); 105 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val1)); 106 return ((val0 ^ val1) & 0x100000000ULL) ? val0 : val1; 107 } 108 109 static inline uint64_t 110 agtimer_get_freq(void) 111 { 112 uint64_t val; 113 114 __asm volatile("mrs %x0, CNTFRQ_EL0" : "=r" (val)); 115 116 return (val); 117 } 118 119 static inline int 120 agtimer_get_ctrl(void) 121 { 122 uint32_t val; 123 124 __asm volatile("mrs %x0, CNTV_CTL_EL0" : "=r" (val)); 125 126 return (val); 127 } 128 129 static inline int 130 agtimer_set_ctrl(uint32_t val) 131 { 132 __asm volatile("msr CNTV_CTL_EL0, %x0" : : "r" (val)); 133 __asm volatile("isb" : : : "memory"); 134 135 return (0); 136 } 137 138 static inline int 139 agtimer_set_tval(uint32_t val) 140 { 141 __asm volatile("msr CNTV_TVAL_EL0, %x0" : : "r" (val)); 142 __asm volatile("isb" : : : "memory"); 143 144 return (0); 145 } 146 147 int 148 agtimer_match(struct device *parent, void *cfdata, void *aux) 149 { 150 struct fdt_attach_args *faa = (struct fdt_attach_args *)aux; 151 152 return (OF_is_compatible(faa->fa_node, "arm,armv7-timer") || 153 OF_is_compatible(faa->fa_node, "arm,armv8-timer")); 154 } 155 156 void 157 agtimer_attach(struct device *parent, struct device *self, void *aux) 158 { 159 struct agtimer_softc *sc = (struct agtimer_softc *)self; 160 struct fdt_attach_args *faa = aux; 161 162 sc->sc_node = faa->fa_node; 163 164 if (agtimer_get_freq() != 0) 165 agtimer_frequency = agtimer_get_freq(); 166 agtimer_frequency = 167 OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency); 168 sc->sc_ticks_per_second = agtimer_frequency; 169 170 printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000); 171 172 /* XXX: disable user access */ 173 174 #ifdef AMPTIMER_DEBUG 175 evcount_attach(&sc->sc_clk_count, "clock", NULL); 176 evcount_attach(&sc->sc_stat_count, "stat", NULL); 177 #endif 178 179 /* 180 * private timer and interrupts not enabled until 181 * timer configures 182 */ 183 184 arm_clock_register(agtimer_cpu_initclocks, agtimer_delay, 185 agtimer_setstatclockrate, agtimer_startclock); 186 187 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 188 agtimer_timecounter.tc_priv = sc; 189 190 tc_init(&agtimer_timecounter); 191 } 192 193 u_int 194 agtimer_get_timecount(struct timecounter *tc) 195 { 196 return agtimer_readcnt64(); 197 } 198 199 int 200 agtimer_intr(void *frame) 201 { 202 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 203 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 204 uint64_t now; 205 uint64_t nextevent; 206 uint32_t r; 207 #if defined(USE_GTIMER_CMP) 208 int skip = 1; 209 #else 210 int64_t delay; 211 #endif 212 int rc = 0; 213 214 /* 215 * DSR - I know that the tick timer is 64 bits, but the following 216 * code deals with rollover, so there is no point in dealing 217 * with the 64 bit math, just let the 32 bit rollover 218 * do the right thing 219 */ 220 221 now = agtimer_readcnt64(); 222 223 while (pc->pc_nexttickevent <= now) { 224 pc->pc_nexttickevent += sc->sc_ticks_per_intr; 225 pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt; 226 227 /* looping a few times is faster than divide */ 228 while (pc->pc_ticks_err_sum > hz) { 229 pc->pc_nexttickevent += 1; 230 pc->pc_ticks_err_sum -= hz; 231 } 232 233 #ifdef AMPTIMER_DEBUG 234 sc->sc_clk_count.ec_count++; 235 #endif 236 rc = 1; 237 hardclock(frame); 238 } 239 while (pc->pc_nextstatevent <= now) { 240 do { 241 r = random() & (sc->sc_statvar -1); 242 } while (r == 0); /* random == 0 not allowed */ 243 pc->pc_nextstatevent += sc->sc_statmin + r; 244 245 /* XXX - correct nextstatevent? */ 246 #ifdef AMPTIMER_DEBUG 247 sc->sc_stat_count.ec_count++; 248 #endif 249 rc = 1; 250 statclock(frame); 251 } 252 253 if (pc->pc_nexttickevent < pc->pc_nextstatevent) 254 nextevent = pc->pc_nexttickevent; 255 else 256 nextevent = pc->pc_nextstatevent; 257 258 delay = nextevent - now; 259 if (delay < 0) 260 delay = 1; 261 262 agtimer_set_tval(delay); 263 264 return (rc); 265 } 266 267 void 268 agtimer_set_clockrate(int32_t new_frequency) 269 { 270 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 271 272 agtimer_frequency = new_frequency; 273 274 if (sc == NULL) 275 return; 276 277 sc->sc_ticks_per_second = agtimer_frequency; 278 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 279 printf("agtimer0: adjusting clock: new tick rate %d KHz\n", 280 sc->sc_ticks_per_second /1000); 281 } 282 283 void 284 agtimer_cpu_initclocks() 285 { 286 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 287 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 288 uint32_t reg; 289 uint64_t next; 290 291 stathz = hz; 292 profhz = hz * 10; 293 294 if (sc->sc_ticks_per_second != agtimer_frequency) { 295 agtimer_set_clockrate(agtimer_frequency); 296 } 297 298 agtimer_setstatclockrate(stathz); 299 300 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 301 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 302 pc->pc_ticks_err_sum = 0; 303 304 /* configure virtual timer interupt */ 305 sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2, 306 IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick"); 307 308 next = agtimer_readcnt64() + sc->sc_ticks_per_intr; 309 pc->pc_nexttickevent = pc->pc_nextstatevent = next; 310 311 reg = agtimer_get_ctrl(); 312 reg &= ~GTIMER_CNTV_CTL_IMASK; 313 reg |= GTIMER_CNTV_CTL_ENABLE; 314 agtimer_set_tval(sc->sc_ticks_per_second); 315 agtimer_set_ctrl(reg); 316 } 317 318 void 319 agtimer_delay(u_int usecs) 320 { 321 uint64_t clock, oclock, delta, delaycnt; 322 uint64_t csec, usec; 323 volatile int j; 324 325 if (usecs > (0x80000000 / agtimer_frequency)) { 326 csec = usecs / 10000; 327 usec = usecs % 10000; 328 329 delaycnt = (agtimer_frequency / 100) * csec + 330 (agtimer_frequency / 100) * usec / 10000; 331 } else { 332 delaycnt = agtimer_frequency * usecs / 1000000; 333 } 334 if (delaycnt <= 1) 335 for (j = 100; j > 0; j--) 336 ; 337 338 oclock = agtimer_readcnt64(); 339 while (1) { 340 for (j = 100; j > 0; j--) 341 ; 342 clock = agtimer_readcnt64(); 343 delta = clock - oclock; 344 if (delta > delaycnt) 345 break; 346 } 347 } 348 349 void 350 agtimer_setstatclockrate(int newhz) 351 { 352 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 353 int minint, statint; 354 int s; 355 356 s = splclock(); 357 358 statint = sc->sc_ticks_per_second / newhz; 359 /* calculate largest 2^n which is smaller that just over half statint */ 360 sc->sc_statvar = 0x40000000; /* really big power of two */ 361 minint = statint / 2 + 100; 362 while (sc->sc_statvar > minint) 363 sc->sc_statvar >>= 1; 364 365 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 366 367 splx(s); 368 369 /* 370 * XXX this allows the next stat timer to occur then it switches 371 * to the new frequency. Rather than switching instantly. 372 */ 373 } 374 375 void 376 agtimer_startclock(void) 377 { 378 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 379 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 380 uint64_t nextevent; 381 uint32_t reg; 382 383 nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr; 384 pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; 385 386 arm_intr_route(sc->sc_ih, 1, curcpu()); 387 388 reg = agtimer_get_ctrl(); 389 reg &= ~GTIMER_CNTV_CTL_IMASK; 390 reg |= GTIMER_CNTV_CTL_ENABLE; 391 agtimer_set_tval(sc->sc_ticks_per_second); 392 agtimer_set_ctrl(reg); 393 } 394 395 void 396 agtimer_init(void) 397 { 398 uint64_t cntfrq = 0; 399 400 /* XXX: Check for Generic Timer support. */ 401 cntfrq = agtimer_get_freq(); 402 403 if (cntfrq != 0) { 404 agtimer_frequency = cntfrq; 405 arm_clock_register(NULL, agtimer_delay, NULL, NULL); 406 } 407 } 408