1 /* $OpenBSD: agtimer.c,v 1.28 2023/09/17 14:50:51 cheloha 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_counter_mask = 0xffffffff, 51 .tc_frequency = 0, 52 .tc_name = "agtimer", 53 .tc_quality = 0, 54 .tc_priv = NULL, 55 .tc_user = TC_AGTIMER, 56 }; 57 58 struct agtimer_softc { 59 struct device sc_dev; 60 int sc_node; 61 62 u_int32_t sc_ticks_per_second; 63 uint64_t sc_nsec_cycle_ratio; 64 uint64_t sc_nsec_max; 65 void *sc_ih; 66 }; 67 68 int agtimer_match(struct device *, void *, void *); 69 void agtimer_attach(struct device *, struct device *, void *); 70 int agtimer_intr(void *); 71 void agtimer_cpu_initclocks(void); 72 void agtimer_delay(u_int); 73 void agtimer_rearm(void *, uint64_t); 74 void agtimer_setstatclockrate(int stathz); 75 void agtimer_set_clockrate(int32_t new_frequency); 76 void agtimer_startclock(void); 77 void agtimer_trigger(void *); 78 79 const struct cfattach agtimer_ca = { 80 sizeof (struct agtimer_softc), agtimer_match, agtimer_attach 81 }; 82 83 struct cfdriver agtimer_cd = { 84 NULL, "agtimer", DV_DULL 85 }; 86 87 struct intrclock agtimer_intrclock = { 88 .ic_rearm = agtimer_rearm, 89 .ic_trigger = agtimer_trigger 90 }; 91 92 uint64_t 93 agtimer_readcnt64_default(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 uint64_t 110 agtimer_readcnt64_sun50i(void) 111 { 112 uint64_t val; 113 int retry; 114 115 __asm volatile("isb" ::: "memory"); 116 for (retry = 0; retry < 150; retry++) { 117 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val)); 118 119 if (((val + 1) & 0x1ff) > 1) 120 break; 121 } 122 KASSERT(retry < 150); 123 124 return val; 125 } 126 127 uint64_t (*agtimer_readcnt64)(void) = agtimer_readcnt64_default; 128 129 static inline uint64_t 130 agtimer_get_freq(void) 131 { 132 uint64_t val; 133 134 __asm volatile("mrs %x0, CNTFRQ_EL0" : "=r" (val)); 135 136 return (val); 137 } 138 139 static inline int 140 agtimer_get_ctrl(void) 141 { 142 uint32_t val; 143 144 __asm volatile("mrs %x0, CNTV_CTL_EL0" : "=r" (val)); 145 146 return (val); 147 } 148 149 static inline int 150 agtimer_set_ctrl(uint32_t val) 151 { 152 __asm volatile("msr CNTV_CTL_EL0, %x0" :: "r" (val)); 153 __asm volatile("isb" ::: "memory"); 154 155 return (0); 156 } 157 158 static inline int 159 agtimer_set_tval(uint32_t val) 160 { 161 __asm volatile("msr CNTV_TVAL_EL0, %x0" :: "r" (val)); 162 __asm volatile("isb" ::: "memory"); 163 164 return (0); 165 } 166 167 int 168 agtimer_match(struct device *parent, void *cfdata, void *aux) 169 { 170 struct fdt_attach_args *faa = (struct fdt_attach_args *)aux; 171 172 return (OF_is_compatible(faa->fa_node, "arm,armv7-timer") || 173 OF_is_compatible(faa->fa_node, "arm,armv8-timer")); 174 } 175 176 void 177 agtimer_attach(struct device *parent, struct device *self, void *aux) 178 { 179 struct agtimer_softc *sc = (struct agtimer_softc *)self; 180 struct fdt_attach_args *faa = aux; 181 182 sc->sc_node = faa->fa_node; 183 184 if (agtimer_get_freq() != 0) 185 agtimer_frequency = agtimer_get_freq(); 186 agtimer_frequency = 187 OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency); 188 sc->sc_ticks_per_second = agtimer_frequency; 189 sc->sc_nsec_cycle_ratio = 190 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 191 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 192 193 printf(": %u kHz\n", sc->sc_ticks_per_second / 1000); 194 195 /* 196 * The Allwinner A64 has an erratum where the bottom 9 bits of 197 * the counter register can't be trusted if any of the higher 198 * bits are rolling over. 199 */ 200 if (OF_getpropbool(sc->sc_node, "allwinner,erratum-unknown1")) { 201 agtimer_readcnt64 = agtimer_readcnt64_sun50i; 202 agtimer_timecounter.tc_get_timecount = 203 agtimer_get_timecount_sun50i; 204 agtimer_timecounter.tc_user = TC_AGTIMER_SUN50I; 205 } 206 207 /* 208 * private timer and interrupts not enabled until 209 * timer configures 210 */ 211 212 arm_clock_register(agtimer_cpu_initclocks, agtimer_delay, 213 agtimer_setstatclockrate, agtimer_startclock); 214 215 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 216 agtimer_timecounter.tc_priv = sc; 217 tc_init(&agtimer_timecounter); 218 219 agtimer_intrclock.ic_cookie = sc; 220 } 221 222 u_int 223 agtimer_get_timecount_default(struct timecounter *tc) 224 { 225 uint64_t val; 226 227 /* 228 * No need to work around Cortex-A73 errata 858921 since we 229 * only look at the low 32 bits here. 230 */ 231 __asm volatile("isb" ::: "memory"); 232 __asm volatile("mrs %x0, CNTVCT_EL0" : "=r" (val)); 233 return (val & 0xffffffff); 234 } 235 236 u_int 237 agtimer_get_timecount_sun50i(struct timecounter *tc) 238 { 239 return agtimer_readcnt64_sun50i(); 240 } 241 242 void 243 agtimer_rearm(void *cookie, uint64_t nsecs) 244 { 245 struct agtimer_softc *sc = cookie; 246 uint32_t cycles; 247 248 if (nsecs > sc->sc_nsec_max) 249 nsecs = sc->sc_nsec_max; 250 cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32; 251 if (cycles > INT32_MAX) 252 cycles = INT32_MAX; 253 agtimer_set_tval(cycles); 254 } 255 256 void 257 agtimer_trigger(void *unused) 258 { 259 agtimer_set_tval(0); 260 } 261 262 int 263 agtimer_intr(void *frame) 264 { 265 return clockintr_dispatch(frame); 266 } 267 268 void 269 agtimer_set_clockrate(int32_t new_frequency) 270 { 271 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 272 273 agtimer_frequency = new_frequency; 274 275 if (sc == NULL) 276 return; 277 278 sc->sc_ticks_per_second = agtimer_frequency; 279 sc->sc_nsec_cycle_ratio = 280 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 281 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 282 283 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 284 285 printf("agtimer0: adjusting clock: new tick rate %u kHz\n", 286 sc->sc_ticks_per_second / 1000); 287 } 288 289 void 290 agtimer_cpu_initclocks(void) 291 { 292 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 293 294 stathz = hz; 295 profhz = stathz * 10; 296 statclock_is_randomized = 1; 297 298 if (sc->sc_ticks_per_second != agtimer_frequency) { 299 agtimer_set_clockrate(agtimer_frequency); 300 } 301 302 /* configure virtual timer interrupt */ 303 sc->sc_ih = arm_intr_establish_fdt_idx(sc->sc_node, 2, 304 IPL_CLOCK|IPL_MPSAFE, agtimer_intr, NULL, "tick"); 305 } 306 307 void 308 agtimer_delay(u_int usecs) 309 { 310 uint64_t cycles, start; 311 312 start = agtimer_readcnt64(); 313 cycles = (uint64_t)usecs * agtimer_frequency / 1000000; 314 while (agtimer_readcnt64() - start < cycles) 315 CPU_BUSY_CYCLE(); 316 } 317 318 void 319 agtimer_setstatclockrate(int newhz) 320 { 321 } 322 323 void 324 agtimer_startclock(void) 325 { 326 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 327 uint64_t kctl; 328 uint32_t reg; 329 330 if (!CPU_IS_PRIMARY(curcpu())) 331 arm_intr_route(sc->sc_ih, 1, curcpu()); 332 333 clockintr_cpu_init(&agtimer_intrclock); 334 335 reg = agtimer_get_ctrl(); 336 reg &= ~GTIMER_CNTV_CTL_IMASK; 337 reg |= GTIMER_CNTV_CTL_ENABLE; 338 agtimer_set_tval(INT32_MAX); 339 agtimer_set_ctrl(reg); 340 341 clockintr_trigger(); 342 343 /* enable userland access to virtual counter */ 344 kctl = READ_SPECIALREG(CNTKCTL_EL1); 345 WRITE_SPECIALREG(CNTKCTL_EL1, kctl | CNTKCTL_EL0VCTEN); 346 } 347 348 void 349 agtimer_init(void) 350 { 351 uint64_t cntfrq = 0; 352 353 /* XXX: Check for Generic Timer support. */ 354 cntfrq = agtimer_get_freq(); 355 356 if (cntfrq != 0) { 357 agtimer_frequency = cntfrq; 358 arm_clock_register(NULL, agtimer_delay, NULL, NULL); 359 } 360 } 361