Home | History | Annotate | Line # | Download | only in imx
      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