1 /* $OpenBSD: gptimer.c,v 1.13 2021/03/25 04:12:01 jsg Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 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 /* 19 * WARNING - this timer initializion has not been checked 20 * to see if it will do _ANYTHING_ sane if the omap enters 21 * low power mode. 22 */ 23 24 #include <sys/param.h> 25 #include <sys/systm.h> 26 #include <sys/kernel.h> 27 #include <sys/evcount.h> 28 #include <sys/device.h> 29 #include <sys/timetc.h> 30 #include <machine/bus.h> 31 #include <armv7/armv7/armv7var.h> 32 #include <armv7/omap/prcmvar.h> 33 34 #include <machine/intr.h> 35 36 /* registers */ 37 #define GP_TIDR 0x000 38 #define GP_TIDR_REV 0xff 39 #define GP_TIOCP_CFG 0x010 40 #define GP_TIOCP_CFG_CLKA 0x000000300 41 #define GP_TIOCP_CFG_EMUFREE 0x000000020 42 #define GP_TIOCP_CFG_IDLEMODE 0x000000018 43 #define GP_TIOCP_CFG_ENAPWAKEUP 0x000000004 44 #define GP_TIOCP_CFG_SOFTRESET 0x000000002 45 #define GP_TIOCP_CFG_AUTOIDLE 0x000000001 46 #define GP_TISTAT 0x014 47 #define GP_TISTAT_RESETDONE 0x000000001 48 #define GP_TISR 0x018 49 #define GP_TISTAT_TCAR 0x00000004 50 #define GP_TISTAT_OVF 0x00000002 51 #define GP_TISTAT_MATCH 0x00000001 52 #define GP_TIER 0x1c 53 #define GP_TIER_TCAR_EN 0x4 54 #define GP_TIER_OVF_EN 0x2 55 #define GP_TIER_MAT_EN 0x1 56 #define GP_TWER 0x020 57 #define GP_TWER_TCAR_EN 0x00000004 58 #define GP_TWER_OVF_EN 0x00000002 59 #define GP_TWER_MAT_EN 0x00000001 60 #define GP_TCLR 0x024 61 #define GP_TCLR_GPO (1<<14) 62 #define GP_TCLR_CAPT (1<<13) 63 #define GP_TCLR_PT (1<<12) 64 #define GP_TCLR_TRG (3<<10) 65 #define GP_TCLR_TRG_O (1<<10) 66 #define GP_TCLR_TRG_OM (2<<10) 67 #define GP_TCLR_TCM (3<<8) 68 #define GP_TCLR_TCM_RISE (1<<8) 69 #define GP_TCLR_TCM_FALL (2<<8) 70 #define GP_TCLR_TCM_BOTH (3<<8) 71 #define GP_TCLR_SCPWM (1<<7) 72 #define GP_TCLR_CE (1<<6) 73 #define GP_TCLR_PRE (1<<5) 74 #define GP_TCLR_PTV (7<<2) 75 #define GP_TCLR_AR (1<<1) 76 #define GP_TCLR_ST (1<<0) 77 #define GP_TCRR 0x028 /* counter */ 78 #define GP_TLDR 0x02c /* reload */ 79 #define GP_TTGR 0x030 80 #define GP_TWPS 0x034 81 #define GP_TWPS_TCLR 0x01 82 #define GP_TWPS_TCRR 0x02 83 #define GP_TWPS_TLDR 0x04 84 #define GP_TWPS_TTGR 0x08 85 #define GP_TWPS_TMAR 0x10 86 #define GP_TWPS_ALL 0x1f 87 #define GP_TMAR 0x038 88 #define GP_TCAR 0x03C 89 #define GP_TSICR 0x040 90 #define GP_TSICR_POSTED 0x00000002 91 #define GP_TSICR_SFT 0x00000001 92 #define GP_TCAR2 0x044 93 94 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ 95 96 static struct evcount clk_count; 97 static struct evcount stat_count; 98 99 void gptimer_attach(struct device *parent, struct device *self, void *args); 100 int gptimer_intr(void *frame); 101 void gptimer_wait(int reg); 102 void gptimer_cpu_initclocks(void); 103 void gptimer_delay(u_int); 104 void gptimer_setstatclockrate(int newhz); 105 106 bus_space_tag_t gptimer_iot; 107 bus_space_handle_t gptimer_ioh0, gptimer_ioh1; 108 int gptimer_irq = 0; 109 110 u_int gptimer_get_timecount(struct timecounter *); 111 112 static struct timecounter gptimer_timecounter = { 113 .tc_get_timecount = gptimer_get_timecount, 114 .tc_poll_pps = NULL, 115 .tc_counter_mask = 0xffffffff, 116 .tc_frequency = 0, 117 .tc_name = "gptimer", 118 .tc_quality = 0, 119 .tc_priv = NULL, 120 .tc_user = 0, 121 }; 122 123 volatile u_int32_t nexttickevent; 124 volatile u_int32_t nextstatevent; 125 u_int32_t ticks_per_second; 126 u_int32_t ticks_per_intr; 127 u_int32_t ticks_err_cnt; 128 u_int32_t ticks_err_sum; 129 u_int32_t statvar, statmin; 130 131 struct cfattach gptimer_ca = { 132 sizeof (struct device), NULL, gptimer_attach 133 }; 134 135 struct cfdriver gptimer_cd = { 136 NULL, "gptimer", DV_DULL 137 }; 138 139 void 140 gptimer_attach(struct device *parent, struct device *self, void *args) 141 { 142 struct armv7_attach_args *aa = args; 143 bus_space_handle_t ioh; 144 u_int32_t rev; 145 146 gptimer_iot = aa->aa_iot; 147 if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr, 148 aa->aa_dev->mem[0].size, 0, &ioh)) 149 panic("gptimer_attach: bus_space_map failed!"); 150 151 rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR); 152 153 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); 154 if (self->dv_unit == 0) { 155 gptimer_ioh0 = ioh; 156 gptimer_irq = aa->aa_dev->irq[0]; 157 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0); 158 } else if (self->dv_unit == 1) { 159 /* start timer because it is used in delay */ 160 gptimer_ioh1 = ioh; 161 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0); 162 gptimer_wait(GP_TWPS_ALL); 163 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0); 164 gptimer_wait(GP_TWPS_ALL); 165 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR, 166 GP_TCLR_AR | GP_TCLR_ST); 167 gptimer_wait(GP_TWPS_ALL); 168 169 gptimer_timecounter.tc_frequency = TIMER_FREQUENCY; 170 tc_init(&gptimer_timecounter); 171 } 172 else 173 panic("attaching too many gptimers at 0x%lx", 174 aa->aa_dev->mem[0].addr); 175 176 arm_clock_register(gptimer_cpu_initclocks, gptimer_delay, 177 gptimer_setstatclockrate, NULL); 178 } 179 180 /* 181 * See comment in arm/xscale/i80321_clock.c 182 * 183 * counter is count up, but with autoreload timers it is not possible 184 * to detect how many interrupts passed while interrupts were blocked. 185 * also it is not possible to atomically add to the register 186 * get get it to precisely fire at a non-fixed interval. 187 * 188 * To work around this two timers are used, GPT1 is used as a reference 189 * clock without reload , however we just ignore the interrupt it 190 * would (may?) generate. 191 * 192 * Internally this keeps track of when the next timer should fire 193 * and based on that time and the current value of the reference 194 * clock a number is written into the timer count register to schedule 195 * the next event. 196 */ 197 198 int 199 gptimer_intr(void *frame) 200 { 201 u_int32_t now, r; 202 u_int32_t nextevent, duration; 203 204 /* clear interrupt */ 205 now = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 206 207 while ((int32_t) (nexttickevent - now) < 0) { 208 nexttickevent += ticks_per_intr; 209 ticks_err_sum += ticks_err_cnt; 210 #if 0 211 if (ticks_err_sum > hz) { 212 u_int32_t match_error; 213 match_error = ticks_err_sum / hz 214 ticks_err_sum -= (match_error * hz); 215 } 216 #else 217 /* looping a few times is faster than divide */ 218 while (ticks_err_sum > hz) { 219 nexttickevent += 1; 220 ticks_err_sum -= hz; 221 } 222 #endif 223 clk_count.ec_count++; 224 hardclock(frame); 225 } 226 while ((int32_t) (nextstatevent - now) < 0) { 227 do { 228 r = random() & (statvar -1); 229 } while (r == 0); /* random == 0 not allowed */ 230 nextstatevent += statmin + r; 231 /* XXX - correct nextstatevent? */ 232 stat_count.ec_count++; 233 statclock(frame); 234 } 235 if ((nexttickevent - now) < (nextstatevent - now)) 236 nextevent = nexttickevent; 237 else 238 nextevent = nextstatevent; 239 240 /* XXX */ 241 duration = nextevent - 242 bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 243 #if 0 244 printf("duration 0x%x %x %x\n", nextevent - 245 bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR), 246 bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TCRR), 247 bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR)); 248 #endif 249 250 251 if (duration <= 0) 252 duration = 1; /* trigger immediately. */ 253 254 if (duration > ticks_per_intr) { 255 /* 256 * If interrupts are blocked too long, like during 257 * the root prompt or ddb, the timer can roll over, 258 * this will allow the system to continue to run 259 * even if time is lost. 260 */ 261 duration = ticks_per_intr; 262 nexttickevent = now; 263 nextstatevent = now; 264 } 265 266 gptimer_wait(GP_TWPS_ALL); 267 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, 268 bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR)); 269 gptimer_wait(GP_TWPS_ALL); 270 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -duration); 271 272 return 1; 273 } 274 275 /* 276 * would be interesting to play with trigger mode while having one timer 277 * in 32kHz mode, and the other timer running in sysclk mode and use 278 * the high resolution speeds (matters more for delay than tick timer 279 */ 280 281 void 282 gptimer_cpu_initclocks() 283 { 284 stathz = 128; 285 profhz = 1024; 286 287 ticks_per_second = TIMER_FREQUENCY; 288 289 setstatclockrate(stathz); 290 291 ticks_per_intr = ticks_per_second / hz; 292 ticks_err_cnt = ticks_per_second % hz; 293 ticks_err_sum = 0; 294 295 prcm_setclock(1, PRCM_CLK_SPEED_32); 296 prcm_setclock(2, PRCM_CLK_SPEED_32); 297 /* establish interrupts */ 298 arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr, 299 NULL, "tick"); 300 301 /* setup timer 0 (hardware timer 2) */ 302 /* reset? - XXX */ 303 304 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0); 305 306 nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot, 307 gptimer_ioh1, GP_TCRR) + ticks_per_intr; 308 309 gptimer_wait(GP_TWPS_ALL); 310 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN); 311 gptimer_wait(GP_TWPS_ALL); 312 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN); 313 gptimer_wait(GP_TWPS_ALL); 314 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 315 GP_TCLR_AR | GP_TCLR_ST); 316 gptimer_wait(GP_TWPS_ALL); 317 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, 318 bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR)); 319 gptimer_wait(GP_TWPS_ALL); 320 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr); 321 gptimer_wait(GP_TWPS_ALL); 322 } 323 324 void 325 gptimer_wait(int reg) 326 { 327 while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg) 328 ; 329 } 330 331 #if 0 332 void 333 microtime(struct timeval *tvp) 334 { 335 int s; 336 int deltacnt; 337 u_int32_t counter, expected; 338 s = splhigh(); 339 340 if (1) { /* not inited */ 341 tvp->tv_sec = 0; 342 tvp->tv_usec = 0; 343 return; 344 } 345 s = splhigh(); 346 counter = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 347 expected = nexttickevent; 348 349 *tvp = time; 350 splx(s); 351 352 deltacnt = counter - expected + ticks_per_intr; 353 354 #if 1 355 /* low frequency timer algorithm */ 356 tvp->tv_usec += deltacnt * 1000000ULL / TIMER_FREQUENCY; 357 #else 358 /* high frequency timer algorithm - XXX */ 359 tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL); 360 #endif 361 362 while (tvp->tv_usec >= 1000000) { 363 tvp->tv_sec++; 364 tvp->tv_usec -= 1000000; 365 } 366 367 } 368 #endif 369 370 void 371 gptimer_delay(u_int usecs) 372 { 373 u_int32_t clock, oclock, delta, delaycnt; 374 volatile int j; 375 int csec, usec; 376 377 if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { 378 csec = usecs / 10000; 379 usec = usecs % 10000; 380 381 delaycnt = (TIMER_FREQUENCY / 100) * csec + 382 (TIMER_FREQUENCY / 100) * usec / 10000; 383 } else { 384 delaycnt = TIMER_FREQUENCY * usecs / 1000000; 385 } 386 if (delaycnt <= 1) 387 for (j = 100; j > 0; j--) 388 ; 389 390 if (gptimer_ioh1 == 0) { 391 /* BAH */ 392 for (; usecs > 0; usecs--) 393 for (j = 100; j > 0; j--) 394 ; 395 return; 396 } 397 oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 398 while (1) { 399 for (j = 100; j > 0; j--) 400 ; 401 clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 402 delta = clock - oclock; 403 if (delta > delaycnt) 404 break; 405 } 406 407 } 408 409 void 410 gptimer_setstatclockrate(int newhz) 411 { 412 int minint, statint; 413 int s; 414 415 s = splclock(); 416 417 statint = ticks_per_second / newhz; 418 /* calculate largest 2^n which is smaller that just over half statint */ 419 statvar = 0x40000000; /* really big power of two */ 420 minint = statint / 2 + 100; 421 while (statvar > minint) 422 statvar >>= 1; 423 424 statmin = statint - (statvar >> 1); 425 426 splx(s); 427 428 /* 429 * XXX this allows the next stat timer to occur then it switches 430 * to the new frequency. Rather than switching instantly. 431 */ 432 } 433 434 435 u_int 436 gptimer_get_timecount(struct timecounter *tc) 437 { 438 return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 439 } 440