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