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