1 /* $OpenBSD: amptimer.c,v 1.15 2023/01/17 02:47:55 cheloha Exp $ */ 2 /* 3 * Copyright (c) 2011 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 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/clockintr.h> 21 #include <sys/device.h> 22 #include <sys/kernel.h> 23 #include <sys/stdint.h> 24 #include <sys/timetc.h> 25 26 #include <arm/cpufunc.h> 27 #include <machine/bus.h> 28 #include <machine/intr.h> 29 #include <arm/cortex/cortex.h> 30 31 /* offset from periphbase */ 32 #define GTIMER_ADDR 0x200 33 #define GTIMER_SIZE 0x100 34 35 /* registers */ 36 #define GTIMER_CNT_LOW 0x00 37 #define GTIMER_CNT_HIGH 0x04 38 #define GTIMER_CTRL 0x08 39 #define GTIMER_CTRL_AA (1 << 3) 40 #define GTIMER_CTRL_IRQ (1 << 2) 41 #define GTIMER_CTRL_COMP (1 << 1) 42 #define GTIMER_CTRL_TIMER (1 << 0) 43 #define GTIMER_STATUS 0x0c 44 #define GTIMER_STATUS_EVENT (1 << 0) 45 #define GTIMER_CMP_LOW 0x10 46 #define GTIMER_CMP_HIGH 0x14 47 #define GTIMER_AUTOINC 0x18 48 49 /* offset from periphbase */ 50 #define PTIMER_ADDR 0x600 51 #define PTIMER_SIZE 0x100 52 53 /* registers */ 54 #define PTIMER_LOAD 0x0 55 #define PTIMER_CNT 0x4 56 #define PTIMER_CTRL 0x8 57 #define PTIMER_CTRL_ENABLE (1<<0) 58 #define PTIMER_CTRL_AUTORELOAD (1<<1) 59 #define PTIMER_CTRL_IRQEN (1<<2) 60 #define PTIMER_STATUS 0xC 61 #define PTIMER_STATUS_EVENT (1<<0) 62 63 #define TIMER_FREQUENCY 396 * 1000 * 1000 /* ARM core clock */ 64 int32_t amptimer_frequency = TIMER_FREQUENCY; 65 66 u_int amptimer_get_timecount(struct timecounter *); 67 68 static struct timecounter amptimer_timecounter = { 69 .tc_get_timecount = amptimer_get_timecount, 70 .tc_poll_pps = NULL, 71 .tc_counter_mask = 0xffffffff, 72 .tc_frequency = 0, 73 .tc_name = "amptimer", 74 .tc_quality = 0, 75 .tc_priv = NULL, 76 .tc_user = 0, 77 }; 78 79 void amptimer_rearm(void *, uint64_t); 80 void amptimer_trigger(void *); 81 82 struct intrclock amptimer_intrclock = { 83 .ic_rearm = amptimer_rearm, 84 .ic_trigger = amptimer_trigger 85 }; 86 87 #define MAX_ARM_CPUS 8 88 89 struct amptimer_softc { 90 struct device sc_dev; 91 bus_space_tag_t sc_iot; 92 bus_space_handle_t sc_ioh; 93 bus_space_handle_t sc_pioh; 94 95 u_int32_t sc_ticks_per_second; 96 u_int64_t sc_nsec_cycle_ratio; 97 u_int64_t sc_nsec_max; 98 }; 99 100 int amptimer_match(struct device *, void *, void *); 101 void amptimer_attach(struct device *, struct device *, void *); 102 uint64_t amptimer_readcnt64(struct amptimer_softc *sc); 103 int amptimer_intr(void *); 104 void amptimer_cpu_initclocks(void); 105 void amptimer_delay(u_int); 106 void amptimer_setstatclockrate(int stathz); 107 void amptimer_set_clockrate(int32_t new_frequency); 108 void amptimer_startclock(void); 109 110 /* hack - XXXX 111 * gptimer connects directly to ampintc, not thru the generic 112 * interface because it uses an 'internal' interrupt 113 * not a peripheral interrupt. 114 */ 115 void *ampintc_intr_establish(int, int, int, struct cpu_info *, 116 int (*)(void *), void *, char *); 117 118 119 120 const struct cfattach amptimer_ca = { 121 sizeof (struct amptimer_softc), amptimer_match, amptimer_attach 122 }; 123 124 struct cfdriver amptimer_cd = { 125 NULL, "amptimer", DV_DULL 126 }; 127 128 uint64_t 129 amptimer_readcnt64(struct amptimer_softc *sc) 130 { 131 uint32_t high0, high1, low; 132 bus_space_tag_t iot = sc->sc_iot; 133 bus_space_handle_t ioh = sc->sc_ioh; 134 135 do { 136 high0 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 137 low = bus_space_read_4(iot, ioh, GTIMER_CNT_LOW); 138 high1 = bus_space_read_4(iot, ioh, GTIMER_CNT_HIGH); 139 } while (high0 != high1); 140 141 return ((((uint64_t)high1) << 32) | low); 142 } 143 144 int 145 amptimer_match(struct device *parent, void *cfdata, void *aux) 146 { 147 if ((cpufunc_id() & CPU_ID_CORTEX_A9_MASK) == CPU_ID_CORTEX_A9) 148 return (1); 149 150 return 0; 151 } 152 153 void 154 amptimer_attach(struct device *parent, struct device *self, void *args) 155 { 156 struct amptimer_softc *sc = (struct amptimer_softc *)self; 157 struct cortex_attach_args *ia = args; 158 bus_space_handle_t ioh, pioh; 159 160 sc->sc_iot = ia->ca_iot; 161 162 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + GTIMER_ADDR, 163 GTIMER_SIZE, 0, &ioh)) 164 panic("amptimer_attach: bus_space_map global timer failed!"); 165 166 if (bus_space_map(sc->sc_iot, ia->ca_periphbase + PTIMER_ADDR, 167 PTIMER_SIZE, 0, &pioh)) 168 panic("amptimer_attach: bus_space_map priv timer failed!"); 169 170 sc->sc_ticks_per_second = amptimer_frequency; 171 sc->sc_nsec_cycle_ratio = 172 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 173 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 174 printf(": %d kHz\n", sc->sc_ticks_per_second / 1000); 175 176 sc->sc_ioh = ioh; 177 sc->sc_pioh = pioh; 178 179 /* disable global timer */ 180 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, 0); 181 182 /* XXX ??? reset counters to 0 - gives us uptime in the counter */ 183 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_LOW, 0); 184 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CNT_HIGH, 0); 185 186 /* enable global timer */ 187 bus_space_write_4(sc->sc_iot, ioh, GTIMER_CTRL, GTIMER_CTRL_TIMER); 188 189 /* Disable private timer, clear event flag. */ 190 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 0); 191 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 192 PTIMER_STATUS_EVENT); 193 194 /* 195 * private timer and interrupts not enabled until 196 * timer configures 197 */ 198 199 arm_clock_register(amptimer_cpu_initclocks, amptimer_delay, 200 amptimer_setstatclockrate, amptimer_startclock); 201 202 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 203 amptimer_timecounter.tc_priv = sc; 204 tc_init(&timer_timecounter); 205 206 amptimer_intrclock.ic_cookie = sc; 207 } 208 209 u_int 210 amptimer_get_timecount(struct timecounter *tc) 211 { 212 struct amptimer_softc *sc = amptimer_timecounter.tc_priv; 213 return bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 214 } 215 216 void 217 amptimer_rearm(void *cookie, uint64_t nsecs) 218 { 219 struct amptimer_softc *sc = cookie; 220 uint32_t cycles, reg; 221 222 if (nsecs > sc->sc_nsec_max) 223 nsecs = sc->sc_nsec_max; 224 cycles = (nsecs * sc->sc_nsec_cycle_ratio) >> 32; 225 if (cycles == 0) 226 cycles = 1; 227 228 /* clear old status */ 229 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 230 PTIMER_STATUS_EVENT); 231 232 /* 233 * Make sure the private timer counter and interrupts are enabled. 234 * XXX Why wouldn't they be? 235 */ 236 reg = bus_space_read_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL); 237 if ((reg & (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) != 238 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)) 239 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 240 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 241 242 /* Start the downcounter. */ 243 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, cycles); 244 } 245 246 void 247 amptimer_trigger(void *cookie) 248 { 249 struct amptimer_softc *sc = cookie; 250 251 /* Clear event flag, then arm counter to fire immediately. */ 252 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_STATUS, 253 PTIMER_STATUS_EVENT); 254 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_LOAD, 1); 255 } 256 257 int 258 amptimer_intr(void *frame) 259 { 260 return clockintr_dispatch(frame); 261 } 262 263 void 264 amptimer_set_clockrate(int32_t new_frequency) 265 { 266 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 267 268 amptimer_frequency = new_frequency; 269 270 if (sc == NULL) 271 return; 272 273 sc->sc_ticks_per_second = amptimer_frequency; 274 sc->sc_nsec_cycle_ratio = 275 sc->sc_ticks_per_second * (1ULL << 32) / 1000000000; 276 sc->sc_nsec_max = UINT64_MAX / sc->sc_nsec_cycle_ratio; 277 278 amptimer_timecounter.tc_frequency = sc->sc_ticks_per_second; 279 280 printf("amptimer0: adjusting clock: new rate %d kHz\n", 281 sc->sc_ticks_per_second / 1000); 282 } 283 284 void 285 amptimer_cpu_initclocks(void) 286 { 287 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 288 289 stathz = hz; 290 profhz = hz * 10; 291 clockintr_init(CL_RNDSTAT); 292 293 if (sc->sc_ticks_per_second != amptimer_frequency) { 294 amptimer_set_clockrate(amptimer_frequency); 295 } 296 297 /* establish interrupts */ 298 /* XXX - irq */ 299 ampintc_intr_establish(29, IST_EDGE_RISING, IPL_CLOCK, 300 NULL, amptimer_intr, NULL, "tick"); 301 302 /* Enable private timer counter and interrupt. */ 303 bus_space_write_4(sc->sc_iot, sc->sc_pioh, PTIMER_CTRL, 304 (PTIMER_CTRL_ENABLE | PTIMER_CTRL_IRQEN)); 305 306 /* Start the clock interrupt cycle. */ 307 clockintr_cpu_init(&timer_intrclock); 308 clockintr_trigger(); 309 } 310 311 void 312 amptimer_delay(u_int usecs) 313 { 314 struct amptimer_softc *sc = amptimer_cd.cd_devs[0]; 315 u_int32_t clock, oclock, delta, delaycnt; 316 volatile int j; 317 int csec, usec; 318 319 if (usecs > (0x80000000 / (sc->sc_ticks_per_second))) { 320 csec = usecs / 10000; 321 usec = usecs % 10000; 322 323 delaycnt = (sc->sc_ticks_per_second / 100) * csec + 324 (sc->sc_ticks_per_second / 100) * usec / 10000; 325 } else { 326 delaycnt = sc->sc_ticks_per_second * usecs / 1000000; 327 } 328 if (delaycnt <= 1) 329 for (j = 100; j > 0; j--) 330 ; 331 332 oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GTIMER_CNT_LOW); 333 while (1) { 334 for (j = 100; j > 0; j--) 335 ; 336 clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 337 GTIMER_CNT_LOW); 338 delta = clock - oclock; 339 if (delta > delaycnt) 340 break; 341 } 342 } 343 344 void 345 amptimer_setstatclockrate(int newhz) 346 { 347 clockintr_setstatclockrate(newhz); 348 } 349 350 void 351 amptimer_startclock(void) 352 { 353 clockintr_cpu_init(&timer_intrclock); 354 clockintr_trigger(); 355 } 356