1 /* $OpenBSD: dmtimer.c,v 1.14 2021/10/24 17:52:27 mpi Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2013 Raphael Graf <r@undefined.ch> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * WARNING - this timer initializion has not been checked 21 * to see if it will do _ANYTHING_ sane if the omap enters 22 * low power mode. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/systm.h> 27 #include <sys/kernel.h> 28 #include <sys/evcount.h> 29 #include <sys/device.h> 30 #include <sys/timetc.h> 31 #include <machine/bus.h> 32 #include <armv7/armv7/armv7var.h> 33 #include <armv7/omap/prcmvar.h> 34 35 #include <machine/intr.h> 36 37 /* registers */ 38 #define DM_TIDR 0x000 39 #define DM_TIDR_MAJOR 0x00000700 40 #define DM_TIDR_MINOR 0x0000003f 41 #define DM_TIOCP_CFG 0x010 42 #define DM_TIOCP_CFG_IDLEMODE (3<<2) 43 #define DM_TIOCP_CFG_EMUFREE (1<<1) 44 #define DM_TIOCP_CFG_SOFTRESET (1<<0) 45 #define DM_TISR 0x028 46 #define DM_TISR_TCAR (1<<2) 47 #define DM_TISR_OVF (1<<1) 48 #define DM_TISR_MAT (1<<0) 49 #define DM_TIER 0x2c 50 #define DM_TIER_TCAR_EN (1<<2) 51 #define DM_TIER_OVF_EN (1<<1) 52 #define DM_TIER_MAT_EN (1<<0) 53 #define DM_TIECR 0x30 54 #define DM_TIECR_TCAR_EN (1<<2) 55 #define DM_TIECR_OVF_EN (1<<1) 56 #define DM_TIECR_MAT_EN (1<<0) 57 #define DM_TWER 0x034 58 #define DM_TWER_TCAR_EN (1<<2) 59 #define DM_TWER_OVF_EN (1<<1) 60 #define DM_TWER_MAT_EN (1<<0) 61 #define DM_TCLR 0x038 62 #define DM_TCLR_GPO (1<<14) 63 #define DM_TCLR_CAPT (1<<13) 64 #define DM_TCLR_PT (1<<12) 65 #define DM_TCLR_TRG (3<<10) 66 #define DM_TCLR_TRG_O (1<<10) 67 #define DM_TCLR_TRG_OM (2<<10) 68 #define DM_TCLR_TCM (3<<8) 69 #define DM_TCLR_TCM_RISE (1<<8) 70 #define DM_TCLR_TCM_FALL (2<<8) 71 #define DM_TCLR_TCM_BOTH (3<<8) 72 #define DM_TCLR_SCPWM (1<<7) 73 #define DM_TCLR_CE (1<<6) 74 #define DM_TCLR_PRE (1<<5) 75 #define DM_TCLR_PTV (7<<2) 76 #define DM_TCLR_AR (1<<1) 77 #define DM_TCLR_ST (1<<0) 78 #define DM_TCRR 0x03c 79 #define DM_TLDR 0x040 80 #define DM_TTGR 0x044 81 #define DM_TWPS 0x048 82 #define DM_TWPS_TMAR (1<<4) 83 #define DM_TWPS_TTGR (1<<3) 84 #define DM_TWPS_TLDR (1<<2) 85 #define DM_TWPS_TCLR (1<<0) 86 #define DM_TWPS_TCRR (1<<1) 87 #define DM_TWPS_ALL 0x1f 88 #define DM_TMAR 0x04c 89 #define DM_TCAR 0x050 90 #define DM_TSICR 0x054 91 #define DM_TSICR_POSTED (1<<2) 92 #define DM_TSICR_SFT (1<<1) 93 #define DM_TCAR2 0x058 94 95 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ 96 #define MAX_TIMERS 2 97 98 static struct evcount clk_count; 99 static struct evcount stat_count; 100 101 void dmtimer_attach(struct device *parent, struct device *self, void *args); 102 int dmtimer_intr(void *frame); 103 void dmtimer_wait(int reg); 104 void dmtimer_cpu_initclocks(void); 105 void dmtimer_delay(u_int); 106 void dmtimer_setstatclockrate(int newhz); 107 108 u_int dmtimer_get_timecount(struct timecounter *); 109 110 static struct timecounter dmtimer_timecounter = { 111 .tc_get_timecount = dmtimer_get_timecount, 112 .tc_poll_pps = NULL, 113 .tc_counter_mask = 0xffffffff, 114 .tc_frequency = 0, 115 .tc_name = "dmtimer", 116 .tc_quality = 0, 117 .tc_priv = NULL, 118 }; 119 120 bus_space_handle_t dmtimer_ioh0; 121 int dmtimer_irq = 0; 122 123 struct dmtimer_softc { 124 struct device sc_dev; 125 bus_space_tag_t sc_iot; 126 bus_space_handle_t sc_ioh[MAX_TIMERS]; 127 u_int32_t sc_irq; 128 u_int32_t sc_ticks_per_second; 129 u_int32_t sc_ticks_per_intr; 130 u_int32_t sc_ticks_err_cnt; 131 u_int32_t sc_ticks_err_sum; 132 u_int32_t sc_statvar; 133 u_int32_t sc_statmin; 134 u_int32_t sc_nexttickevent; 135 u_int32_t sc_nextstatevent; 136 }; 137 138 const struct cfattach dmtimer_ca = { 139 sizeof (struct dmtimer_softc), NULL, dmtimer_attach 140 }; 141 142 struct cfdriver dmtimer_cd = { 143 NULL, "dmtimer", DV_DULL 144 }; 145 146 void 147 dmtimer_attach(struct device *parent, struct device *self, void *args) 148 { 149 struct dmtimer_softc *sc = (struct dmtimer_softc *)self; 150 struct armv7_attach_args *aa = args; 151 bus_space_handle_t ioh; 152 u_int32_t rev, cfg; 153 154 sc->sc_iot = aa->aa_iot; 155 156 if (bus_space_map(sc->sc_iot, aa->aa_dev->mem[0].addr, 157 aa->aa_dev->mem[0].size, 0, &ioh)) 158 panic("%s: bus_space_map failed!", __func__); 159 160 161 prcm_setclock(1, PRCM_CLK_SPEED_32); 162 prcm_setclock(2, PRCM_CLK_SPEED_32); 163 prcm_enablemodule(PRCM_TIMER2); 164 prcm_enablemodule(PRCM_TIMER3); 165 166 /* reset */ 167 bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG, 168 DM_TIOCP_CFG_SOFTRESET); 169 while (bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG) 170 & DM_TIOCP_CFG_SOFTRESET) 171 ; 172 173 if (self->dv_unit == 0) { 174 dmtimer_ioh0 = ioh; 175 dmtimer_irq = aa->aa_dev->irq[0]; 176 /* enable write posted mode */ 177 bus_space_write_4(sc->sc_iot, ioh, DM_TSICR, DM_TSICR_POSTED); 178 /* stop timer */ 179 bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, 0); 180 } else if (self->dv_unit == 1) { 181 /* start timer because it is used in delay */ 182 /* interrupts and posted mode are disabled */ 183 sc->sc_irq = dmtimer_irq; 184 sc->sc_ioh[0] = dmtimer_ioh0; 185 sc->sc_ioh[1] = ioh; 186 187 bus_space_write_4(sc->sc_iot, ioh, DM_TCRR, 0); 188 bus_space_write_4(sc->sc_iot, ioh, DM_TLDR, 0); 189 bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, 190 DM_TCLR_AR | DM_TCLR_ST); 191 192 dmtimer_timecounter.tc_frequency = TIMER_FREQUENCY; 193 dmtimer_timecounter.tc_priv = sc; 194 tc_init(&dmtimer_timecounter); 195 arm_clock_register(dmtimer_cpu_initclocks, dmtimer_delay, 196 dmtimer_setstatclockrate, NULL); 197 } 198 else 199 panic("attaching too many dmtimers at 0x%lx", 200 aa->aa_dev->mem[0].addr); 201 202 /* set IDLEMODE to smart-idle */ 203 cfg = bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG); 204 bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG, 205 (cfg & ~DM_TIOCP_CFG_IDLEMODE) | 0x02); 206 207 rev = bus_space_read_4(sc->sc_iot, ioh, DM_TIDR); 208 printf(" rev %d.%d\n", (rev & DM_TIDR_MAJOR) >> 8, rev & DM_TIDR_MINOR); 209 } 210 211 /* 212 * See comment in arm/xscale/i80321_clock.c 213 * 214 * Counter is count up, but with autoreload timers it is not possible 215 * to detect how many interrupts passed while interrupts were blocked. 216 * Also it is not possible to atomically add to the register. 217 * 218 * To work around this two timers are used, one is used as a reference 219 * clock without reload, however we just disable the interrupt it 220 * could generate. 221 * 222 * Internally this keeps track of when the next timer should fire 223 * and based on that time and the current value of the reference 224 * clock a number is written into the timer count register to schedule 225 * the next event. 226 */ 227 228 int 229 dmtimer_intr(void *frame) 230 { 231 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; 232 u_int32_t now, r, nextevent; 233 int32_t duration; 234 235 now = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); 236 237 while ((int32_t) (sc->sc_nexttickevent - now) <= 0) { 238 sc->sc_nexttickevent += sc->sc_ticks_per_intr; 239 sc->sc_ticks_err_sum += sc->sc_ticks_err_cnt; 240 241 while (sc->sc_ticks_err_sum > hz) { 242 sc->sc_nexttickevent += 1; 243 sc->sc_ticks_err_sum -= hz; 244 } 245 246 clk_count.ec_count++; 247 hardclock(frame); 248 } 249 250 while ((int32_t) (sc->sc_nextstatevent - now) <= 0) { 251 do { 252 r = random() & (sc->sc_statvar - 1); 253 } while (r == 0); /* random == 0 not allowed */ 254 sc->sc_nextstatevent += sc->sc_statmin + r; 255 stat_count.ec_count++; 256 statclock(frame); 257 } 258 if ((sc->sc_nexttickevent - now) < (sc->sc_nextstatevent - now)) 259 nextevent = sc->sc_nexttickevent; 260 else 261 nextevent = sc->sc_nextstatevent; 262 263 duration = nextevent - 264 bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); 265 266 if (duration <= 0) 267 duration = 1; /* trigger immediately. */ 268 269 if (duration > sc->sc_ticks_per_intr + 1) { 270 printf("%s: time lost!\n", __func__); 271 /* 272 * If interrupts are blocked too long, like during 273 * the root prompt or ddb, the timer can roll over, 274 * this will allow the system to continue to run 275 * even if time is lost. 276 */ 277 duration = sc->sc_ticks_per_intr; 278 sc->sc_nexttickevent = now; 279 sc->sc_nextstatevent = now; 280 } 281 282 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, 283 bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR)); 284 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -duration); 285 dmtimer_wait(DM_TWPS_ALL); 286 287 return 1; 288 } 289 290 /* 291 * would be interesting to play with trigger mode while having one timer 292 * in 32kHz mode, and the other timer running in sysclk mode and use 293 * the high resolution speeds (matters more for delay than tick timer 294 */ 295 296 void 297 dmtimer_cpu_initclocks(void) 298 { 299 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; 300 301 stathz = 128; 302 profhz = 1024; 303 304 sc->sc_ticks_per_second = TIMER_FREQUENCY; /* 32768 */ 305 306 setstatclockrate(stathz); 307 308 sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; 309 sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; 310 sc->sc_ticks_err_sum = 0; 311 312 /* establish interrupts */ 313 arm_intr_establish(sc->sc_irq, IPL_CLOCK, dmtimer_intr, 314 NULL, "tick"); 315 316 /* setup timer 0 */ 317 318 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TLDR, 0); 319 320 sc->sc_nexttickevent = sc->sc_nextstatevent = bus_space_read_4(sc->sc_iot, 321 sc->sc_ioh[1], DM_TCRR) + sc->sc_ticks_per_intr; 322 323 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TIER, DM_TIER_OVF_EN); 324 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TWER, DM_TWER_OVF_EN); 325 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, /*clear interrupt flags */ 326 bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR)); 327 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -sc->sc_ticks_per_intr); 328 dmtimer_wait(DM_TWPS_ALL); 329 bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCLR, /* autoreload and start */ 330 DM_TCLR_AR | DM_TCLR_ST); 331 dmtimer_wait(DM_TWPS_ALL); 332 } 333 334 void 335 dmtimer_wait(int reg) 336 { 337 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; 338 while (bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TWPS) & reg) 339 ; 340 } 341 342 void 343 dmtimer_delay(u_int usecs) 344 { 345 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; 346 u_int32_t clock, oclock, delta, delaycnt; 347 volatile int j; 348 int csec, usec; 349 350 if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { 351 csec = usecs / 10000; 352 usec = usecs % 10000; 353 354 delaycnt = (TIMER_FREQUENCY / 100) * csec + 355 (TIMER_FREQUENCY / 100) * usec / 10000; 356 } else { 357 delaycnt = TIMER_FREQUENCY * usecs / 1000000; 358 } 359 if (delaycnt <= 1) 360 for (j = 100; j > 0; j--) 361 ; 362 363 if (sc->sc_ioh[1] == 0) { 364 /* BAH */ 365 for (; usecs > 0; usecs--) 366 for (j = 100; j > 0; j--) 367 ; 368 return; 369 } 370 oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); 371 while (1) { 372 for (j = 100; j > 0; j--) 373 ; 374 clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); 375 delta = clock - oclock; 376 if (delta > delaycnt) 377 break; 378 } 379 380 } 381 382 void 383 dmtimer_setstatclockrate(int newhz) 384 { 385 struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; 386 int minint, statint; 387 int s; 388 389 s = splclock(); 390 391 statint = sc->sc_ticks_per_second / newhz; 392 /* calculate largest 2^n which is smaller than just over half statint */ 393 sc->sc_statvar = 0x40000000; /* really big power of two */ 394 minint = statint / 2 + 100; 395 while (sc->sc_statvar > minint) 396 sc->sc_statvar >>= 1; 397 398 sc->sc_statmin = statint - (sc->sc_statvar >> 1); 399 400 splx(s); 401 402 /* 403 * XXX this allows the next stat timer to occur then it switches 404 * to the new frequency. Rather than switching instantly. 405 */ 406 } 407 408 409 u_int 410 dmtimer_get_timecount(struct timecounter *tc) 411 { 412 struct dmtimer_softc *sc = dmtimer_timecounter.tc_priv; 413 414 return bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); 415 } 416