1 1.5 skrll /* $Id: imx23_timrot.c,v 1.5 2025/10/09 06:15:16 skrll Exp $ */ 2 1.1 jkunz 3 1.1 jkunz /* 4 1.1 jkunz * Copyright (c) 2012 The NetBSD Foundation, Inc. 5 1.1 jkunz * All rights reserved. 6 1.1 jkunz * 7 1.1 jkunz * This code is derived from software contributed to The NetBSD Foundation 8 1.1 jkunz * by Petri Laakso. 9 1.1 jkunz * 10 1.1 jkunz * Redistribution and use in source and binary forms, with or without 11 1.1 jkunz * modification, are permitted provided that the following conditions 12 1.1 jkunz * are met: 13 1.1 jkunz * 1. Redistributions of source code must retain the above copyright 14 1.1 jkunz * notice, this list of conditions and the following disclaimer. 15 1.1 jkunz * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 jkunz * notice, this list of conditions and the following disclaimer in the 17 1.1 jkunz * documentation and/or other materials provided with the distribution. 18 1.1 jkunz * 19 1.1 jkunz * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 1.1 jkunz * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 1.1 jkunz * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 1.1 jkunz * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 1.1 jkunz * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 1.1 jkunz * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 1.1 jkunz * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 1.1 jkunz * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 1.1 jkunz * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 1.1 jkunz * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 1.1 jkunz * POSSIBILITY OF SUCH DAMAGE. 30 1.1 jkunz */ 31 1.1 jkunz 32 1.1 jkunz #include <sys/param.h> 33 1.5 skrll 34 1.1 jkunz #include <sys/bus.h> 35 1.1 jkunz #include <sys/device.h> 36 1.1 jkunz #include <sys/errno.h> 37 1.1 jkunz #include <sys/systm.h> 38 1.1 jkunz 39 1.1 jkunz #include <arm/imx/imx23_timrotreg.h> 40 1.5 skrll #include <arm/imx/imx23_timrotvar.h> 41 1.1 jkunz #include <arm/imx/imx23var.h> 42 1.1 jkunz 43 1.1 jkunz extern int hz; 44 1.1 jkunz extern int stathz; 45 1.1 jkunz 46 1.1 jkunz static int timrot_match(device_t, cfdata_t, void *); 47 1.1 jkunz static void timrot_attach(device_t, device_t, void *); 48 1.1 jkunz static int timrot_activate(device_t, enum devact); 49 1.1 jkunz 50 1.5 skrll static int 51 1.5 skrll timrot_init(struct timrot_softc *, bus_space_tag_t, bus_size_t, int8_t, int, 52 1.5 skrll int (*)(void *)); 53 1.1 jkunz static void timrot_reset(void); 54 1.1 jkunz 55 1.1 jkunz 56 1.1 jkunz void cpu_initclocks(void); 57 1.1 jkunz void setstatclockrate(int); 58 1.1 jkunz 59 1.1 jkunz static bus_space_tag_t timrot_iot; 60 1.1 jkunz static bus_space_handle_t timrot_hdl; 61 1.1 jkunz 62 1.5 skrll 63 1.5 skrll CFATTACH_DECL3_NEW(imx23timrot, 64 1.1 jkunz sizeof(struct timrot_softc), 65 1.1 jkunz timrot_match, 66 1.1 jkunz timrot_attach, 67 1.1 jkunz NULL, 68 1.1 jkunz timrot_activate, 69 1.1 jkunz NULL, 70 1.1 jkunz NULL, 71 1.1 jkunz 0); 72 1.1 jkunz 73 1.1 jkunz #define MAX_TIMERS 4 74 1.1 jkunz #define SYS_TIMER 0 75 1.4 skrll #define STAT_TIMER 1 76 1.1 jkunz #define SCHED_TIMER 2 77 1.1 jkunz 78 1.1 jkunz struct timrot_softc *timer_sc[MAX_TIMERS]; 79 1.1 jkunz 80 1.5 skrll static void timer_start(struct timrot_softc *); 81 1.1 jkunz 82 1.1 jkunz #define TIMROT_SOFT_RST_LOOP 455 /* At least 1 us ... */ 83 1.1 jkunz #define TIMROT_READ(reg) \ 84 1.1 jkunz bus_space_read_4(timrot_iot, timrot_hdl, (reg)) 85 1.1 jkunz #define TIMROT_WRITE(reg, val) \ 86 1.1 jkunz bus_space_write_4(timrot_iot, timrot_hdl, (reg), (val)) 87 1.1 jkunz 88 1.1 jkunz #define TIMER_REGS_SIZE 0x20 89 1.1 jkunz 90 1.1 jkunz #define TIMER_CTRL 0x00 91 1.1 jkunz #define TIMER_CTRL_SET 0x04 92 1.1 jkunz #define TIMER_CTRL_CLR 0x08 93 1.1 jkunz #define TIMER_CTRL_TOG 0x0C 94 1.1 jkunz #define TIMER_COUNT 0x10 95 1.1 jkunz 96 1.1 jkunz #define TIMER_READ(sc, reg) \ 97 1.1 jkunz bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg)) 98 1.1 jkunz #define TIMER_WRITE(sc, reg, val) \ 99 1.1 jkunz bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val)) 100 1.1 jkunz #define TIMER_WRITE_2(sc, reg, val) \ 101 1.1 jkunz bus_space_write_2(sc->sc_iot, sc->sc_hdl, (reg), (val)) 102 1.1 jkunz 103 1.1 jkunz #define SELECT_32KHZ 0x8 /* Use 32kHz clock source. */ 104 1.1 jkunz #define SOURCE_32KHZ_HZ 32000 /* Above source in Hz. */ 105 1.1 jkunz 106 1.1 jkunz #define IRQ HW_TIMROT_TIMCTRL0_IRQ 107 1.1 jkunz #define IRQ_EN HW_TIMROT_TIMCTRL0_IRQ_EN 108 1.1 jkunz #define UPDATE HW_TIMROT_TIMCTRL0_UPDATE 109 1.1 jkunz #define RELOAD HW_TIMROT_TIMCTRL0_RELOAD 110 1.1 jkunz 111 1.1 jkunz static int 112 1.1 jkunz timrot_match(device_t parent, cfdata_t match, void *aux) 113 1.1 jkunz { 114 1.1 jkunz struct apb_attach_args *aa = aux; 115 1.1 jkunz 116 1.1 jkunz if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0 117 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE)) 118 1.1 jkunz return 1; 119 1.1 jkunz 120 1.1 jkunz if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1 121 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE)) 122 1.1 jkunz return 1; 123 1.1 jkunz 124 1.1 jkunz #if 0 125 1.1 jkunz if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL2 126 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE)) 127 1.1 jkunz return 1; 128 1.1 jkunz 129 1.1 jkunz if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL3 130 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE)) 131 1.1 jkunz return 1; 132 1.1 jkunz #endif 133 1.1 jkunz return 0; 134 1.1 jkunz } 135 1.1 jkunz 136 1.1 jkunz static void 137 1.1 jkunz timrot_attach(device_t parent, device_t self, void *aux) 138 1.1 jkunz { 139 1.1 jkunz struct apb_attach_args *aa = aux; 140 1.1 jkunz struct timrot_softc *sc = device_private(self); 141 1.1 jkunz 142 1.1 jkunz if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0 143 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE 144 1.1 jkunz && timer_sc[SYS_TIMER] == NULL) { 145 1.5 skrll imx23timrot_systimer_init(sc, aa->aa_iot, aa->aa_irq); 146 1.1 jkunz 147 1.1 jkunz aprint_normal("\n"); 148 1.1 jkunz 149 1.1 jkunz } else if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1 150 1.1 jkunz && aa->aa_size == TIMER_REGS_SIZE 151 1.1 jkunz && timer_sc[STAT_TIMER] == NULL) { 152 1.5 skrll imx23timrot_stattimer_init(sc, aa->aa_iot, aa->aa_irq); 153 1.5 skrll 154 1.5 skrll aprint_normal("\n"); 155 1.5 skrll } 156 1.5 skrll 157 1.5 skrll return; 158 1.5 skrll } 159 1.5 skrll 160 1.5 skrll /* 161 1.5 skrll * Initiates initialization of the systimer 162 1.5 skrll */ 163 1.5 skrll int 164 1.5 skrll imx23timrot_systimer_init(struct timrot_softc *sc, bus_space_tag_t iot, 165 1.5 skrll int8_t irq) 166 1.5 skrll { 167 1.5 skrll int status; 168 1.5 skrll 169 1.5 skrll status = timrot_init(sc, iot, HW_TIMROT_TIMCTRL0, irq, hz, 170 1.5 skrll &imx23timrot_systimer_irq); 171 1.5 skrll timer_sc[SYS_TIMER] = sc; 172 1.5 skrll 173 1.5 skrll return status; 174 1.5 skrll } 175 1.5 skrll 176 1.5 skrll /* 177 1.5 skrll * Initiates initialization of the stattimer 178 1.5 skrll */ 179 1.5 skrll int 180 1.5 skrll imx23timrot_stattimer_init(struct timrot_softc *sc, bus_space_tag_t iot, 181 1.5 skrll int8_t irq) 182 1.5 skrll { 183 1.5 skrll int status; 184 1.5 skrll 185 1.5 skrll stathz = (hz>>1); 186 1.5 skrll status = timrot_init(sc, iot, HW_TIMROT_TIMCTRL1, irq, hz, 187 1.5 skrll &imx23timrot_stattimer_irq); 188 1.5 skrll timer_sc[STAT_TIMER] = sc; 189 1.5 skrll 190 1.5 skrll return status; 191 1.5 skrll } 192 1.5 skrll 193 1.5 skrll 194 1.5 skrll /* 195 1.5 skrll * Generic initialization code for a timer 196 1.5 skrll */ 197 1.5 skrll static int 198 1.5 skrll timrot_init(struct timrot_softc *sc, bus_space_tag_t iot, 199 1.5 skrll bus_size_t timctrl_reg, int8_t irq, int freq, 200 1.5 skrll int (*handler)(void *)) 201 1.5 skrll { 202 1.5 skrll static int timrot_attached = 0; 203 1.5 skrll 204 1.5 skrll if (!timrot_attached) { 205 1.5 skrll timrot_iot = iot; 206 1.5 skrll if (bus_space_map(timrot_iot, HW_TIMROT_BASE, HW_TIMROT_SIZE, 0, 207 1.5 skrll &timrot_hdl)) { 208 1.1 jkunz aprint_error_dev(sc->sc_dev, 209 1.5 skrll "unable to map bus space\n"); 210 1.5 skrll return 1; 211 1.1 jkunz } 212 1.5 skrll timrot_reset(); 213 1.5 skrll timrot_attached = 1; 214 1.5 skrll } 215 1.1 jkunz 216 1.5 skrll if (bus_space_subregion(timrot_iot, timrot_hdl, timctrl_reg, 217 1.5 skrll TIMER_REGS_SIZE, &sc->sc_hdl)) { 218 1.5 skrll aprint_error_dev(sc->sc_dev, "unable to map subregion\n"); 219 1.5 skrll return 1; 220 1.5 skrll } 221 1.1 jkunz 222 1.5 skrll sc->sc_iot = iot; 223 1.5 skrll sc->sc_irq = irq; 224 1.5 skrll sc->irq_handler = handler; 225 1.5 skrll sc->freq = freq; 226 1.1 jkunz 227 1.5 skrll return 0; 228 1.1 jkunz } 229 1.1 jkunz 230 1.1 jkunz static int 231 1.1 jkunz timrot_activate(device_t self, enum devact act) 232 1.1 jkunz { 233 1.1 jkunz return EOPNOTSUPP; 234 1.1 jkunz } 235 1.1 jkunz 236 1.1 jkunz /* 237 1.5 skrll * imx23timrot_cpu_initclocks is called once at the boot time. It actually 238 1.5 skrll * starts the timers. 239 1.1 jkunz */ 240 1.1 jkunz void 241 1.5 skrll imx23timrot_cpu_initclocks(void) 242 1.1 jkunz { 243 1.1 jkunz if (timer_sc[SYS_TIMER] != NULL) 244 1.5 skrll timer_start(timer_sc[SYS_TIMER]); 245 1.1 jkunz 246 1.1 jkunz if (timer_sc[STAT_TIMER] != NULL) 247 1.5 skrll timer_start(timer_sc[STAT_TIMER]); 248 1.1 jkunz 249 1.1 jkunz return; 250 1.1 jkunz } 251 1.1 jkunz 252 1.1 jkunz /* 253 1.1 jkunz * Change statclock rate when profiling takes place. 254 1.1 jkunz */ 255 1.1 jkunz void 256 1.1 jkunz setstatclockrate(int newhz) 257 1.1 jkunz { 258 1.1 jkunz struct timrot_softc *sc = timer_sc[STAT_TIMER]; 259 1.1 jkunz sc->freq = newhz; 260 1.1 jkunz 261 1.1 jkunz TIMER_WRITE_2(sc, TIMER_COUNT, 262 1.3 matt __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1, 263 1.1 jkunz HW_TIMROT_TIMCOUNT0_FIXED_COUNT)); 264 1.1 jkunz 265 1.1 jkunz return; 266 1.1 jkunz } 267 1.1 jkunz 268 1.1 jkunz /* 269 1.5 skrll * Generic function to actually start the timer 270 1.1 jkunz */ 271 1.1 jkunz static void 272 1.5 skrll timer_start(struct timrot_softc *sc) 273 1.1 jkunz { 274 1.1 jkunz uint32_t ctrl; 275 1.1 jkunz 276 1.1 jkunz TIMER_WRITE_2(sc, TIMER_COUNT, 277 1.3 matt __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1, 278 1.1 jkunz HW_TIMROT_TIMCOUNT0_FIXED_COUNT)); 279 1.1 jkunz ctrl = IRQ_EN | UPDATE | RELOAD | SELECT_32KHZ; 280 1.1 jkunz TIMER_WRITE(sc, TIMER_CTRL, ctrl); 281 1.1 jkunz 282 1.5 skrll if(sc->sc_irq != -1) { 283 1.5 skrll intr_establish(sc->sc_irq, IPL_SCHED, IST_LEVEL, 284 1.5 skrll sc->irq_handler, NULL); 285 1.5 skrll } 286 1.1 jkunz 287 1.1 jkunz return; 288 1.1 jkunz } 289 1.1 jkunz 290 1.1 jkunz /* 291 1.1 jkunz * Timer IRQ handlers. 292 1.1 jkunz */ 293 1.5 skrll int 294 1.5 skrll imx23timrot_systimer_irq(void *frame) 295 1.1 jkunz { 296 1.1 jkunz hardclock(frame); 297 1.1 jkunz 298 1.1 jkunz TIMER_WRITE(timer_sc[SYS_TIMER], TIMER_CTRL_CLR, IRQ); 299 1.1 jkunz 300 1.1 jkunz return 1; 301 1.1 jkunz } 302 1.1 jkunz 303 1.5 skrll int 304 1.5 skrll imx23timrot_stattimer_irq(void *frame) 305 1.1 jkunz { 306 1.1 jkunz statclock(frame); 307 1.1 jkunz 308 1.1 jkunz TIMER_WRITE(timer_sc[STAT_TIMER], TIMER_CTRL_CLR, IRQ); 309 1.1 jkunz 310 1.1 jkunz return 1; 311 1.1 jkunz } 312 1.1 jkunz 313 1.1 jkunz /* 314 1.1 jkunz * Reset the TIMROT block. 315 1.1 jkunz * 316 1.2 jkunz * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block" 317 1.1 jkunz */ 318 1.1 jkunz static void 319 1.1 jkunz timrot_reset(void) 320 1.1 jkunz { 321 1.1 jkunz unsigned int loop; 322 1.4 skrll 323 1.1 jkunz /* Prepare for soft-reset by making sure that SFTRST is not currently 324 1.1 jkunz * asserted. Also clear CLKGATE so we can wait for its assertion below. 325 1.1 jkunz */ 326 1.1 jkunz TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST); 327 1.1 jkunz 328 1.1 jkunz /* Wait at least a microsecond for SFTRST to deassert. */ 329 1.1 jkunz loop = 0; 330 1.1 jkunz while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) || 331 1.1 jkunz (loop < TIMROT_SOFT_RST_LOOP)) 332 1.1 jkunz loop++; 333 1.1 jkunz 334 1.1 jkunz /* Clear CLKGATE so we can wait for its assertion below. */ 335 1.1 jkunz TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE); 336 1.1 jkunz 337 1.1 jkunz /* Soft-reset the block. */ 338 1.1 jkunz TIMROT_WRITE(HW_TIMROT_ROTCTRL_SET, HW_TIMROT_ROTCTRL_SFTRST); 339 1.1 jkunz 340 1.1 jkunz /* Wait until clock is in the gated state. */ 341 1.1 jkunz while (!(TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE)); 342 1.1 jkunz 343 1.1 jkunz /* Bring block out of reset. */ 344 1.1 jkunz TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST); 345 1.1 jkunz 346 1.1 jkunz loop = 0; 347 1.1 jkunz while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) || 348 1.1 jkunz (loop < TIMROT_SOFT_RST_LOOP)) 349 1.1 jkunz loop++; 350 1.1 jkunz 351 1.1 jkunz TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE); 352 1.1 jkunz /* Wait until clock is in the NON-gated state. */ 353 1.1 jkunz while (TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE); 354 1.1 jkunz 355 1.1 jkunz return; 356 1.1 jkunz } 357