1 /* $OpenBSD: agtimer.c,v 1.21 2023/01/09 15:22:53 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/clockintr.h> 22 #include <sys/queue.h> 23 #include <sys/malloc.h> 24 #include <sys/device.h> 25 #include <sys/kernel.h> 26 #include <sys/stdint.h> 27 #include <sys/timetc.h> 28 #include <sys/evcount.h> 29 30 #include <machine/intr.h> 31 #include <machine/bus.h> 32 #include <machine/fdt.h> 33 34 #include <dev/ofw/fdt.h> 35 #include <dev/ofw/openfirm.h> 36 37 /* registers */ 38 #define GTIMER_CNTV_CTL_ENABLE (1 << 0) 39 #define GTIMER_CNTV_CTL_IMASK (1 << 1) 40 #define GTIMER_CNTV_CTL_ISTATUS (1 << 2) 41 42 #define TIMER_FREQUENCY 24 * 1000 * 1000 /* ARM core clock */ 43 int32_t agtimer_frequency = TIMER_FREQUENCY; 44 45 u_int agtimer_get_timecount_default(struct timecounter *); 46 u_int agtimer_get_timecount_sun50i(struct timecounter *); 47 48 static struct timecounter agtimer_timecounter = { 49 .tc_get_timecount = agtimer_get_timecount_default, 50 .tc_poll_pps = NULL, 51 .tc_counter_mask = 0xffffffff, 52 .tc_frequency = 0, 53 .tc_name = "agtimer", 54 .tc_quality = 0, 55 .tc_priv = NULL, 56 .tc_user = TC_AGTIMER, 57 }; 58 59 struct agtimer_softc { 60 struct device sc_dev; 61 int sc_node; 62 63 u_int32_t sc_ticks_per_second; 64 uint64_t sc_nsec_cycle_ratio; 65 uint64_t sc_nsec_max; 66 void *sc_ih; 67 }; 68 69 int agtimer_match(struct device *, void *, void *); 70 void agtimer_attach(struct device *, struct device *, void *); 71 int agtimer_intr(void *); 72 void agtimer_cpu_initclocks(void); 73 void agtimer_delay(u_int); 74 void agtimer_rearm(void *, uint64_t); 75 void agtimer_setstatclockrate(int stathz); 76 void agtimer_set_clockrate(int32_t new_frequency); 77 void agtimer_startclock(void); 78 void agtimer_trigger(void *); 79 80 const struct cfattach agtimer_ca = { 81 sizeof (struct agtimer_softc), agtimer_match, agtimer_attach 82 }; 83 84 struct cfdriver agtimer_cd = { 85 NULL, "agtimer", DV_DULL 86 }; 87 88 struct intrclock agtimer_intrclock = { 89 .ic_rearm = agtimer_rearm, 90 .ic_trigger = agtimer_trigger 91 }; 92 93 uint64_t 94 agtimer_readcnt64_default(void) 95 { 96 uint64_t val0, val1; 97 98 /* 99 * Work around Cortex-A73 errata 858921, where there is a 100 * one-cycle window where the read might return the old value 101 * for the low 32 bits and the new value for the high 32 bits 102 * upon roll-over of the low 32 bits. 103 */ 104 __asm volatile("isb" ::: "memory"); 105 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val0)); 106 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val1)); 107 return ((val0 ^ val1) & 0x100000000ULL) ? val0 : val1; 108 } 109 110 uint64_t 111 agtimer_readcnt64_sun50i(void) 112 { 113 uint64_t val; 114 int retry; 115 116 __asm volatile("isb" ::: "memory"); 117 for (retry = 0; retry < 150; retry++) { 118 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val)); 119 120 if (((val + 1) & 0x1ff) > 1) 121 break; 122 } 123 KASSERT(retry < 150); 124 125 return val; 126 } 127 128 uint64_t (*agtimer_readcnt64)(void) = agtimer_readcnt64_default; 129 130 static inline uint64_t 131 agtimer_get_freq(void) 132 { 133 uint64_t val; 134 135 __asm volatile("mrs %x0, CNTFRQ_EL0" : "=r" (val)); 136 137 return (val); 138 } 139 140 static inline int 141 agtimer_get_ctrl(void) 142 { 143 uint32_t val; 144 145 __asm volatile("mrs %x0, CNTV_CTL_EL0" : "=r" (val)); 146 147 return (val); 148 } 149 150 static inline int 151 agtimer_set_ctrl(uint32_t val) 152 { 153 __asm volatile("msr CNTV_CTL_EL0, %x0" :: "r" (val)); 154 __asm volatile("isb" ::: "memory"); 155 156 return (0); 157 } 158 159 static inline int 160 agtimer_set_tval(uint32_t val) 161 { 162 __asm volatile("msr CNTV_TVAL_EL0, %x0" :: "r" (val)); 163 __asm volatile("isb" ::: "memory"); 164 165 return (0); 166 } 167 168 int 169 agtimer_match(struct device *parent, void *cfdata, void *aux) 170 { 171 struct fdt_attach_args *faa = (struct fdt_attach_args *)aux; 172 173 return (OF_is_compatible(faa->fa_node, "arm,armv7-timer") || 174 OF_is_compatible(faa->fa_node, "arm,armv8-timer")); 175 } 176 177 void 178 agtimer_attach(struct device *parent, struct device *self, void *aux) 179 { 180 struct agtimer_softc *sc = (struct agtimer_softc *)self; 181 struct fdt_attach_args *faa = aux; 182 183 sc->sc_node = faa->fa_node; 184 185 if (agtimer_get_freq() != 0) 186 agtimer_frequency = agtimer_get_freq(); 187 agtimer_frequency = 188 OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency); 189 sc->sc_ticks_per_second = agtimer_frequency; 190 sc->sc_nsec_cycle_ratio = 191 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 192 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 193 194 printf(": %u kHz\n", sc->sc_ticks_per_second / 1000); 195 196 /* 197 * The Allwinner A64 has an erratum where the bottom 9 bits of 198 * the counter register can't be trusted if any of the higher 199 * bits are rolling over. 200 */ 201 if (OF_getpropbool(sc->sc_node, "allwinner,erratum-unknown1")) { 202 agtimer_readcnt64 = agtimer_readcnt64_sun50i; 203 agtimer_timecounter.tc_get_timecount = 204 agtimer_get_timecount_sun50i; 205 agtimer_timecounter.tc_user = TC_AGTIMER_SUN50I; 206 } 207 208 /* 209 * private timer and interrupts not enabled until 210 * timer configures 211 */ 212 213 arm_clock_register(agtimer_cpu_initclocks, agtimer_delay, 214 agtimer_setstatclockrate, agtimer_startclock); 215 216 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 217 agtimer_timecounter.tc_priv = sc; 218 tc_init(&agtimer_timecounter); 219 220 agtimer_intrclock.ic_cookie = sc; 221 } 222 223 u_int 224 agtimer_get_timecount_default(struct timecounter *tc) 225 { 226 uint64_t val; 227 228 /* 229 * No need to work around Cortex-A73 errata 858921 since we 230 * only look at the low 32 bits here. 231 */ 232 __asm volatile("isb" ::: "memory"); 233 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val)); 234 return (val & 0xffffffff); 235 } 236 237 u_int 238 agtimer_get_timecount_sun50i(struct timecounter *tc) 239 { 240 return agtimer_readcnt64_sun50i(); 241 } 242 243 void 244 agtimer_rearm(void *cookie, uint64_t nsecs) 245 { 246 struct agtimer_softc *sc = cookie; 247 uint32_t cycles; 248 249 if (nsecs > sc->sc_nsec_max) 250 nsecs = sc->sc_nsec_max; 251 cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32; 252 if (cycles > INT32_MAX) 253 cycles = INT32_MAX; 254 agtimer_set_tval(cycles); 255 } 256 257 void 258 agtimer_trigger(void *unused) 259 { 260 agtimer_set_tval(0); 261 } 262 263 int 264 agtimer_intr(void *frame) 265 { 266 return clockintr_dispatch(frame); 267 } 268 269 void 270 agtimer_set_clockrate(int32_t new_frequency) 271 { 272 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 273 274 agtimer_frequency = new_frequency; 275 276 if (sc == NULL) 277 return; 278 279 sc->sc_ticks_per_second = agtimer_frequency; 280 sc->sc_nsec_cycle_ratio = 281 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 282 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 283 284 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 285 286 printf("agtimer0: adjusting clock: new tick rate %u kHz\n", 287 sc->sc_ticks_per_second / 1000); 288 } 289 290 void 291 agtimer_cpu_initclocks(void) 292 { 293 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 294 uint32_t reg; 295 uint64_t kctl; 296 297 stathz = hz; 298 profhz = stathz * 10; 299 clockintr_init(CL_RNDSTAT); 300 301 if (sc->sc_ticks_per_second != agtimer_frequency) { 302 agtimer_set_clockrate(agtimer_frequency); 303 } 304 305 /* configure virtual timer interrupt */ 306 sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2, 307 IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick"); 308 309 clockintr_cpu_init(&agtimer_intrclock); 310 311 reg = agtimer_get_ctrl(); 312 reg &= ~GTIMER_CNTV_CTL_IMASK; 313 reg |= GTIMER_CNTV_CTL_ENABLE; 314 agtimer_set_tval(INT32_MAX); 315 agtimer_set_ctrl(reg); 316 317 clockintr_trigger(); 318 319 /* enable userland access to virtual counter */ 320 kctl = READ_SPECIALREG(CNTKCTL_EL1); 321 WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN); 322 } 323 324 void 325 agtimer_delay(u_int usecs) 326 { 327 uint64_t clock, oclock, delta, delaycnt; 328 uint64_t csec, usec; 329 volatile int j; 330 331 if (usecs > (0x80000000 / agtimer_frequency)) { 332 csec = usecs / 10000; 333 usec = usecs % 10000; 334 335 delaycnt = (agtimer_frequency / 100) * csec + 336 (agtimer_frequency / 100) * usec / 10000; 337 } else { 338 delaycnt = agtimer_frequency * usecs / 1000000; 339 } 340 if (delaycnt <= 1) 341 for (j = 100; j > 0; j--) 342 ; 343 344 oclock = agtimer_readcnt64(); 345 while (1) { 346 for (j = 100; j > 0; j--) 347 ; 348 clock = agtimer_readcnt64(); 349 delta = clock - oclock; 350 if (delta > delaycnt) 351 break; 352 } 353 } 354 355 void 356 agtimer_setstatclockrate(int newhz) 357 { 358 clockintr_setstatclockrate(newhz); 359 } 360 361 void 362 agtimer_startclock(void) 363 { 364 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 365 uint64_t kctl; 366 uint32_t reg; 367 368 arm_intr_route(sc->sc_ih, 1, curcpu()); 369 370 clockintr_cpu_init(&agtimer_intrclock); 371 372 reg = agtimer_get_ctrl(); 373 reg &= ~GTIMER_CNTV_CTL_IMASK; 374 reg |= GTIMER_CNTV_CTL_ENABLE; 375 agtimer_set_tval(INT32_MAX); 376 agtimer_set_ctrl(reg); 377 378 clockintr_trigger(); 379 380 /* enable userland access to virtual counter */ 381 kctl = READ_SPECIALREG(CNTKCTL_EL1); 382 WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN); 383 } 384 385 void 386 agtimer_init(void) 387 { 388 uint64_t cntfrq = 0; 389 390 /* XXX: Check for Generic Timer support. */ 391 cntfrq = agtimer_get_freq(); 392 393 if (cntfrq != 0) { 394 agtimer_frequency = cntfrq; 395 arm_clock_register(NULL, agtimer_delay, NULL, NULL); 396 } 397 } 398