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