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