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