1 /* $OpenBSD: amptimer.c,v 1.11 2021/02/23 04:44:30 cheloha 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 .tc_get_timecount = amptimer_get_timecount, 71 .tc_poll_pps = NULL, 72 .tc_counter_mask = 0xffffffff, 73 .tc_frequency = 0, 74 .tc_name = "amptimer", 75 .tc_quality = 0, 76 .tc_priv = NULL, 77 .tc_user = 0, 78 }; 79 80 #define MAX_ARM_CPUS 8 81 82 struct amptimer_pcpu_softc { 83 uint64_t pc_nexttickevent; 84 uint64_t pc_nextstatevent; 85 u_int32_t pc_ticks_err_sum; 86 }; 87 88 struct amptimer_softc { 89 struct device sc_dev; 90 bus_space_tag_t sc_iot; 91 bus_space_handle_t sc_ioh; 92 bus_space_handle_t sc_pioh; 93 94 struct amptimer_pcpu_softc sc_pstat[MAX_ARM_CPUS]; 95 96 u_int32_t sc_ticks_err_cnt; 97 u_int32_t sc_ticks_per_second; 98 u_int32_t sc_ticks_per_intr; 99 u_int32_t sc_statvar; 100 u_int32_t sc_statmin; 101 102 #ifdef AMPTIMER_DEBUG 103 struct evcount sc_clk_count; 104 struct evcount sc_stat_count; 105 #endif 106 }; 107 108 int amptimer_match(struct device *, void *, void *); 109 void amptimer_attach(struct device *, struct device *, void *); 110 uint64_t amptimer_readcnt64(struct amptimer_softc *sc); 111 int amptimer_intr(void *); 112 void amptimer_cpu_initclocks(void); 113 void amptimer_delay(u_int); 114 void amptimer_setstatclockrate(int stathz); 115 void amptimer_set_clockrate(int32_t new_frequency); 116 void amptimer_startclock(void); 117 118 /* hack - XXXX 119 * gptimer connects directly to ampintc, not thru the generic 120 * interface because it uses an 'internal' interrupt 121 * not a peripheral interrupt. 122 */ 123 void *ampintc_intr_establish(int, int, int, struct cpu_info *, 124 int (*)(void *), void *, char *); 125 126 127 128 struct cfattach amptimer_ca = { 129 sizeof (struct amptimer_softc), amptimer_match, amptimer_attach 130 }; 131 132 struct cfdriver amptimer_cd = { 133 NULL, "amptimer", DV_DULL 134 }; 135 136 uint64_t 137 amptimer_readcnt64(struct amptimer_softc *sc) 138 { 139 uint32_t high0, high1, low; 140 bus_space_tag_t iot = sc->sc_iot; 141 bus_space_handle_t ioh = sc->sc_ioh; 142 143 do { 144 high0 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 145 low = bus_space_read_4(iot, ioh, GTIMER_CNT_LOW); 146 high1 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 147 } while (high0 != high1); 148 149 return ((((uint64_t)high1) << 32) | low); 150 } 151 152 int 153 amptimer_match(struct device *parent, void *cfdata, void *aux) 154 { 155 if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9) 156 return (1); 157 158 return 0; 159 } 160 161 void 162 amptimer_attach(struct device *parent, struct device *self, void *args) 163 { 164 struct amptimer_softc *sc = (struct amptimer_softc *)self; 165 struct cortex_attach_args *ia = args; 166 bus_space_handle_t ioh, pioh; 167 168 sc->sc_iot = ia->ca_iot; 169 170 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR, 171 GTIMER_SIZE, 0, &ioh)) 172 panic("amptimer_attach: bus_space_map global timer failed!"); 173 174 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR, 175 PTIMER_SIZE, 0, &pioh)) 176 panic("amptimer_attach: bus_space_map priv timer failed!"); 177 178 sc->sc_ticks_per_second = amptimer_frequency; 179 printf(": %d kHz\n", sc->sc_ticks_per_second / 1000); 180 181 sc->sc_ioh = ioh; 182 sc->sc_pioh = pioh; 183 184 /* disable global timer */ 185 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0); 186 187 /* XXX ??? reset counters to 0 - gives us uptime in the counter */ 188 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0); 189 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0); 190 191 /* enable global timer */ 192 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER); 193 194 #if defined(USE_GTIMER_CMP) 195 196 /* clear event */ 197 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_STATUS, 1); 198 #else 199 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0); 200 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 201 PTIMER_STATUS_EVENT); 202 #endif 203 204 205 #ifdef AMPTIMER_DEBUG 206 evcount_attach(&sc->sc_clk_count, "clock", NULL); 207 evcount_attach(&sc->sc_stat_count, "stat", NULL); 208 #endif 209 210 /* 211 * private timer and interrupts not enabled until 212 * timer configures 213 */ 214 215 arm_clock_register(amptimer_cpu_initclocks, amptimer_delay, 216 amptimer_setstatclockrate, amptimer_startclock); 217 218 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 219 amptimer_timecounter.tc_priv = sc; 220 221 tc_init(&timer_timecounter); 222 } 223 224 u_int 225 amptimer_get_timecount(struct timecounter *tc) 226 { 227 struct amptimer_softc *sc = amptimer_timecounter.tc_priv; 228 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 229 } 230 231 int 232 amptimer_intr(void *frame) 233 { 234 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 235 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 236 uint64_t now; 237 uint64_t nextevent; 238 uint32_t r, reg; 239 #if defined(USE_GTIMER_CMP) 240 int skip = 1; 241 #else 242 int64_t delay; 243 #endif 244 int rc = 0; 245 246 /* 247 * DSR - I know that the tick timer is 64 bits, but the following 248 * code deals with rollover, so there is no point in dealing 249 * with the 64 bit math, just let the 32 bit rollover 250 * do the right thing 251 */ 252 253 now = amptimer_readcnt64(sc); 254 255 while (pc->pc_nexttickevent <= now) { 256 pc->pc_nexttickevent += sc->sc_ticks_per_intr; 257 pc->pc_ticks_err_sum += sc->sc_ticks_err_cnt; 258 259 /* looping a few times is faster than divide */ 260 while (pc->pc_ticks_err_sum > hz) { 261 pc->pc_nexttickevent += 1; 262 pc->pc_ticks_err_sum -= hz; 263 } 264 265 #ifdef AMPTIMER_DEBUG 266 sc->sc_clk_count.ec_count++; 267 #endif 268 rc = 1; 269 hardclock(frame); 270 } 271 while (pc->pc_nextstatevent <= now) { 272 do { 273 r = random() & (sc->sc_statvar -1); 274 } while (r == 0); /* random == 0 not allowed */ 275 pc->pc_nextstatevent += sc->sc_statmin + r; 276 277 /* XXX - correct nextstatevent? */ 278 #ifdef AMPTIMER_DEBUG 279 sc->sc_stat_count.ec_count++; 280 #endif 281 rc = 1; 282 statclock(frame); 283 } 284 285 if (pc->pc_nexttickevent < pc->pc_nextstatevent) 286 nextevent = pc->pc_nexttickevent; 287 else 288 nextevent = pc->pc_nextstatevent; 289 290 #if defined(USE_GTIMER_CMP) 291 again: 292 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL); 293 reg &= ~GTIMER_CTRL_COMP; 294 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 295 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW, 296 nextevent & 0xffffffff); 297 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH, 298 nextevent >> 32); 299 reg |= GTIMER_CTRL_COMP; 300 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 301 302 now = amptimer_readcnt64(sc); 303 if (now >= nextevent) { 304 nextevent = now + skip; 305 skip += 1; 306 goto again; 307 } 308 #else 309 /* clear old status */ 310 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 311 PTIMER_STATUS_EVENT); 312 313 delay = nextevent - now; 314 if (delay < 0) 315 delay = 1; 316 317 reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL); 318 if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) != 319 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) 320 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 321 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 322 323 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, delay); 324 #endif 325 326 return (rc); 327 } 328 329 void 330 amptimer_set_clockrate(int32_t new_frequency) 331 { 332 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 333 334 amptimer_frequency = new_frequency; 335 336 if (sc == NULL) 337 return; 338 339 sc->sc_ticks_per_second = amptimer_frequency; 340 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 341 printf("amptimer0: adjusting clock: new rate %d kHz\n", 342 sc->sc_ticks_per_second / 1000); 343 } 344 345 void 346 amptimer_cpu_initclocks() 347 { 348 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 349 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 350 uint64_t next; 351 #if defined(USE_GTIMER_CMP) 352 uint32_t reg; 353 #endif 354 355 stathz = hz; 356 profhz = hz * 10; 357 358 if (sc->sc_ticks_per_second != amptimer_frequency) { 359 amptimer_set_clockrate(amptimer_frequency); 360 } 361 362 amptimer_setstatclockrate(stathz); 363 364 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 365 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 366 pc->pc_ticks_err_sum = 0; 367 368 /* establish interrupts */ 369 /* XXX - irq */ 370 #if defined(USE_GTIMER_CMP) 371 ampintc_intr_establish(27, IST_EDGE_RISING, IPL_CLOCK, 372 NULL, amptimer_intr, NULL, "tick"); 373 #else 374 ampintc_intr_establish(29, IST_EDGE_RISING, IPL_CLOCK, 375 NULL, amptimer_intr, NULL, "tick"); 376 #endif 377 378 next = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr; 379 pc->pc_nexttickevent = pc->pc_nextstatevent = next; 380 381 #if defined(USE_GTIMER_CMP) 382 reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL); 383 reg &= ~GTIMER_CTRL_COMP; 384 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 385 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_LOW, 386 next & 0xffffffff); 387 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CMP_HIGH, 388 next >> 32); 389 reg |= GTIMER_CTRL_COMP | GTIMER_CTRL_IRQ; 390 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GTIMER_CTRL, reg); 391 #else 392 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 393 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 394 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 395 sc->sc_ticks_per_intr); 396 #endif 397 } 398 399 void 400 amptimer_delay(u_int usecs) 401 { 402 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 403 u_int32_t clock, oclock, delta, delaycnt; 404 volatile int j; 405 int csec, usec; 406 407 if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) { 408 csec = usecs / 10000; 409 usec = usecs % 10000; 410 411 delaycnt = (sc->sc_ticks_per_second / 100) * csec + 412 (sc->sc_ticks_per_second / 100) * usec / 10000; 413 } else { 414 delaycnt = sc->sc_ticks_per_second * usecs / 1000000; 415 } 416 if (delaycnt <= 1) 417 for (j = 100; j > 0; j--) 418 ; 419 420 oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 421 while (1) { 422 for (j = 100; j > 0; j--) 423 ; 424 clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 425 GTIMER_CNT_LOW); 426 delta = clock - oclock; 427 if (delta > delaycnt) 428 break; 429 } 430 } 431 432 void 433 amptimer_setstatclockrate(int newhz) 434 { 435 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 436 int minint, statint; 437 int s; 438 439 s = splclock(); 440 441 statint = sc->sc_ticks_per_second / newhz; 442 /* calculate largest 2^n which is smaller that just over half statint */ 443 sc->sc_statvar = 0x40000000; /* really big power of two */ 444 minint = statint / 2 + 100; 445 while (sc->sc_statvar > minint) 446 sc->sc_statvar >>= 1; 447 448 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 449 450 splx(s); 451 452 /* 453 * XXX this allows the next stat timer to occur then it switches 454 * to the new frequency. Rather than switching instantly. 455 */ 456 } 457 458 void 459 amptimer_startclock(void) 460 { 461 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 462 struct amptimer_pcpu_softc *pc = &sc->sc_pstat[CPU_INFO_UNIT(curcpu())]; 463 uint64_t nextevent; 464 465 nextevent = amptimer_readcnt64(sc) + sc->sc_ticks_per_intr; 466 pc->pc_nexttickevent = pc->pc_nextstatevent = nextevent; 467 468 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 469 sc->sc_ticks_per_intr); 470 } 471