1fc0dd0d3SIan Lepore /*- 2fc0dd0d3SIan Lepore * Copyright (c) 2017 Ian Lepore <ian@freebsd.org> 3fc0dd0d3SIan Lepore * All rights reserved. 4fc0dd0d3SIan Lepore * 5fc0dd0d3SIan Lepore * Redistribution and use in source and binary forms, with or without 6fc0dd0d3SIan Lepore * modification, are permitted provided that the following conditions 7fc0dd0d3SIan Lepore * are met: 8fc0dd0d3SIan Lepore * 1. Redistributions of source code must retain the above copyright 9fc0dd0d3SIan Lepore * notice, this list of conditions and the following disclaimer. 10fc0dd0d3SIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 11fc0dd0d3SIan Lepore * notice, this list of conditions and the following disclaimer in the 12fc0dd0d3SIan Lepore * documentation and/or other materials provided with the distribution. 13fc0dd0d3SIan Lepore * 14fc0dd0d3SIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15fc0dd0d3SIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16fc0dd0d3SIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17fc0dd0d3SIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18fc0dd0d3SIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19fc0dd0d3SIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20fc0dd0d3SIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21fc0dd0d3SIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22fc0dd0d3SIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23fc0dd0d3SIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24fc0dd0d3SIan Lepore * SUCH DAMAGE. 25fc0dd0d3SIan Lepore */ 26fc0dd0d3SIan Lepore 27fc0dd0d3SIan Lepore #include <sys/cdefs.h> 28fc0dd0d3SIan Lepore __FBSDID("$FreeBSD$"); 29fc0dd0d3SIan Lepore 30fc0dd0d3SIan Lepore /* 31fc0dd0d3SIan Lepore * Driver for imx Enhanced Programmable Interval Timer, a simple free-running 32fc0dd0d3SIan Lepore * counter device that can be used as the system timecounter. On imx5 a second 33fc0dd0d3SIan Lepore * instance of the device is used as the system eventtimer. 34fc0dd0d3SIan Lepore */ 35fc0dd0d3SIan Lepore 36fc0dd0d3SIan Lepore #include <sys/param.h> 37fc0dd0d3SIan Lepore #include <sys/systm.h> 38fc0dd0d3SIan Lepore #include <sys/bus.h> 39fc0dd0d3SIan Lepore #include <sys/kernel.h> 40fc0dd0d3SIan Lepore #include <sys/module.h> 41fc0dd0d3SIan Lepore #include <sys/malloc.h> 42fc0dd0d3SIan Lepore #include <sys/rman.h> 43fc0dd0d3SIan Lepore #include <sys/timeet.h> 44fc0dd0d3SIan Lepore #include <sys/timetc.h> 45fc0dd0d3SIan Lepore #include <sys/watchdog.h> 46fc0dd0d3SIan Lepore #include <machine/bus.h> 47fc0dd0d3SIan Lepore #include <machine/cpu.h> 48fc0dd0d3SIan Lepore #include <machine/intr.h> 49fc0dd0d3SIan Lepore #include <machine/machdep.h> 50fc0dd0d3SIan Lepore 51fc0dd0d3SIan Lepore #include <dev/fdt/fdt_common.h> 52fc0dd0d3SIan Lepore #include <dev/ofw/openfirm.h> 53fc0dd0d3SIan Lepore #include <dev/ofw/ofw_bus.h> 54fc0dd0d3SIan Lepore #include <dev/ofw/ofw_bus_subr.h> 55fc0dd0d3SIan Lepore 56fc0dd0d3SIan Lepore #include <arm/freescale/imx/imx_ccmvar.h> 57fc0dd0d3SIan Lepore #include <arm/freescale/imx/imx_machdep.h> 58fc0dd0d3SIan Lepore 59fc0dd0d3SIan Lepore #define EPIT_CR 0x00 /* Control register */ 60fc0dd0d3SIan Lepore #define EPIT_CR_CLKSRC_SHIFT 24 61fc0dd0d3SIan Lepore #define EPIT_CR_CLKSRC_OFF 0 62fc0dd0d3SIan Lepore #define EPIT_CR_CLKSRC_IPG 1 63fc0dd0d3SIan Lepore #define EPIT_CR_CLKSRC_HFCLK 2 64fc0dd0d3SIan Lepore #define EPIT_CR_CLKSRC_LFCLK 3 65fc0dd0d3SIan Lepore #define EPIT_CR_STOPEN (1u << 21) 66fc0dd0d3SIan Lepore #define EPIT_CR_WAITEN (1u << 19) 67fc0dd0d3SIan Lepore #define EPIT_CR_DBGEN (1u << 18) 68fc0dd0d3SIan Lepore #define EPIT_CR_IOVW (1u << 17) 69fc0dd0d3SIan Lepore #define EPIT_CR_SWR (1u << 16) 70fc0dd0d3SIan Lepore #define EPIT_CR_RLD (1u << 3) 71fc0dd0d3SIan Lepore #define EPIT_CR_OCIEN (1u << 2) 72fc0dd0d3SIan Lepore #define EPIT_CR_ENMOD (1u << 1) 73fc0dd0d3SIan Lepore #define EPIT_CR_EN (1u << 0) 74fc0dd0d3SIan Lepore 75fc0dd0d3SIan Lepore #define EPIT_SR 0x04 /* Status register */ 76fc0dd0d3SIan Lepore #define EPIT_SR_OCIF (1u << 0) 77fc0dd0d3SIan Lepore 78fc0dd0d3SIan Lepore #define EPIT_LR 0x08 /* Load register */ 79fc0dd0d3SIan Lepore #define EPIT_CMPR 0x0c /* Compare register */ 80fc0dd0d3SIan Lepore #define EPIT_CNR 0x10 /* Counter register */ 81fc0dd0d3SIan Lepore 82fc0dd0d3SIan Lepore /* 83fc0dd0d3SIan Lepore * Define event timer limits. 84fc0dd0d3SIan Lepore * 85fc0dd0d3SIan Lepore * In theory our minimum period is 1 tick, because to setup a oneshot we don't 86fc0dd0d3SIan Lepore * need a read-modify-write sequence to calculate and set a compare register 87fc0dd0d3SIan Lepore * value while the counter is running. In practice the waveform diagrams in the 88fc0dd0d3SIan Lepore * manual make it appear that a setting of 1 might cause it to miss the event, 89fc0dd0d3SIan Lepore * so I'm setting the lower limit to 2 ticks. 90fc0dd0d3SIan Lepore */ 91fc0dd0d3SIan Lepore #define ET_MIN_TICKS 2 92fc0dd0d3SIan Lepore #define ET_MAX_TICKS 0xfffffffe 93fc0dd0d3SIan Lepore 94fc0dd0d3SIan Lepore static u_int epit_tc_get_timecount(struct timecounter *tc); 95fc0dd0d3SIan Lepore 96fc0dd0d3SIan Lepore struct epit_softc { 97fc0dd0d3SIan Lepore device_t dev; 98fc0dd0d3SIan Lepore struct resource * memres; 99fc0dd0d3SIan Lepore struct resource * intres; 100fc0dd0d3SIan Lepore void * inthandle; 101fc0dd0d3SIan Lepore uint32_t clkfreq; 102fc0dd0d3SIan Lepore uint32_t ctlreg; 103fc0dd0d3SIan Lepore uint32_t period; 104fc0dd0d3SIan Lepore struct timecounter tc; 105fc0dd0d3SIan Lepore struct eventtimer et; 106fc0dd0d3SIan Lepore bool oneshot; 107fc0dd0d3SIan Lepore }; 108fc0dd0d3SIan Lepore 109fc0dd0d3SIan Lepore /* 110fc0dd0d3SIan Lepore * Probe data. For some reason, the standard linux dts files don't have 111fc0dd0d3SIan Lepore * compatible properties on the epit devices (other properties are missing too, 112fc0dd0d3SIan Lepore * like clocks, but we don't care as much about that). So our probe routine 113fc0dd0d3SIan Lepore * uses the name of the node (must contain "epit") and the address of the 114fc0dd0d3SIan Lepore * registers as identifying marks. 115fc0dd0d3SIan Lepore */ 116fc0dd0d3SIan Lepore static const uint32_t imx51_epit_ioaddr[2] = {0x73fac000, 0x73fb0000}; 117fc0dd0d3SIan Lepore static const uint32_t imx53_epit_ioaddr[2] = {0x53fac000, 0x53fb0000}; 118fc0dd0d3SIan Lepore static const uint32_t imx6_epit_ioaddr[2] = {0x020d0000, 0x020d4000}; 119fc0dd0d3SIan Lepore 120fc0dd0d3SIan Lepore /* ocd_data is number of units to instantiate on the platform */ 121fc0dd0d3SIan Lepore static struct ofw_compat_data compat_data[] = { 122fc0dd0d3SIan Lepore {"fsl,imx6ul-epit", 1}, 123fc0dd0d3SIan Lepore {"fsl,imx6sx-epit", 1}, 124fc0dd0d3SIan Lepore {"fsl,imx6q-epit", 1}, 125fc0dd0d3SIan Lepore {"fsl,imx6dl-epit", 1}, 126fc0dd0d3SIan Lepore {"fsl,imx53-epit", 2}, 127fc0dd0d3SIan Lepore {"fsl,imx51-epit", 2}, 128fc0dd0d3SIan Lepore {"fsl,imx31-epit", 2}, 129fc0dd0d3SIan Lepore {"fsl,imx27-epit", 2}, 130fc0dd0d3SIan Lepore {"fsl,imx25-epit", 2}, 131fc0dd0d3SIan Lepore {NULL, 0} 132fc0dd0d3SIan Lepore }; 133fc0dd0d3SIan Lepore 134fc0dd0d3SIan Lepore static inline uint32_t 135fc0dd0d3SIan Lepore RD4(struct epit_softc *sc, bus_size_t offset) 136fc0dd0d3SIan Lepore { 137fc0dd0d3SIan Lepore 138fc0dd0d3SIan Lepore return (bus_read_4(sc->memres, offset)); 139fc0dd0d3SIan Lepore } 140fc0dd0d3SIan Lepore 141fc0dd0d3SIan Lepore static inline void 142fc0dd0d3SIan Lepore WR4(struct epit_softc *sc, bus_size_t offset, uint32_t value) 143fc0dd0d3SIan Lepore { 144fc0dd0d3SIan Lepore 145fc0dd0d3SIan Lepore bus_write_4(sc->memres, offset, value); 146fc0dd0d3SIan Lepore } 147fc0dd0d3SIan Lepore 148fc0dd0d3SIan Lepore static inline void 149fc0dd0d3SIan Lepore WR4B(struct epit_softc *sc, bus_size_t offset, uint32_t value) 150fc0dd0d3SIan Lepore { 151fc0dd0d3SIan Lepore 152fc0dd0d3SIan Lepore bus_write_4(sc->memres, offset, value); 153fc0dd0d3SIan Lepore bus_barrier(sc->memres, offset, 4, BUS_SPACE_BARRIER_WRITE); 154fc0dd0d3SIan Lepore } 155fc0dd0d3SIan Lepore 156fc0dd0d3SIan Lepore static u_int 157fc0dd0d3SIan Lepore epit_read_counter(struct epit_softc *sc) 158fc0dd0d3SIan Lepore { 159fc0dd0d3SIan Lepore 160fc0dd0d3SIan Lepore /* 161fc0dd0d3SIan Lepore * Hardware is a downcounter, adjust to look like it counts up for use 162fc0dd0d3SIan Lepore * with timecounter and DELAY. 163fc0dd0d3SIan Lepore */ 164fc0dd0d3SIan Lepore return (0xffffffff - RD4(sc, EPIT_CNR)); 165fc0dd0d3SIan Lepore } 166fc0dd0d3SIan Lepore 167fc0dd0d3SIan Lepore static void 168fc0dd0d3SIan Lepore epit_do_delay(int usec, void *arg) 169fc0dd0d3SIan Lepore { 170fc0dd0d3SIan Lepore struct epit_softc *sc = arg; 171fc0dd0d3SIan Lepore uint64_t curcnt, endcnt, startcnt, ticks; 172fc0dd0d3SIan Lepore 173fc0dd0d3SIan Lepore /* 174fc0dd0d3SIan Lepore * Calculate the tick count with 64-bit values so that it works for any 175fc0dd0d3SIan Lepore * clock frequency. Loop until the hardware count reaches start+ticks. 176fc0dd0d3SIan Lepore * If the 32-bit hardware count rolls over while we're looping, just 177fc0dd0d3SIan Lepore * manually do a carry into the high bits after each read; don't worry 178fc0dd0d3SIan Lepore * that doing this on each loop iteration is inefficient -- we're trying 179fc0dd0d3SIan Lepore * to waste time here. 180fc0dd0d3SIan Lepore */ 181fc0dd0d3SIan Lepore ticks = 1 + ((uint64_t)usec * sc->clkfreq) / 1000000; 182fc0dd0d3SIan Lepore curcnt = startcnt = epit_read_counter(sc); 183fc0dd0d3SIan Lepore endcnt = startcnt + ticks; 184fc0dd0d3SIan Lepore while (curcnt < endcnt) { 185fc0dd0d3SIan Lepore curcnt = epit_read_counter(sc); 186fc0dd0d3SIan Lepore if (curcnt < startcnt) 187fc0dd0d3SIan Lepore curcnt += 1ULL << 32; 188fc0dd0d3SIan Lepore } 189fc0dd0d3SIan Lepore } 190fc0dd0d3SIan Lepore 191fc0dd0d3SIan Lepore static u_int 192fc0dd0d3SIan Lepore epit_tc_get_timecount(struct timecounter *tc) 193fc0dd0d3SIan Lepore { 194fc0dd0d3SIan Lepore 195fc0dd0d3SIan Lepore return (epit_read_counter(tc->tc_priv)); 196fc0dd0d3SIan Lepore } 197fc0dd0d3SIan Lepore 198fc0dd0d3SIan Lepore static int 199fc0dd0d3SIan Lepore epit_tc_attach(struct epit_softc *sc) 200fc0dd0d3SIan Lepore { 201fc0dd0d3SIan Lepore 202fc0dd0d3SIan Lepore /* When the counter hits zero, reload with 0xffffffff. Start it. */ 203fc0dd0d3SIan Lepore WR4(sc, EPIT_LR, 0xffffffff); 204fc0dd0d3SIan Lepore WR4(sc, EPIT_CR, sc->ctlreg | EPIT_CR_EN); 205fc0dd0d3SIan Lepore 206fc0dd0d3SIan Lepore /* Register as a timecounter. */ 207fc0dd0d3SIan Lepore sc->tc.tc_name = "EPIT"; 208fc0dd0d3SIan Lepore sc->tc.tc_quality = 1000; 209fc0dd0d3SIan Lepore sc->tc.tc_frequency = sc->clkfreq; 210fc0dd0d3SIan Lepore sc->tc.tc_counter_mask = 0xffffffff; 211fc0dd0d3SIan Lepore sc->tc.tc_get_timecount = epit_tc_get_timecount; 212fc0dd0d3SIan Lepore sc->tc.tc_priv = sc; 213fc0dd0d3SIan Lepore tc_init(&sc->tc); 214fc0dd0d3SIan Lepore 215fc0dd0d3SIan Lepore /* We are the DELAY() implementation. */ 216fc0dd0d3SIan Lepore arm_set_delay(epit_do_delay, sc); 21789ea89deSAndrew Turner 218fc0dd0d3SIan Lepore return (0); 219fc0dd0d3SIan Lepore } 220fc0dd0d3SIan Lepore 221fc0dd0d3SIan Lepore static int 222fc0dd0d3SIan Lepore epit_et_start(struct eventtimer *et, sbintime_t first, sbintime_t period) 223fc0dd0d3SIan Lepore { 224fc0dd0d3SIan Lepore struct epit_softc *sc; 225fc0dd0d3SIan Lepore uint32_t ticks; 226fc0dd0d3SIan Lepore 227fc0dd0d3SIan Lepore sc = (struct epit_softc *)et->et_priv; 228fc0dd0d3SIan Lepore 229fc0dd0d3SIan Lepore /* 230fc0dd0d3SIan Lepore * Disable the timer and clear any pending status. The timer may be 231fc0dd0d3SIan Lepore * running or may have just expired if we're called to reschedule the 232fc0dd0d3SIan Lepore * next event before the previous event time arrives. 233fc0dd0d3SIan Lepore */ 234fc0dd0d3SIan Lepore WR4(sc, EPIT_CR, sc->ctlreg); 235fc0dd0d3SIan Lepore WR4(sc, EPIT_SR, EPIT_SR_OCIF); 236fc0dd0d3SIan Lepore if (period != 0) { 237fc0dd0d3SIan Lepore sc->oneshot = false; 238fc0dd0d3SIan Lepore ticks = ((uint32_t)et->et_frequency * period) >> 32; 239fc0dd0d3SIan Lepore } else if (first != 0) { 240fc0dd0d3SIan Lepore sc->oneshot = true; 241fc0dd0d3SIan Lepore ticks = ((uint32_t)et->et_frequency * first) >> 32; 242fc0dd0d3SIan Lepore } else { 243fc0dd0d3SIan Lepore return (EINVAL); 244fc0dd0d3SIan Lepore } 245fc0dd0d3SIan Lepore 246fc0dd0d3SIan Lepore /* Set the countdown load register and start the timer. */ 247fc0dd0d3SIan Lepore WR4(sc, EPIT_LR, ticks); 248fc0dd0d3SIan Lepore WR4B(sc, EPIT_CR, sc->ctlreg | EPIT_CR_EN); 249fc0dd0d3SIan Lepore 250fc0dd0d3SIan Lepore return (0); 251fc0dd0d3SIan Lepore } 252fc0dd0d3SIan Lepore 253fc0dd0d3SIan Lepore static int 254fc0dd0d3SIan Lepore epit_et_stop(struct eventtimer *et) 255fc0dd0d3SIan Lepore { 256fc0dd0d3SIan Lepore struct epit_softc *sc; 257fc0dd0d3SIan Lepore 258fc0dd0d3SIan Lepore sc = (struct epit_softc *)et->et_priv; 259fc0dd0d3SIan Lepore 260fc0dd0d3SIan Lepore /* Disable the timer and clear any pending status. */ 261fc0dd0d3SIan Lepore WR4(sc, EPIT_CR, sc->ctlreg); 262fc0dd0d3SIan Lepore WR4B(sc, EPIT_SR, EPIT_SR_OCIF); 263fc0dd0d3SIan Lepore 264fc0dd0d3SIan Lepore return (0); 265fc0dd0d3SIan Lepore } 266fc0dd0d3SIan Lepore 267fc0dd0d3SIan Lepore static int 268fc0dd0d3SIan Lepore epit_intr(void *arg) 269fc0dd0d3SIan Lepore { 270fc0dd0d3SIan Lepore struct epit_softc *sc; 271fc0dd0d3SIan Lepore uint32_t status; 272fc0dd0d3SIan Lepore 273fc0dd0d3SIan Lepore sc = arg; 274fc0dd0d3SIan Lepore 275fc0dd0d3SIan Lepore /* 276fc0dd0d3SIan Lepore * Disable a one-shot timer until a new event is scheduled so that the 277fc0dd0d3SIan Lepore * counter doesn't wrap and fire again. Do this before clearing the 278fc0dd0d3SIan Lepore * status since a short period would make it fire again really soon. 279fc0dd0d3SIan Lepore * 280fc0dd0d3SIan Lepore * Clear interrupt status before invoking event callbacks. The callback 281fc0dd0d3SIan Lepore * often sets up a new one-shot timer event and if the interval is short 282fc0dd0d3SIan Lepore * enough it can fire before we get out of this function. If we cleared 283fc0dd0d3SIan Lepore * at the bottom we'd miss the interrupt and hang until the clock wraps. 284fc0dd0d3SIan Lepore */ 285fc0dd0d3SIan Lepore if (sc->oneshot) 286fc0dd0d3SIan Lepore WR4(sc, EPIT_CR, sc->ctlreg); 287fc0dd0d3SIan Lepore 288fc0dd0d3SIan Lepore status = RD4(sc, EPIT_SR); 289fc0dd0d3SIan Lepore WR4B(sc, EPIT_SR, status); 290fc0dd0d3SIan Lepore 291fc0dd0d3SIan Lepore if ((status & EPIT_SR_OCIF) == 0) 292fc0dd0d3SIan Lepore return (FILTER_STRAY); 293fc0dd0d3SIan Lepore 294fc0dd0d3SIan Lepore if (sc->et.et_active) 295fc0dd0d3SIan Lepore sc->et.et_event_cb(&sc->et, sc->et.et_arg); 296fc0dd0d3SIan Lepore 297fc0dd0d3SIan Lepore return (FILTER_HANDLED); 298fc0dd0d3SIan Lepore } 299fc0dd0d3SIan Lepore 300fc0dd0d3SIan Lepore static int 301fc0dd0d3SIan Lepore epit_et_attach(struct epit_softc *sc) 302fc0dd0d3SIan Lepore { 303fc0dd0d3SIan Lepore int err, rid; 304fc0dd0d3SIan Lepore 305fc0dd0d3SIan Lepore rid = 0; 306fc0dd0d3SIan Lepore sc->intres = bus_alloc_resource_any(sc->dev, SYS_RES_IRQ, &rid, 307fc0dd0d3SIan Lepore RF_ACTIVE); 308fc0dd0d3SIan Lepore if (sc->intres == NULL) { 309fc0dd0d3SIan Lepore device_printf(sc->dev, "could not allocate interrupt\n"); 310fc0dd0d3SIan Lepore return (ENXIO); 311fc0dd0d3SIan Lepore } 312fc0dd0d3SIan Lepore 313fc0dd0d3SIan Lepore err = bus_setup_intr(sc->dev, sc->intres, INTR_TYPE_CLK | INTR_MPSAFE, 314fc0dd0d3SIan Lepore epit_intr, NULL, sc, &sc->inthandle); 315fc0dd0d3SIan Lepore if (err != 0) { 316fc0dd0d3SIan Lepore device_printf(sc->dev, "unable to setup the irq handler\n"); 317fc0dd0d3SIan Lepore return (err); 318fc0dd0d3SIan Lepore } 319fc0dd0d3SIan Lepore 320fc0dd0d3SIan Lepore /* To be an eventtimer, we need interrupts enabled. */ 321fc0dd0d3SIan Lepore sc->ctlreg |= EPIT_CR_OCIEN; 322fc0dd0d3SIan Lepore 323fc0dd0d3SIan Lepore /* Register as an eventtimer. */ 324fc0dd0d3SIan Lepore sc->et.et_name = "EPIT"; 325fc0dd0d3SIan Lepore sc->et.et_flags = ET_FLAGS_ONESHOT | ET_FLAGS_PERIODIC; 326fc0dd0d3SIan Lepore sc->et.et_quality = 1000; 327fc0dd0d3SIan Lepore sc->et.et_frequency = sc->clkfreq; 328fc0dd0d3SIan Lepore sc->et.et_min_period = ((uint64_t)ET_MIN_TICKS << 32) / sc->clkfreq; 329fc0dd0d3SIan Lepore sc->et.et_max_period = ((uint64_t)ET_MAX_TICKS << 32) / sc->clkfreq; 330fc0dd0d3SIan Lepore sc->et.et_start = epit_et_start; 331fc0dd0d3SIan Lepore sc->et.et_stop = epit_et_stop; 332fc0dd0d3SIan Lepore sc->et.et_priv = sc; 333fc0dd0d3SIan Lepore et_register(&sc->et); 334fc0dd0d3SIan Lepore 335fc0dd0d3SIan Lepore return (0); 336fc0dd0d3SIan Lepore } 337fc0dd0d3SIan Lepore 338fc0dd0d3SIan Lepore static int 339fc0dd0d3SIan Lepore epit_probe(device_t dev) 340fc0dd0d3SIan Lepore { 341fc0dd0d3SIan Lepore struct resource *memres; 342fc0dd0d3SIan Lepore rman_res_t ioaddr; 343fc0dd0d3SIan Lepore int num_units, rid, unit; 344fc0dd0d3SIan Lepore 345fc0dd0d3SIan Lepore if (!ofw_bus_status_okay(dev)) 346fc0dd0d3SIan Lepore return (ENXIO); 347fc0dd0d3SIan Lepore 348fc0dd0d3SIan Lepore /* 349fc0dd0d3SIan Lepore * The FDT data for imx5 and imx6 EPIT hardware is missing or broken, 350fc0dd0d3SIan Lepore * but it may get fixed some day, so first just do a normal check. We 351fc0dd0d3SIan Lepore * return success if the compatible string matches and we haven't 352fc0dd0d3SIan Lepore * already instantiated the number of units needed on this platform. 353fc0dd0d3SIan Lepore */ 354fc0dd0d3SIan Lepore unit = device_get_unit(dev); 355fc0dd0d3SIan Lepore num_units = ofw_bus_search_compatible(dev, compat_data)->ocd_data; 356fc0dd0d3SIan Lepore if (unit < num_units) { 357fc0dd0d3SIan Lepore device_set_desc(dev, "i.MX EPIT timer"); 358fc0dd0d3SIan Lepore return (BUS_PROBE_DEFAULT); 359fc0dd0d3SIan Lepore } 360fc0dd0d3SIan Lepore 361fc0dd0d3SIan Lepore /* 362fc0dd0d3SIan Lepore * No compat string match, but for imx6 all the data we need is in the 363fc0dd0d3SIan Lepore * node except the compat string, so do our own compatibility check 364fc0dd0d3SIan Lepore * using the device name of the node and the register block address. 365fc0dd0d3SIan Lepore */ 366fc0dd0d3SIan Lepore if (strstr(ofw_bus_get_name(dev), "epit") == NULL) 367fc0dd0d3SIan Lepore return (ENXIO); 368fc0dd0d3SIan Lepore 369fc0dd0d3SIan Lepore rid = 0; 370fc0dd0d3SIan Lepore memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_UNMAPPED); 371fc0dd0d3SIan Lepore if (memres == NULL) 372fc0dd0d3SIan Lepore return (ENXIO); 373fc0dd0d3SIan Lepore ioaddr = rman_get_start(memres); 374fc0dd0d3SIan Lepore bus_free_resource(dev, SYS_RES_MEMORY, memres); 375fc0dd0d3SIan Lepore 376fc0dd0d3SIan Lepore if (imx_soc_family() == 6) { 377fc0dd0d3SIan Lepore if (unit > 0) 378fc0dd0d3SIan Lepore return (ENXIO); 379fc0dd0d3SIan Lepore if (ioaddr != imx6_epit_ioaddr[unit]) 380fc0dd0d3SIan Lepore return (ENXIO); 381fc0dd0d3SIan Lepore } else { 382fc0dd0d3SIan Lepore if (unit > 1) 383fc0dd0d3SIan Lepore return (ENXIO); 384fc0dd0d3SIan Lepore switch (imx_soc_type()) { 385fc0dd0d3SIan Lepore case IMXSOC_51: 386fc0dd0d3SIan Lepore if (ioaddr != imx51_epit_ioaddr[unit]) 387fc0dd0d3SIan Lepore return (ENXIO); 388fc0dd0d3SIan Lepore break; 389fc0dd0d3SIan Lepore case IMXSOC_53: 390fc0dd0d3SIan Lepore if (ioaddr != imx53_epit_ioaddr[unit]) 391fc0dd0d3SIan Lepore return (ENXIO); 392fc0dd0d3SIan Lepore break; 393fc0dd0d3SIan Lepore default: 394fc0dd0d3SIan Lepore return (ENXIO); 395fc0dd0d3SIan Lepore } 396fc0dd0d3SIan Lepore /* 397fc0dd0d3SIan Lepore * XXX Right now we have no way to handle the fact that the 398fc0dd0d3SIan Lepore * entire EPIT node is missing, which means no interrupt data. 399fc0dd0d3SIan Lepore */ 400fc0dd0d3SIan Lepore return (ENXIO); 401fc0dd0d3SIan Lepore } 402fc0dd0d3SIan Lepore 403fc0dd0d3SIan Lepore device_set_desc(dev, "i.MX EPIT timer"); 404fc0dd0d3SIan Lepore return (BUS_PROBE_DEFAULT); 405fc0dd0d3SIan Lepore } 406fc0dd0d3SIan Lepore 407fc0dd0d3SIan Lepore static int 408fc0dd0d3SIan Lepore epit_attach(device_t dev) 409fc0dd0d3SIan Lepore { 410fc0dd0d3SIan Lepore struct epit_softc *sc; 411fc0dd0d3SIan Lepore int err, rid; 412fc0dd0d3SIan Lepore uint32_t clksrc; 413fc0dd0d3SIan Lepore 414fc0dd0d3SIan Lepore sc = device_get_softc(dev); 415fc0dd0d3SIan Lepore sc->dev = dev; 416fc0dd0d3SIan Lepore 417fc0dd0d3SIan Lepore rid = 0; 418fc0dd0d3SIan Lepore sc->memres = bus_alloc_resource_any(sc->dev, SYS_RES_MEMORY, &rid, 419fc0dd0d3SIan Lepore RF_ACTIVE); 420fc0dd0d3SIan Lepore if (sc->memres == NULL) { 421fc0dd0d3SIan Lepore device_printf(sc->dev, "could not allocate registers\n"); 422fc0dd0d3SIan Lepore return (ENXIO); 423fc0dd0d3SIan Lepore } 424fc0dd0d3SIan Lepore 425fc0dd0d3SIan Lepore /* 426fc0dd0d3SIan Lepore * For now, use ipg (66 MHz). Some day we should get this from fdt. 427fc0dd0d3SIan Lepore */ 428fc0dd0d3SIan Lepore clksrc = EPIT_CR_CLKSRC_IPG; 429fc0dd0d3SIan Lepore 430fc0dd0d3SIan Lepore switch (clksrc) { 431fc0dd0d3SIan Lepore default: 432fc0dd0d3SIan Lepore device_printf(dev, 433fc0dd0d3SIan Lepore "Unsupported clock source '%d', using IPG\n", clksrc); 434fc0dd0d3SIan Lepore /* FALLTHROUGH */ 435fc0dd0d3SIan Lepore case EPIT_CR_CLKSRC_IPG: 436fc0dd0d3SIan Lepore sc->clkfreq = imx_ccm_ipg_hz(); 437fc0dd0d3SIan Lepore break; 438fc0dd0d3SIan Lepore case EPIT_CR_CLKSRC_HFCLK: 439fc0dd0d3SIan Lepore sc->clkfreq = imx_ccm_perclk_hz(); 440fc0dd0d3SIan Lepore break; 441fc0dd0d3SIan Lepore case EPIT_CR_CLKSRC_LFCLK: 442fc0dd0d3SIan Lepore sc->clkfreq = 32768; 443fc0dd0d3SIan Lepore break; 444fc0dd0d3SIan Lepore } 445fc0dd0d3SIan Lepore 446fc0dd0d3SIan Lepore /* 447fc0dd0d3SIan Lepore * Init: stop operations and clear all options, then set up options and 448fc0dd0d3SIan Lepore * clock source, then do a soft-reset and wait for it to complete. 449fc0dd0d3SIan Lepore */ 450fc0dd0d3SIan Lepore WR4(sc, EPIT_CR, 0); 451fc0dd0d3SIan Lepore 452fc0dd0d3SIan Lepore sc->ctlreg = 453fc0dd0d3SIan Lepore (clksrc << EPIT_CR_CLKSRC_SHIFT) | /* Use selected clock */ 454fc0dd0d3SIan Lepore EPIT_CR_ENMOD | /* Reload counter on enable */ 455fc0dd0d3SIan Lepore EPIT_CR_RLD | /* Reload counter from LR */ 456fc0dd0d3SIan Lepore EPIT_CR_STOPEN | /* Run in STOP mode */ 457fc0dd0d3SIan Lepore EPIT_CR_WAITEN | /* Run in WAIT mode */ 458fc0dd0d3SIan Lepore EPIT_CR_DBGEN; /* Run in DEBUG mode */ 459fc0dd0d3SIan Lepore 460fc0dd0d3SIan Lepore WR4B(sc, EPIT_CR, sc->ctlreg | EPIT_CR_SWR); 461fc0dd0d3SIan Lepore while (RD4(sc, EPIT_CR) & EPIT_CR_SWR) 462fc0dd0d3SIan Lepore continue; 463fc0dd0d3SIan Lepore 464fc0dd0d3SIan Lepore /* 465fc0dd0d3SIan Lepore * Unit 0 is the timecounter, 1 (if instantiated) is the eventtimer. 466fc0dd0d3SIan Lepore */ 467fc0dd0d3SIan Lepore if (device_get_unit(sc->dev) == 0) 468fc0dd0d3SIan Lepore err = epit_tc_attach(sc); 469fc0dd0d3SIan Lepore else 470fc0dd0d3SIan Lepore err = epit_et_attach(sc); 471fc0dd0d3SIan Lepore 472fc0dd0d3SIan Lepore return (err); 473fc0dd0d3SIan Lepore } 474fc0dd0d3SIan Lepore 475fc0dd0d3SIan Lepore static device_method_t epit_methods[] = { 476fc0dd0d3SIan Lepore DEVMETHOD(device_probe, epit_probe), 477fc0dd0d3SIan Lepore DEVMETHOD(device_attach, epit_attach), 478fc0dd0d3SIan Lepore 479fc0dd0d3SIan Lepore DEVMETHOD_END 480fc0dd0d3SIan Lepore }; 481fc0dd0d3SIan Lepore 482fc0dd0d3SIan Lepore static driver_t epit_driver = { 483fc0dd0d3SIan Lepore "imx_epit", 484fc0dd0d3SIan Lepore epit_methods, 485fc0dd0d3SIan Lepore sizeof(struct epit_softc), 486fc0dd0d3SIan Lepore }; 487fc0dd0d3SIan Lepore 488*ea538dabSJohn Baldwin EARLY_DRIVER_MODULE(imx_epit, simplebus, epit_driver, 0, 0, BUS_PASS_TIMER); 489