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