1 /* $OpenBSD: gptimer.c,v 1.9 2020/07/12 20:36:37 naddy 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/time.h> 28 #include <sys/evcount.h> 29 #include <sys/device.h> 30 #include <sys/timetc.h> 31 #include <dev/clock_subr.h> 32 #include <machine/bus.h> 33 #include <armv7/armv7/armv7var.h> 34 #include <armv7/omap/prcmvar.h> 35 36 #include <machine/intr.h> 37 #include <arm/cpufunc.h> 38 39 /* registers */ 40 #define GP_TIDR 0x000 41 #define GP_TIDR_REV 0xff 42 #define GP_TIOCP_CFG 0x010 43 #define GP_TIOCP_CFG_CLKA 0x000000300 44 #define GP_TIOCP_CFG_EMUFREE 0x000000020 45 #define GP_TIOCP_CFG_IDLEMODE 0x000000018 46 #define GP_TIOCP_CFG_ENAPWAKEUP 0x000000004 47 #define GP_TIOCP_CFG_SOFTRESET 0x000000002 48 #define GP_TIOCP_CFG_AUTOIDLE 0x000000001 49 #define GP_TISTAT 0x014 50 #define GP_TISTAT_RESETDONE 0x000000001 51 #define GP_TISR 0x018 52 #define GP_TISTAT_TCAR 0x00000004 53 #define GP_TISTAT_OVF 0x00000002 54 #define GP_TISTAT_MATCH 0x00000001 55 #define GP_TIER 0x1c 56 #define GP_TIER_TCAR_EN 0x4 57 #define GP_TIER_OVF_EN 0x2 58 #define GP_TIER_MAT_EN 0x1 59 #define GP_TWER 0x020 60 #define GP_TWER_TCAR_EN 0x00000004 61 #define GP_TWER_OVF_EN 0x00000002 62 #define GP_TWER_MAT_EN 0x00000001 63 #define GP_TCLR 0x024 64 #define GP_TCLR_GPO (1<<14) 65 #define GP_TCLR_CAPT (1<<13) 66 #define GP_TCLR_PT (1<<12) 67 #define GP_TCLR_TRG (3<<10) 68 #define GP_TCLR_TRG_O (1<<10) 69 #define GP_TCLR_TRG_OM (2<<10) 70 #define GP_TCLR_TCM (3<<8) 71 #define GP_TCLR_TCM_RISE (1<<8) 72 #define GP_TCLR_TCM_FALL (2<<8) 73 #define GP_TCLR_TCM_BOTH (3<<8) 74 #define GP_TCLR_SCPWM (1<<7) 75 #define GP_TCLR_CE (1<<6) 76 #define GP_TCLR_PRE (1<<5) 77 #define GP_TCLR_PTV (7<<2) 78 #define GP_TCLR_AR (1<<1) 79 #define GP_TCLR_ST (1<<0) 80 #define GP_TCRR 0x028 /* counter */ 81 #define GP_TLDR 0x02c /* reload */ 82 #define GP_TTGR 0x030 83 #define GP_TWPS 0x034 84 #define GP_TWPS_TCLR 0x01 85 #define GP_TWPS_TCRR 0x02 86 #define GP_TWPS_TLDR 0x04 87 #define GP_TWPS_TTGR 0x08 88 #define GP_TWPS_TMAR 0x10 89 #define GP_TWPS_ALL 0x1f 90 #define GP_TMAR 0x038 91 #define GP_TCAR 0x03C 92 #define GP_TSICR 0x040 93 #define GP_TSICR_POSTED 0x00000002 94 #define GP_TSICR_SFT 0x00000001 95 #define GP_TCAR2 0x044 96 97 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ 98 99 static struct evcount clk_count; 100 static struct evcount stat_count; 101 #define GPT1_IRQ 38 102 #define GPTIMER0_IRQ 38 103 104 //static int clk_irq = GPT1_IRQ; /* XXX 37 */ 105 106 void gptimer_attach(struct device *parent, struct device *self, void *args); 107 int gptimer_intr(void *frame); 108 void gptimer_wait(int reg); 109 void gptimer_cpu_initclocks(void); 110 void gptimer_delay(u_int); 111 void gptimer_setstatclockrate(int newhz); 112 113 bus_space_tag_t gptimer_iot; 114 bus_space_handle_t gptimer_ioh0, gptimer_ioh1; 115 int gptimer_irq = 0; 116 117 u_int gptimer_get_timecount(struct timecounter *); 118 119 static struct timecounter gptimer_timecounter = { 120 gptimer_get_timecount, NULL, 0xffffffff, 0, "gptimer", 0, NULL, 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 // u_int32_t now; 285 stathz = 128; 286 profhz = 1024; 287 288 ticks_per_second = TIMER_FREQUENCY; 289 290 setstatclockrate(stathz); 291 292 ticks_per_intr = ticks_per_second / hz; 293 ticks_err_cnt = ticks_per_second % hz; 294 ticks_err_sum = 0; 295 296 prcm_setclock(1, PRCM_CLK_SPEED_32); 297 prcm_setclock(2, PRCM_CLK_SPEED_32); 298 /* establish interrupts */ 299 arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr, 300 NULL, "tick"); 301 302 /* setup timer 0 (hardware timer 2) */ 303 /* reset? - XXX */ 304 305 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0); 306 307 nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot, 308 gptimer_ioh1, GP_TCRR) + ticks_per_intr; 309 310 gptimer_wait(GP_TWPS_ALL); 311 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN); 312 gptimer_wait(GP_TWPS_ALL); 313 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN); 314 gptimer_wait(GP_TWPS_ALL); 315 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 316 GP_TCLR_AR | GP_TCLR_ST); 317 gptimer_wait(GP_TWPS_ALL); 318 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, 319 bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR)); 320 gptimer_wait(GP_TWPS_ALL); 321 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr); 322 gptimer_wait(GP_TWPS_ALL); 323 } 324 325 void 326 gptimer_wait(int reg) 327 { 328 while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg) 329 ; 330 } 331 332 #if 0 333 void 334 microtime(struct timeval *tvp) 335 { 336 int s; 337 int deltacnt; 338 u_int32_t counter, expected; 339 s = splhigh(); 340 341 if (1) { /* not inited */ 342 tvp->tv_sec = 0; 343 tvp->tv_usec = 0; 344 return; 345 } 346 s = splhigh(); 347 counter = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 348 expected = nexttickevent; 349 350 *tvp = time; 351 splx(s); 352 353 deltacnt = counter - expected + ticks_per_intr; 354 355 #if 1 356 /* low frequency timer algorithm */ 357 tvp->tv_usec += deltacnt * 1000000ULL / TIMER_FREQUENCY; 358 #else 359 /* high frequency timer algorithm - XXX */ 360 tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL); 361 #endif 362 363 while (tvp->tv_usec >= 1000000) { 364 tvp->tv_sec++; 365 tvp->tv_usec -= 1000000; 366 } 367 368 } 369 #endif 370 371 void 372 gptimer_delay(u_int usecs) 373 { 374 u_int32_t clock, oclock, delta, delaycnt; 375 volatile int j; 376 int csec, usec; 377 378 if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { 379 csec = usecs / 10000; 380 usec = usecs % 10000; 381 382 delaycnt = (TIMER_FREQUENCY / 100) * csec + 383 (TIMER_FREQUENCY / 100) * usec / 10000; 384 } else { 385 delaycnt = TIMER_FREQUENCY * usecs / 1000000; 386 } 387 if (delaycnt <= 1) 388 for (j = 100; j > 0; j--) 389 ; 390 391 if (gptimer_ioh1 == 0) { 392 /* BAH */ 393 for (; usecs > 0; usecs--) 394 for (j = 100; j > 0; j--) 395 ; 396 return; 397 } 398 oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 399 while (1) { 400 for (j = 100; j > 0; j--) 401 ; 402 clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 403 delta = clock - oclock; 404 if (delta > delaycnt) 405 break; 406 } 407 408 } 409 410 void 411 gptimer_setstatclockrate(int newhz) 412 { 413 int minint, statint; 414 int s; 415 416 s = splclock(); 417 418 statint = ticks_per_second / newhz; 419 /* calculate largest 2^n which is smaller that just over half statint */ 420 statvar = 0x40000000; /* really big power of two */ 421 minint = statint / 2 + 100; 422 while (statvar > minint) 423 statvar >>= 1; 424 425 statmin = statint - (statvar >> 1); 426 427 splx(s); 428 429 /* 430 * XXX this allows the next stat timer to occur then it switches 431 * to the new frequency. Rather than switching instantly. 432 */ 433 } 434 435 436 u_int 437 gptimer_get_timecount(struct timecounter *tc) 438 { 439 return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 440 } 441