1 /* $OpenBSD: agtimer.c,v 1.12 2021/02/23 04:44:30 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/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 <arm/cpufunc.h> 33 #include <arm/cortex/cortex.h> 34 35 #include <dev/ofw/fdt.h> 36 #include <dev/ofw/openfirm.h> 37 38 /* registers */ 39 #define GTIMER_CNTP_CTL_ENABLE (1 << 0) 40 #define GTIMER_CNTP_CTL_IMASK (1 << 1) 41 #define GTIMER_CNTP_CTL_ISTATUS (1 << 2) 42 43 #define TIMER_FREQUENCY 24 * 1000 * 1000 /* ARM core clock */ 44 int32_t agtimer_frequency = TIMER_FREQUENCY; 45 46 u_int agtimer_get_timecount(struct timecounter *); 47 48 static struct timecounter agtimer_timecounter = { 49 .tc_get_timecount = agtimer_get_timecount, 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 }; 57 58 struct agtimer_pcpu_softc { 59 uint64_t pc_nexttickevent; 60 uint64_t pc_nextstatevent; 61 u_int32_t pc_ticks_err_sum; 62 }; 63 64 struct agtimer_softc { 65 struct device sc_dev; 66 int sc_node; 67 68 struct agtimer_pcpu_softc sc_pstat[MAXCPUS]; 69 70 u_int32_t sc_ticks_err_cnt; 71 u_int32_t sc_ticks_per_second; 72 u_int32_t sc_ticks_per_intr; 73 u_int32_t sc_statvar; 74 u_int32_t sc_statmin; 75 76 #ifdef AMPTIMER_DEBUG 77 struct evcount sc_clk_count; 78 struct evcount sc_stat_count; 79 #endif 80 }; 81 82 int agtimer_match(struct device *, void *, void *); 83 void agtimer_attach(struct device *, struct device *, void *); 84 uint64_t agtimer_readcnt64(void); 85 int agtimer_intr(void *); 86 void agtimer_cpu_initclocks(void); 87 void agtimer_delay(u_int); 88 void agtimer_setstatclockrate(int stathz); 89 void agtimer_set_clockrate(int32_t new_frequency); 90 void agtimer_startclock(void); 91 92 struct cfattach agtimer_ca = { 93 sizeof (struct agtimer_softc), agtimer_match, agtimer_attach 94 }; 95 96 struct cfdriver agtimer_cd = { 97 NULL, "agtimer", DV_DULL 98 }; 99 100 uint64_t 101 agtimer_readcnt64(void) 102 { 103 uint64_t val; 104 105 __asm volatile("mrrc p15, 0, %Q0, %R0, c14" : "=r" (val)); 106 107 return (val); 108 } 109 110 static inline int 111 agtimer_get_ctrl(void) 112 { 113 uint32_t val; 114 115 __asm volatile("mrc p15, 0, %0, c14, c2, 1" : "=r" (val)); 116 117 return (val); 118 } 119 120 static inline int 121 agtimer_set_ctrl(uint32_t val) 122 { 123 __asm volatile("mcr p15, 0, %[val], c14, c2, 1" : : 124 [val] "r" (val)); 125 126 cpu_drain_writebuf(); 127 //isb(); 128 129 return (0); 130 } 131 132 static inline int 133 agtimer_set_tval(uint32_t val) 134 { 135 __asm volatile("mcr p15, 0, %[val], c14, c2, 0" : : 136 [val] "r" (val)); 137 cpu_drain_writebuf(); 138 //isb(); 139 140 return (0); 141 } 142 143 int 144 agtimer_match(struct device *parent, void *cfdata, void *aux) 145 { 146 struct fdt_attach_args *faa = (struct fdt_attach_args *)aux; 147 148 return OF_is_compatible(faa->fa_node, "arm,armv7-timer"); 149 } 150 151 void 152 agtimer_attach(struct device *parent, struct device *self, void *aux) 153 { 154 struct agtimer_softc *sc = (struct agtimer_softc *)self; 155 struct fdt_attach_args *faa = aux; 156 157 sc->sc_node = faa->fa_node; 158 159 agtimer_frequency = 160 OF_getpropint(sc->sc_node, "clock-frequency", agtimer_frequency); 161 sc->sc_ticks_per_second = agtimer_frequency; 162 163 printf(": %d kHz\n", sc->sc_ticks_per_second / 1000); 164 165 /* XXX: disable user access */ 166 167 #ifdef AMPTIMER_DEBUG 168 evcount_attach(&sc->sc_clk_count, "clock", NULL); 169 evcount_attach(&sc->sc_stat_count, "stat", NULL); 170 #endif 171 172 /* 173 * private timer and interrupts not enabled until 174 * timer configures 175 */ 176 177 arm_clock_register(agtimer_cpu_initclocks, agtimer_delay, 178 agtimer_setstatclockrate, agtimer_startclock); 179 180 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 181 agtimer_timecounter.tc_priv = sc; 182 183 tc_init(&agtimer_timecounter); 184 } 185 186 u_int 187 agtimer_get_timecount(struct timecounter *tc) 188 { 189 return agtimer_readcnt64(); 190 } 191 192 int 193 agtimer_intr(void *frame) 194 { 195 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 196 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 197 uint64_t now; 198 uint64_t nextevent; 199 uint32_t r; 200 #if defined(USE_GTIMER_CMP) 201 int skip = 1; 202 #else 203 int64_t delay; 204 #endif 205 int rc = 0; 206 207 /* 208 * DSR - I know that the tick timer is 64 bits, but the following 209 * code deals with rollover, so there is no point in dealing 210 * with the 64 bit math, just let the 32 bit rollover 211 * do the right thing 212 */ 213 214 now = agtimer_readcnt64(); 215 216 while (pc->pc_nexttickevent <= now) { 217 pc->pc_nexttickevent += sc->sc_ticks_per_intr; 218 pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt; 219 220 /* looping a few times is faster than divide */ 221 while (pc->pc_ticks_err_sum > hz) { 222 pc->pc_nexttickevent += 1; 223 pc->pc_ticks_err_sum -= hz; 224 } 225 226 #ifdef AMPTIMER_DEBUG 227 sc->sc_clk_count.ec_count++; 228 #endif 229 rc = 1; 230 hardclock(frame); 231 } 232 while (pc->pc_nextstatevent <= now) { 233 do { 234 r = random() & (sc->sc_statvar -1); 235 } while (r == 0); /* random == 0 not allowed */ 236 pc->pc_nextstatevent += sc->sc_statmin + r; 237 238 /* XXX - correct nextstatevent? */ 239 #ifdef AMPTIMER_DEBUG 240 sc->sc_stat_count.ec_count++; 241 #endif 242 rc = 1; 243 statclock(frame); 244 } 245 246 if (pc->pc_nexttickevent < pc->pc_nextstatevent) 247 nextevent = pc->pc_nexttickevent; 248 else 249 nextevent = pc->pc_nextstatevent; 250 251 delay = nextevent - now; 252 if (delay < 0) 253 delay = 1; 254 255 agtimer_set_tval(delay); 256 257 return (rc); 258 } 259 260 void 261 agtimer_set_clockrate(int32_t new_frequency) 262 { 263 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 264 265 agtimer_frequency = new_frequency; 266 267 if (sc == NULL) 268 return; 269 270 sc->sc_ticks_per_second = agtimer_frequency; 271 agtimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 272 printf("agtimer0: adjusting clock: new rate %d kHz\n", 273 sc->sc_ticks_per_second / 1000); 274 } 275 276 void 277 agtimer_cpu_initclocks() 278 { 279 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 280 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 281 uint32_t reg; 282 uint64_t next; 283 284 stathz = hz; 285 profhz = hz * 10; 286 287 if (sc->sc_ticks_per_second != agtimer_frequency) { 288 agtimer_set_clockrate(agtimer_frequency); 289 } 290 291 agtimer_setstatclockrate(stathz); 292 293 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 294 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 295 pc->pc_ticks_err_sum = 0; 296 297 /* Setup secure and non-secure timer IRQs. */ 298 arm_intr_establish_fdt_idx(sc->sc_node, 0, IPL_CLOCK, 299 agtimer_intr, NULL, "tick"); 300 arm_intr_establish_fdt_idx(sc->sc_node, 1, IPL_CLOCK, 301 agtimer_intr, NULL, "tick"); 302 303 next = agtimer_readcnt64() + sc->sc_ticks_per_intr; 304 pc->pc_nexttickevent = pc->pc_nextstatevent = next; 305 306 reg = agtimer_get_ctrl(); 307 reg &= ~GTIMER_CNTP_CTL_IMASK; 308 reg |= GTIMER_CNTP_CTL_ENABLE; 309 agtimer_set_tval(sc->sc_ticks_per_second); 310 agtimer_set_ctrl(reg); 311 } 312 313 void 314 agtimer_delay(u_int usecs) 315 { 316 u_int32_t clock, oclock, delta, delaycnt; 317 volatile int j; 318 int csec, usec; 319 320 if (usecs > (0x80000000 / agtimer_frequency)) { 321 csec = usecs / 10000; 322 usec = usecs % 10000; 323 324 delaycnt = (agtimer_frequency / 100) * csec + 325 (agtimer_frequency / 100) * usec / 10000; 326 } else { 327 delaycnt = agtimer_frequency * usecs / 1000000; 328 } 329 if (delaycnt <= 1) 330 for (j = 100; j > 0; j--) 331 ; 332 333 oclock = agtimer_readcnt64(); 334 while (1) { 335 for (j = 100; j > 0; j--) 336 ; 337 clock = agtimer_readcnt64(); 338 delta = clock - oclock; 339 if (delta > delaycnt) 340 break; 341 } 342 } 343 344 void 345 agtimer_setstatclockrate(int newhz) 346 { 347 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 348 int minint, statint; 349 int s; 350 351 s = splclock(); 352 353 statint = sc->sc_ticks_per_second / newhz; 354 /* calculate largest 2^n which is smaller that just over half statint */ 355 sc->sc_statvar = 0x40000000; /* really big power of two */ 356 minint = statint / 2 + 100; 357 while (sc->sc_statvar > minint) 358 sc->sc_statvar >>= 1; 359 360 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 361 362 splx(s); 363 364 /* 365 * XXX this allows the next stat timer to occur then it switches 366 * to the new frequency. Rather than switching instantly. 367 */ 368 } 369 370 void 371 agtimer_startclock(void) 372 { 373 struct agtimer_softc *sc = agtimer_cd.cd_devs[0]; 374 struct agtimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 375 uint64_t nextevent; 376 uint32_t reg; 377 378 nextevent = agtimer_readcnt64() + sc->sc_ticks_per_intr; 379 pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; 380 381 reg = agtimer_get_ctrl(); 382 reg &= ~GTIMER_CNTP_CTL_IMASK; 383 reg |= GTIMER_CNTP_CTL_ENABLE; 384 agtimer_set_tval(sc->sc_ticks_per_second); 385 agtimer_set_ctrl(reg); 386 } 387 388 void 389 agtimer_init(void) 390 { 391 uint32_t id_pfr1, cntfrq = 0; 392 393 /* Check for Generic Timer support. */ 394 __asm volatile("mrc p15, 0, %0, c0, c1, 1" : "=r"(id_pfr1)); 395 if ((id_pfr1 & 0x000f0000) == 0x00010000) 396 __asm volatile("mrc p15, 0, %0, c14, c0, 0" : "=r" (cntfrq)); 397 398 if (cntfrq != 0) { 399 agtimer_frequency = cntfrq; 400 arm_clock_register(NULL, agtimer_delay, NULL, NULL); 401 } 402 } 403