1 /* $Id: imx23_timrot.c,v 1.3 2013/10/07 17:36:40 matt 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 #include <sys/bus.h> 34 #include <sys/device.h> 35 #include <sys/errno.h> 36 #include <sys/systm.h> 37 38 #include <arm/pic/picvar.h> 39 40 #include <arm/imx/imx23_icollreg.h> 41 #include <arm/imx/imx23_timrotreg.h> 42 #include <arm/imx/imx23var.h> 43 44 extern int hz; 45 extern int stathz; 46 47 static int timrot_match(device_t, cfdata_t, void *); 48 static void timrot_attach(device_t, device_t, void *); 49 static int timrot_activate(device_t, enum devact); 50 51 static void timrot_reset(void); 52 53 /* 54 * Timer IRQ handler definitions. 55 */ 56 static int systimer_irq(void *); 57 static int stattimer_irq(void *); 58 59 void cpu_initclocks(void); 60 void setstatclockrate(int); 61 62 /* Allocated for each timer instance. */ 63 struct timrot_softc { 64 device_t sc_dev; 65 bus_space_tag_t sc_iot; 66 bus_space_handle_t sc_hdl; 67 int8_t sc_irq; 68 int (*irq_handler)(void *); 69 int freq; 70 }; 71 72 static bus_space_tag_t timrot_iot; 73 static bus_space_handle_t timrot_hdl; 74 75 CFATTACH_DECL3_NEW(timrot, 76 sizeof(struct timrot_softc), 77 timrot_match, 78 timrot_attach, 79 NULL, 80 timrot_activate, 81 NULL, 82 NULL, 83 0); 84 85 #define MAX_TIMERS 4 86 #define SYS_TIMER 0 87 #define STAT_TIMER 1 88 #define SCHED_TIMER 2 89 90 struct timrot_softc *timer_sc[MAX_TIMERS]; 91 92 static void timer_init(struct timrot_softc *); 93 94 #define TIMROT_SOFT_RST_LOOP 455 /* At least 1 us ... */ 95 #define TIMROT_READ(reg) \ 96 bus_space_read_4(timrot_iot, timrot_hdl, (reg)) 97 #define TIMROT_WRITE(reg, val) \ 98 bus_space_write_4(timrot_iot, timrot_hdl, (reg), (val)) 99 100 #define TIMER_REGS_SIZE 0x20 101 102 #define TIMER_CTRL 0x00 103 #define TIMER_CTRL_SET 0x04 104 #define TIMER_CTRL_CLR 0x08 105 #define TIMER_CTRL_TOG 0x0C 106 #define TIMER_COUNT 0x10 107 108 #define TIMER_READ(sc, reg) \ 109 bus_space_read_4(sc->sc_iot, sc->sc_hdl, (reg)) 110 #define TIMER_WRITE(sc, reg, val) \ 111 bus_space_write_4(sc->sc_iot, sc->sc_hdl, (reg), (val)) 112 #define TIMER_WRITE_2(sc, reg, val) \ 113 bus_space_write_2(sc->sc_iot, sc->sc_hdl, (reg), (val)) 114 115 #define SELECT_32KHZ 0x8 /* Use 32kHz clock source. */ 116 #define SOURCE_32KHZ_HZ 32000 /* Above source in Hz. */ 117 118 #define IRQ HW_TIMROT_TIMCTRL0_IRQ 119 #define IRQ_EN HW_TIMROT_TIMCTRL0_IRQ_EN 120 #define UPDATE HW_TIMROT_TIMCTRL0_UPDATE 121 #define RELOAD HW_TIMROT_TIMCTRL0_RELOAD 122 123 static int 124 timrot_match(device_t parent, cfdata_t match, void *aux) 125 { 126 struct apb_attach_args *aa = aux; 127 128 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0 129 && aa->aa_size == TIMER_REGS_SIZE)) 130 return 1; 131 132 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1 133 && aa->aa_size == TIMER_REGS_SIZE)) 134 return 1; 135 136 #if 0 137 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL2 138 && aa->aa_size == TIMER_REGS_SIZE)) 139 return 1; 140 141 if ((aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL3 142 && aa->aa_size == TIMER_REGS_SIZE)) 143 return 1; 144 #endif 145 return 0; 146 } 147 148 static void 149 timrot_attach(device_t parent, device_t self, void *aux) 150 { 151 struct apb_attach_args *aa = aux; 152 struct timrot_softc *sc = device_private(self); 153 static int timrot_attached = 0; 154 155 if (!timrot_attached) { 156 timrot_iot = aa->aa_iot; 157 if (bus_space_map(timrot_iot, HW_TIMROT_BASE, HW_TIMROT_SIZE, 158 0, &timrot_hdl)) { 159 aprint_error_dev(sc->sc_dev, 160 "unable to map bus space\n"); 161 return; 162 } 163 timrot_reset(); 164 timrot_attached = 1; 165 } 166 167 if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL0 168 && aa->aa_size == TIMER_REGS_SIZE 169 && timer_sc[SYS_TIMER] == NULL) { 170 if (bus_space_subregion(timrot_iot, timrot_hdl, 171 HW_TIMROT_TIMCTRL0, TIMER_REGS_SIZE, 172 &sc->sc_hdl)) { 173 aprint_error_dev(sc->sc_dev, 174 "unable to map subregion\n"); 175 return; 176 } 177 178 sc->sc_iot = aa->aa_iot; 179 sc->sc_irq = aa->aa_irq; 180 sc->irq_handler = &systimer_irq; 181 sc->freq = hz; 182 183 timer_sc[SYS_TIMER] = sc; 184 185 aprint_normal("\n"); 186 187 } else if (aa->aa_addr == HW_TIMROT_BASE + HW_TIMROT_TIMCTRL1 188 && aa->aa_size == TIMER_REGS_SIZE 189 && timer_sc[STAT_TIMER] == NULL) { 190 if (bus_space_subregion(timrot_iot, timrot_hdl, 191 HW_TIMROT_TIMCTRL1, TIMER_REGS_SIZE, &sc->sc_hdl)) { 192 aprint_error_dev(sc->sc_dev, 193 "unable to map subregion\n"); 194 return; 195 } 196 197 sc->sc_iot = aa->aa_iot; 198 sc->sc_irq = aa->aa_irq; 199 sc->irq_handler = &stattimer_irq; 200 stathz = (hz>>1); 201 sc->freq = stathz; 202 203 timer_sc[STAT_TIMER] = sc; 204 205 aprint_normal("\n"); 206 } 207 208 return; 209 } 210 211 static int 212 timrot_activate(device_t self, enum devact act) 213 { 214 return EOPNOTSUPP; 215 } 216 217 /* 218 * cpu_initclock is called once at the boot time. 219 */ 220 void 221 cpu_initclocks(void) 222 { 223 if (timer_sc[SYS_TIMER] != NULL) 224 timer_init(timer_sc[SYS_TIMER]); 225 226 if (timer_sc[STAT_TIMER] != NULL) 227 timer_init(timer_sc[STAT_TIMER]); 228 229 return; 230 } 231 232 /* 233 * Change statclock rate when profiling takes place. 234 */ 235 void 236 setstatclockrate(int newhz) 237 { 238 struct timrot_softc *sc = timer_sc[STAT_TIMER]; 239 sc->freq = newhz; 240 241 TIMER_WRITE_2(sc, TIMER_COUNT, 242 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1, 243 HW_TIMROT_TIMCOUNT0_FIXED_COUNT)); 244 245 return; 246 } 247 248 /* 249 * Generic timer initialization function. 250 */ 251 static void 252 timer_init(struct timrot_softc *sc) 253 { 254 uint32_t ctrl; 255 256 TIMER_WRITE_2(sc, TIMER_COUNT, 257 __SHIFTIN(SOURCE_32KHZ_HZ / sc->freq - 1, 258 HW_TIMROT_TIMCOUNT0_FIXED_COUNT)); 259 ctrl = IRQ_EN | UPDATE | RELOAD | SELECT_32KHZ; 260 TIMER_WRITE(sc, TIMER_CTRL, ctrl); 261 262 intr_establish(sc->sc_irq, IPL_SCHED, IST_LEVEL, sc->irq_handler, NULL); 263 264 return; 265 } 266 267 /* 268 * Timer IRQ handlers. 269 */ 270 static int 271 systimer_irq(void *frame) 272 { 273 hardclock(frame); 274 275 TIMER_WRITE(timer_sc[SYS_TIMER], TIMER_CTRL_CLR, IRQ); 276 277 return 1; 278 } 279 280 static int 281 stattimer_irq(void *frame) 282 { 283 statclock(frame); 284 285 TIMER_WRITE(timer_sc[STAT_TIMER], TIMER_CTRL_CLR, IRQ); 286 287 return 1; 288 } 289 290 /* 291 * Reset the TIMROT block. 292 * 293 * Inspired by i.MX23 RM "39.3.10 Correct Way to Soft Reset a Block" 294 */ 295 static void 296 timrot_reset(void) 297 { 298 unsigned int loop; 299 300 /* Prepare for soft-reset by making sure that SFTRST is not currently 301 * asserted. Also clear CLKGATE so we can wait for its assertion below. 302 */ 303 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST); 304 305 /* Wait at least a microsecond for SFTRST to deassert. */ 306 loop = 0; 307 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) || 308 (loop < TIMROT_SOFT_RST_LOOP)) 309 loop++; 310 311 /* Clear CLKGATE so we can wait for its assertion below. */ 312 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE); 313 314 /* Soft-reset the block. */ 315 TIMROT_WRITE(HW_TIMROT_ROTCTRL_SET, HW_TIMROT_ROTCTRL_SFTRST); 316 317 /* Wait until clock is in the gated state. */ 318 while (!(TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE)); 319 320 /* Bring block out of reset. */ 321 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_SFTRST); 322 323 loop = 0; 324 while ((TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_SFTRST) || 325 (loop < TIMROT_SOFT_RST_LOOP)) 326 loop++; 327 328 TIMROT_WRITE(HW_TIMROT_ROTCTRL_CLR, HW_TIMROT_ROTCTRL_CLKGATE); 329 /* Wait until clock is in the NON-gated state. */ 330 while (TIMROT_READ(HW_TIMROT_ROTCTRL) & HW_TIMROT_ROTCTRL_CLKGATE); 331 332 return; 333 } 334