1 /* $OpenBSD: gptimer.c,v 1.19 2023/02/04 19:19:36 cheloha 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 initialization 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/clockintr.h> 27 #include <sys/kernel.h> 28 #include <sys/evcount.h> 29 #include <sys/device.h> 30 #include <sys/stdint.h> 31 #include <sys/timetc.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 38 /* registers */ 39 #define GP_TIDR 0x000 40 #define GP_TIDR_REV 0xff 41 #define GP_TIOCP_CFG 0x010 42 #define GP_TIOCP_CFG_CLKA 0x000000300 43 #define GP_TIOCP_CFG_EMUFREE 0x000000020 44 #define GP_TIOCP_CFG_IDLEMODE 0x000000018 45 #define GP_TIOCP_CFG_ENAPWAKEUP 0x000000004 46 #define GP_TIOCP_CFG_SOFTRESET 0x000000002 47 #define GP_TIOCP_CFG_AUTOIDLE 0x000000001 48 #define GP_TISTAT 0x014 49 #define GP_TISTAT_RESETDONE 0x000000001 50 #define GP_TISR 0x018 51 #define GP_TISTAT_TCAR 0x00000004 52 #define GP_TISTAT_OVF 0x00000002 53 #define GP_TISTAT_MATCH 0x00000001 54 #define GP_TIER 0x1c 55 #define GP_TIER_TCAR_EN 0x4 56 #define GP_TIER_OVF_EN 0x2 57 #define GP_TIER_MAT_EN 0x1 58 #define GP_TWER 0x020 59 #define GP_TWER_TCAR_EN 0x00000004 60 #define GP_TWER_OVF_EN 0x00000002 61 #define GP_TWER_MAT_EN 0x00000001 62 #define GP_TCLR 0x024 63 #define GP_TCLR_GPO (1<<14) 64 #define GP_TCLR_CAPT (1<<13) 65 #define GP_TCLR_PT (1<<12) 66 #define GP_TCLR_TRG (3<<10) 67 #define GP_TCLR_TRG_O (1<<10) 68 #define GP_TCLR_TRG_OM (2<<10) 69 #define GP_TCLR_TCM (3<<8) 70 #define GP_TCLR_TCM_RISE (1<<8) 71 #define GP_TCLR_TCM_FALL (2<<8) 72 #define GP_TCLR_TCM_BOTH (3<<8) 73 #define GP_TCLR_SCPWM (1<<7) 74 #define GP_TCLR_CE (1<<6) 75 #define GP_TCLR_PRE (1<<5) 76 #define GP_TCLR_PTV (7<<2) 77 #define GP_TCLR_AR (1<<1) 78 #define GP_TCLR_ST (1<<0) 79 #define GP_TCRR 0x028 /* counter */ 80 #define GP_TLDR 0x02c /* reload */ 81 #define GP_TTGR 0x030 82 #define GP_TWPS 0x034 83 #define GP_TWPS_TCLR 0x01 84 #define GP_TWPS_TCRR 0x02 85 #define GP_TWPS_TLDR 0x04 86 #define GP_TWPS_TTGR 0x08 87 #define GP_TWPS_TMAR 0x10 88 #define GP_TWPS_ALL 0x1f 89 #define GP_TMAR 0x038 90 #define GP_TCAR 0x03C 91 #define GP_TSICR 0x040 92 #define GP_TSICR_POSTED 0x00000002 93 #define GP_TSICR_SFT 0x00000001 94 #define GP_TCAR2 0x044 95 96 #define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ 97 98 void gptimer_attach(struct device *parent, struct device *self, void *args); 99 int gptimer_intr(void *frame); 100 void gptimer_wait(int reg); 101 void gptimer_cpu_initclocks(void); 102 void gptimer_delay(u_int); 103 void gptimer_reset_tisr(void); 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_counter_mask = 0xffffffff, 115 .tc_frequency = 0, 116 .tc_name = "gptimer", 117 .tc_quality = 0, 118 .tc_priv = NULL, 119 .tc_user = 0, 120 }; 121 122 uint64_t gptimer_nsec_cycle_ratio; 123 uint64_t gptimer_nsec_max; 124 125 void gptimer_rearm(void *, uint64_t); 126 void gptimer_trigger(void *); 127 128 const struct intrclock gptimer_intrclock = { 129 .ic_rearm = gptimer_rearm, 130 .ic_trigger = gptimer_trigger 131 }; 132 133 const struct cfattach gptimer_ca = { 134 sizeof (struct device), NULL, gptimer_attach 135 }; 136 137 struct cfdriver gptimer_cd = { 138 NULL, "gptimer", DV_DULL 139 }; 140 141 void 142 gptimer_attach(struct device *parent, struct device *self, void *args) 143 { 144 struct armv7_attach_args *aa = args; 145 bus_space_handle_t ioh; 146 u_int32_t rev; 147 148 gptimer_iot = aa->aa_iot; 149 if (bus_space_map(gptimer_iot, aa->aa_dev->mem[0].addr, 150 aa->aa_dev->mem[0].size, 0, &ioh)) 151 panic("gptimer_attach: bus_space_map failed!"); 152 153 rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR); 154 155 printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); 156 if (self->dv_unit == 0) { 157 gptimer_ioh0 = ioh; 158 gptimer_irq = aa->aa_dev->irq[0]; 159 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0); 160 } else if (self->dv_unit == 1) { 161 /* start timer because it is used in delay */ 162 gptimer_ioh1 = ioh; 163 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0); 164 gptimer_wait(GP_TWPS_ALL); 165 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0); 166 gptimer_wait(GP_TWPS_ALL); 167 bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR, 168 GP_TCLR_AR | GP_TCLR_ST); 169 gptimer_wait(GP_TWPS_ALL); 170 171 gptimer_timecounter.tc_frequency = TIMER_FREQUENCY; 172 tc_init(&gptimer_timecounter); 173 } 174 else 175 panic("attaching too many gptimers at 0x%lx", 176 aa->aa_dev->mem[0].addr); 177 178 arm_clock_register(gptimer_cpu_initclocks, gptimer_delay, 179 gptimer_setstatclockrate, NULL); 180 } 181 182 int 183 gptimer_intr(void *frame) 184 { 185 clockintr_dispatch(frame); 186 return 1; 187 } 188 189 /* 190 * would be interesting to play with trigger mode while having one timer 191 * in 32kHz mode, and the other timer running in sysclk mode and use 192 * the high resolution speeds (matters more for delay than tick timer 193 */ 194 195 void 196 gptimer_cpu_initclocks(void) 197 { 198 stathz = hz; 199 profhz = stathz * 10; 200 clockintr_init(CL_RNDSTAT); 201 202 gptimer_nsec_cycle_ratio = TIMER_FREQUENCY * (1ULL << 32) / 1000000000; 203 gptimer_nsec_max = UINT64_MAX / gptimer_nsec_cycle_ratio; 204 205 prcm_setclock(1, PRCM_CLK_SPEED_32); 206 prcm_setclock(2, PRCM_CLK_SPEED_32); 207 208 /* establish interrupts */ 209 arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr, 210 NULL, "tick"); 211 212 /* setup timer 0 (hardware timer 2) */ 213 /* reset? - XXX */ 214 gptimer_wait(GP_TWPS_ALL); 215 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN); 216 gptimer_wait(GP_TWPS_ALL); 217 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN); 218 gptimer_wait(GP_TWPS_ALL); 219 220 /* start the clock interrupt cycle */ 221 clockintr_cpu_init(&gptimer_intrclock); 222 clockintr_trigger(); 223 } 224 225 void 226 gptimer_wait(int reg) 227 { 228 while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg) 229 ; 230 } 231 232 /* 233 * Clear all interrupt status bits. 234 */ 235 void 236 gptimer_reset_tisr(void) 237 { 238 u_int32_t tisr; 239 240 tisr = bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR); 241 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, tisr); 242 } 243 244 void 245 gptimer_rearm(void *unused, uint64_t nsecs) 246 { 247 uint32_t cycles; 248 u_long s; 249 250 if (nsecs > gptimer_nsec_max) 251 nsecs = gptimer_nsec_max; 252 cycles = (nsecs * gptimer_nsec_cycle_ratio) >> 32; 253 254 s = intr_disable(); 255 gptimer_reset_tisr(); 256 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, 257 UINT32_MAX - cycles); 258 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST); 259 gptimer_wait(GP_TWPS_ALL); 260 intr_restore(s); 261 } 262 263 void 264 gptimer_trigger(void *unused) 265 { 266 u_long s; 267 268 s = intr_disable(); 269 270 /* stop timer. */ 271 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0); 272 gptimer_wait(GP_TWPS_ALL); 273 274 /* clear interrupt status bits. */ 275 gptimer_reset_tisr(); 276 277 /* set shortest possible timeout. */ 278 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, UINT32_MAX); 279 280 /* start timer, wait for writes to post. */ 281 bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, GP_TCLR_ST); 282 gptimer_wait(GP_TWPS_ALL); 283 284 intr_restore(s); 285 } 286 287 void 288 gptimer_delay(u_int usecs) 289 { 290 u_int32_t clock, oclock, delta, delaycnt; 291 volatile int j; 292 int csec, usec; 293 294 if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { 295 csec = usecs / 10000; 296 usec = usecs % 10000; 297 298 delaycnt = (TIMER_FREQUENCY / 100) * csec + 299 (TIMER_FREQUENCY / 100) * usec / 10000; 300 } else { 301 delaycnt = TIMER_FREQUENCY * usecs / 1000000; 302 } 303 if (delaycnt <= 1) 304 for (j = 100; j > 0; j--) 305 ; 306 307 if (gptimer_ioh1 == 0) { 308 /* BAH */ 309 for (; usecs > 0; usecs--) 310 for (j = 100; j > 0; j--) 311 ; 312 return; 313 } 314 oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 315 while (1) { 316 for (j = 100; j > 0; j--) 317 ; 318 clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 319 delta = clock - oclock; 320 if (delta > delaycnt) 321 break; 322 } 323 324 } 325 326 void 327 gptimer_setstatclockrate(int newhz) 328 { 329 clockintr_setstatclockrate(newhz); 330 } 331 332 333 u_int 334 gptimer_get_timecount(struct timecounter *tc) 335 { 336 return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); 337 } 338