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