1 /* $OpenBSD: amptimer.c,v 1.9 2020/07/14 15:34:14 patrick Exp $ */ 2 /* 3 * Copyright (c) 2011 Dale Rahn <drahn@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/queue.h> 21 #include <sys/malloc.h> 22 #include <sys/device.h> 23 #include <sys/kernel.h> 24 #include <sys/timetc.h> 25 #include <sys/evcount.h> 26 27 #include <arm/cpufunc.h> 28 #include <machine/bus.h> 29 #include <machine/intr.h> 30 #include <arm/cortex/cortex.h> 31 32 /* offset from periphbase */ 33 #define GTIMER_ADDR 0x200 34 #define GTIMER_SIZE 0x100 35 36 /* registers */ 37 #define GTIMER_CNT_LOW 0x00 38 #define GTIMER_CNT_HIGH 0x04 39 #define GTIMER_CTRL 0x08 40 #define GTIMER_CTRL_AA (1 << 3) 41 #define GTIMER_CTRL_IRQ (1 << 2) 42 #define GTIMER_CTRL_COMP (1 << 1) 43 #define GTIMER_CTRL_TIMER (1 << 0) 44 #define GTIMER_STATUS 0x0c 45 #define GTIMER_STATUS_EVENT (1 << 0) 46 #define GTIMER_CMP_LOW 0x10 47 #define GTIMER_CMP_HIGH 0x14 48 #define GTIMER_AUTOINC 0x18 49 50 /* offset from periphbase */ 51 #define PTIMER_ADDR 0x600 52 #define PTIMER_SIZE 0x100 53 54 /* registers */ 55 #define PTIMER_LOAD 0x0 56 #define PTIMER_CNT 0x4 57 #define PTIMER_CTRL 0x8 58 #define PTIMER_CTRL_ENABLE (1<<0) 59 #define PTIMER_CTRL_AUTORELOAD (1<<1) 60 #define PTIMER_CTRL_IRQEN (1<<2) 61 #define PTIMER_STATUS 0xC 62 #define PTIMER_STATUS_EVENT (1<<0) 63 64 #define TIMER_FREQUENCY 396 * 1000 * 1000 /* ARM core clock */ 65 int32_t amptimer_frequency = TIMER_FREQUENCY; 66 67 u_int amptimer_get_timecount(struct timecounter *); 68 69 static struct timecounter amptimer_timecounter = { 70 amptimer_get_timecount, NULL, 0xffffffff, 0, "amptimer", 0, NULL, 0 71 }; 72 73 #define MAX_ARM_CPUS 8 74 75 struct amptimer_pcpu_softc { 76 uint64_t pc_nexttickevent; 77 uint64_t pc_nextstatevent; 78 u_int32_t pc_ticks_err_sum; 79 }; 80 81 struct amptimer_softc { 82 struct device sc_dev; 83 bus_space_tag_t sc_iot; 84 bus_space_handle_t sc_ioh; 85 bus_space_handle_t sc_pioh; 86 87 struct amptimer_pcpu_softc sc_pstat[MAX_ARM_CPUS]; 88 89 u_int32_t sc_ticks_err_cnt; 90 u_int32_t sc_ticks_per_second; 91 u_int32_t sc_ticks_per_intr; 92 u_int32_t sc_statvar; 93 u_int32_t sc_statmin; 94 95 #ifdef AMPTIMER_DEBUG 96 struct evcount sc_clk_count; 97 struct evcount sc_stat_count; 98 #endif 99 }; 100 101 int amptimer_match(struct device *, void *, void *); 102 void amptimer_attach(struct device *, struct device *, void *); 103 uint64_t amptimer_readcnt64(struct amptimer_softc *sc); 104 int amptimer_intr(void *); 105 void amptimer_cpu_initclocks(void); 106 void amptimer_delay(u_int); 107 void amptimer_setstatclockrate(int stathz); 108 void amptimer_set_clockrate(int32_t new_frequency); 109 void amptimer_startclock(void); 110 111 /* hack - XXXX 112 * gptimer connects directly to ampintc, not thru the generic 113 * interface because it uses an 'internal' interrupt 114 * not a peripheral interrupt. 115 */ 116 void *ampintc_intr_establish(int, int, int, struct cpu_info *, 117 int (*)(void *), void *, char *); 118 119 120 121 struct cfattach amptimer_ca = { 122 sizeof (struct amptimer_softc), amptimer_match, amptimer_attach 123 }; 124 125 struct cfdriver amptimer_cd = { 126 NULL, "amptimer", DV_DULL 127 }; 128 129 uint64_t 130 amptimer_readcnt64(struct amptimer_softc *sc) 131 { 132 uint32_t high0, high1, low; 133 bus_space_tag_t iot = sc->sc_iot; 134 bus_space_handle_t ioh = sc->sc_ioh; 135 136 do { 137 high0 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 138 low = bus_space_read_4(iot, ioh, GTIMER_CNT_LOW); 139 high1 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 140 } while (high0 != high1); 141 142 return ((((uint64_t)high1) << 32) | low); 143 } 144 145 int 146 amptimer_match(struct device *parent, void *cfdata, void *aux) 147 { 148 if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9) 149 return (1); 150 151 return 0; 152 } 153 154 void 155 amptimer_attach(struct device *parent, struct device *self, void *args) 156 { 157 struct amptimer_softc *sc = (struct amptimer_softc *)self; 158 struct cortex_attach_args *ia = args; 159 bus_space_handle_t ioh, pioh; 160 161 sc->sc_iot = ia->ca_iot; 162 163 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR, 164 GTIMER_SIZE, 0, &ioh)) 165 panic("amptimer_attach: bus_space_map global timer failed!"); 166 167 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR, 168 PTIMER_SIZE, 0, &pioh)) 169 panic("amptimer_attach: bus_space_map priv timer failed!"); 170 171 sc->sc_ticks_per_second = amptimer_frequency; 172 printf(": tick rate %d KHz\n", sc->sc_ticks_per_second /1000); 173 174 sc->sc_ioh = ioh; 175 sc->sc_pioh = pioh; 176 177 /* disable global timer */ 178 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0); 179 180 /* XXX ??? reset counters to 0 - gives us uptime in the counter */ 181 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0); 182 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0); 183 184 /* enable global timer */ 185 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER); 186 187 #if defined(USE_GTIMER_CMP) 188 189 /* clear event */ 190 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_STATUS, 1); 191 #else 192 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0); 193 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 194 PTIMER_STATUS_EVENT); 195 #endif 196 197 198 #ifdef AMPTIMER_DEBUG 199 evcount_attach(&sc->sc_clk_count, "clock", NULL); 200 evcount_attach(&sc->sc_stat_count, "stat", NULL); 201 #endif 202 203 /* 204 * private timer and interrupts not enabled until 205 * timer configures 206 */ 207 208 arm_clock_register(amptimer_cpu_initclocks, amptimer_delay, 209 amptimer_setstatclockrate, amptimer_startclock); 210 211 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 212 amptimer_timecounter.tc_priv = sc; 213 214 tc_init(&timer_timecounter); 215 } 216 217 u_int 218 amptimer_get_timecount(struct timecounter *tc) 219 { 220 struct amptimer_softc *sc = amptimer_timecounter.tc_priv; 221 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 222 } 223 224 int 225 amptimer_intr(void *frame) 226 { 227 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 228 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 229 uint64_t now; 230 uint64_t nextevent; 231 uint32_t r, reg; 232 #if defined(USE_GTIMER_CMP) 233 int skip = 1; 234 #else 235 int64_t delay; 236 #endif 237 int rc = 0; 238 239 /* 240 * DSR - I know that the tick timer is 64 bits, but the following 241 * code deals with rollover, so there is no point in dealing 242 * with the 64 bit math, just let the 32 bit rollover 243 * do the right thing 244 */ 245 246 now = amptimer_readcnt64(sc); 247 248 while (pc->pc_nexttickevent <= now) { 249 pc->pc_nexttickevent += sc->sc_ticks_per_intr; 250 pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt; 251 252 /* looping a few times is faster than divide */ 253 while (pc->pc_ticks_err_sum > hz) { 254 pc->pc_nexttickevent += 1; 255 pc->pc_ticks_err_sum -= hz; 256 } 257 258 #ifdef AMPTIMER_DEBUG 259 sc->sc_clk_count.ec_count++; 260 #endif 261 rc = 1; 262 hardclock(frame); 263 } 264 while (pc->pc_nextstatevent <= now) { 265 do { 266 r = random() & (sc->sc_statvar -1); 267 } while (r == 0); /* random == 0 not allowed */ 268 pc->pc_nextstatevent += sc->sc_statmin + r; 269 270 /* XXX - correct nextstatevent? */ 271 #ifdef AMPTIMER_DEBUG 272 sc->sc_stat_count.ec_count++; 273 #endif 274 rc = 1; 275 statclock(frame); 276 } 277 278 if (pc->pc_nexttickevent < pc->pc_nextstatevent) 279 nextevent = pc->pc_nexttickevent; 280 else 281 nextevent = pc->pc_nextstatevent; 282 283 #if defined(USE_GTIMER_CMP) 284 again: 285 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL); 286 reg &= ~GTIMER_CTRL_COMP; 287 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 288 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW, 289 nextevent & 0xffffffff); 290 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH, 291 nextevent >> 32); 292 reg |= GTIMER_CTRL_COMP; 293 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 294 295 now = amptimer_readcnt64(sc); 296 if (now >= nextevent) { 297 nextevent = now + skip; 298 skip += 1; 299 goto again; 300 } 301 #else 302 /* clear old status */ 303 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 304 PTIMER_STATUS_EVENT); 305 306 delay = nextevent - now; 307 if (delay < 0) 308 delay = 1; 309 310 reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL); 311 if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) != 312 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) 313 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 314 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 315 316 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, delay); 317 #endif 318 319 return (rc); 320 } 321 322 void 323 amptimer_set_clockrate(int32_t new_frequency) 324 { 325 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 326 327 amptimer_frequency = new_frequency; 328 329 if (sc == NULL) 330 return; 331 332 sc->sc_ticks_per_second = amptimer_frequency; 333 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 334 printf("amptimer0: adjusting clock: new tick rate %d KHz\n", 335 sc->sc_ticks_per_second /1000); 336 } 337 338 void 339 amptimer_cpu_initclocks() 340 { 341 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 342 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 343 uint64_t next; 344 #if defined(USE_GTIMER_CMP) 345 uint32_t reg; 346 #endif 347 348 stathz = hz; 349 profhz = hz * 10; 350 351 if (sc->sc_ticks_per_second != amptimer_frequency) { 352 amptimer_set_clockrate(amptimer_frequency); 353 } 354 355 amptimer_setstatclockrate(stathz); 356 357 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 358 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 359 pc->pc_ticks_err_sum = 0; 360 361 /* establish interrupts */ 362 /* XXX - irq */ 363 #if defined(USE_GTIMER_CMP) 364 ampintc_intr_establish(27, IST_EDGE_RISING, IPL_CLOCK, 365 NULL, amptimer_intr, NULL, "tick"); 366 #else 367 ampintc_intr_establish(29, IST_EDGE_RISING, IPL_CLOCK, 368 NULL, amptimer_intr, NULL, "tick"); 369 #endif 370 371 next = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr; 372 pc->pc_nexttickevent = pc->pc_nextstatevent = next; 373 374 #if defined(USE_GTIMER_CMP) 375 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL); 376 reg &= ~GTIMER_CTRL_COMP; 377 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 378 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW, 379 next & 0xffffffff); 380 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH, 381 next >> 32); 382 reg |= GTIMER_CTRL_COMP | GTIMER_CTRL_IRQ; 383 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 384 #else 385 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 386 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 387 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 388 sc->sc_ticks_per_intr); 389 #endif 390 } 391 392 void 393 amptimer_delay(u_int usecs) 394 { 395 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 396 u_int32_t clock, oclock, delta, delaycnt; 397 volatile int j; 398 int csec, usec; 399 400 if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) { 401 csec = usecs / 10000; 402 usec = usecs % 10000; 403 404 delaycnt = (sc->sc_ticks_per_second / 100) * csec + 405 (sc->sc_ticks_per_second / 100) * usec / 10000; 406 } else { 407 delaycnt = sc->sc_ticks_per_second * usecs / 1000000; 408 } 409 if (delaycnt <= 1) 410 for (j = 100; j > 0; j--) 411 ; 412 413 oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 414 while (1) { 415 for (j = 100; j > 0; j--) 416 ; 417 clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 418 GTIMER_CNT_LOW); 419 delta = clock - oclock; 420 if (delta > delaycnt) 421 break; 422 } 423 } 424 425 void 426 amptimer_setstatclockrate(int newhz) 427 { 428 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 429 int minint, statint; 430 int s; 431 432 s = splclock(); 433 434 statint = sc->sc_ticks_per_second / newhz; 435 /* calculate largest 2^n which is smaller that just over half statint */ 436 sc->sc_statvar = 0x40000000; /* really big power of two */ 437 minint = statint / 2 + 100; 438 while (sc->sc_statvar > minint) 439 sc->sc_statvar >>= 1; 440 441 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 442 443 splx(s); 444 445 /* 446 * XXX this allows the next stat timer to occur then it switches 447 * to the new frequency. Rather than switching instantly. 448 */ 449 } 450 451 void 452 amptimer_startclock(void) 453 { 454 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 455 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 456 uint64_t nextevent; 457 458 nextevent = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr; 459 pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; 460 461 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 462 sc->sc_ticks_per_intr); 463 } 464