14159fbabSIan Lepore /*- 24159fbabSIan Lepore * Copyright (c) 2015 Ian lepore <ian@freebsd.org> 34159fbabSIan Lepore * All rights reserved. 44159fbabSIan Lepore * 54159fbabSIan Lepore * Redistribution and use in source and binary forms, with or without 64159fbabSIan Lepore * modification, are permitted provided that the following conditions 74159fbabSIan Lepore * are met: 84159fbabSIan Lepore * 1. Redistributions of source code must retain the above copyright 94159fbabSIan Lepore * notice, this list of conditions and the following disclaimer. 104159fbabSIan Lepore * 2. Redistributions in binary form must reproduce the above copyright 114159fbabSIan Lepore * notice, this list of conditions and the following disclaimer in the 124159fbabSIan Lepore * documentation and/or other materials provided with the distribution. 134159fbabSIan Lepore * 144159fbabSIan Lepore * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154159fbabSIan Lepore * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164159fbabSIan Lepore * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174159fbabSIan Lepore * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184159fbabSIan Lepore * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194159fbabSIan Lepore * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204159fbabSIan Lepore * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214159fbabSIan Lepore * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224159fbabSIan Lepore * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234159fbabSIan Lepore * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244159fbabSIan Lepore * SUCH DAMAGE. 254159fbabSIan Lepore */ 264159fbabSIan Lepore 274159fbabSIan Lepore /* 284159fbabSIan Lepore * AM335x PPS driver using DMTimer capture. 294159fbabSIan Lepore * 304159fbabSIan Lepore * Note that this PPS driver does not use an interrupt. Instead it uses the 314159fbabSIan Lepore * hardware's ability to latch the timer's count register in response to a 324159fbabSIan Lepore * signal on an IO pin. Each of timers 4-7 have an associated pin, and this 334159fbabSIan Lepore * code allows any one of those to be used. 344159fbabSIan Lepore * 354159fbabSIan Lepore * The timecounter routines in kern_tc.c call the pps poll routine periodically 364159fbabSIan Lepore * to see if a new counter value has been latched. When a new value has been 374159fbabSIan Lepore * latched, the only processing done in the poll routine is to capture the 384159fbabSIan Lepore * current set of timecounter timehands (done with pps_capture()) and the 394159fbabSIan Lepore * latched value from the timer. The remaining work (done by pps_event() while 404159fbabSIan Lepore * holding a mutex) is scheduled to be done later in a non-interrupt context. 414159fbabSIan Lepore */ 424159fbabSIan Lepore 434159fbabSIan Lepore #include <sys/cdefs.h> 444159fbabSIan Lepore __FBSDID("$FreeBSD$"); 454159fbabSIan Lepore 460050ea24SMichal Meloun #include "opt_platform.h" 470050ea24SMichal Meloun 484159fbabSIan Lepore #include <sys/param.h> 494159fbabSIan Lepore #include <sys/systm.h> 504159fbabSIan Lepore #include <sys/bus.h> 514159fbabSIan Lepore #include <sys/conf.h> 524159fbabSIan Lepore #include <sys/kernel.h> 5353117a36SIan Lepore #include <sys/lock.h> 544159fbabSIan Lepore #include <sys/module.h> 554159fbabSIan Lepore #include <sys/malloc.h> 562d5913e4SIan Lepore #include <sys/mutex.h> 574159fbabSIan Lepore #include <sys/rman.h> 584159fbabSIan Lepore #include <sys/timepps.h> 594159fbabSIan Lepore #include <sys/timetc.h> 604159fbabSIan Lepore #include <machine/bus.h> 614159fbabSIan Lepore 624159fbabSIan Lepore #include <dev/ofw/openfirm.h> 634159fbabSIan Lepore #include <dev/ofw/ofw_bus.h> 644159fbabSIan Lepore #include <dev/ofw/ofw_bus_subr.h> 650050ea24SMichal Meloun #include <dev/extres/clk/clk.h> 664159fbabSIan Lepore 670050ea24SMichal Meloun #include <arm/ti/ti_sysc.h> 684159fbabSIan Lepore #include <arm/ti/ti_pinmux.h> 694159fbabSIan Lepore #include <arm/ti/am335x/am335x_scm_padconf.h> 704159fbabSIan Lepore 714159fbabSIan Lepore #include "am335x_dmtreg.h" 724159fbabSIan Lepore 734159fbabSIan Lepore #define PPS_CDEV_NAME "dmtpps" 744159fbabSIan Lepore 754159fbabSIan Lepore struct dmtpps_softc { 764159fbabSIan Lepore device_t dev; 774159fbabSIan Lepore int mem_rid; 784159fbabSIan Lepore struct resource * mem_res; 794159fbabSIan Lepore int tmr_num; /* N from hwmod str "timerN" */ 804159fbabSIan Lepore char tmr_name[12]; /* "DMTimerN" */ 814159fbabSIan Lepore uint32_t tclr; /* Cached TCLR register. */ 824159fbabSIan Lepore struct timecounter tc; 834159fbabSIan Lepore int pps_curmode; /* Edge mode now set in hw. */ 844159fbabSIan Lepore struct cdev * pps_cdev; 854159fbabSIan Lepore struct pps_state pps_state; 864159fbabSIan Lepore struct mtx pps_mtx; 870050ea24SMichal Meloun clk_t clk_fck; 880050ea24SMichal Meloun uint64_t sysclk_freq; 894159fbabSIan Lepore }; 904159fbabSIan Lepore 914159fbabSIan Lepore static int dmtpps_tmr_num; /* Set by probe() */ 924159fbabSIan Lepore 934159fbabSIan Lepore /* List of compatible strings for FDT tree */ 944159fbabSIan Lepore static struct ofw_compat_data compat_data[] = { 954159fbabSIan Lepore {"ti,am335x-timer", 1}, 964159fbabSIan Lepore {"ti,am335x-timer-1ms", 1}, 974159fbabSIan Lepore {NULL, 0}, 984159fbabSIan Lepore }; 99*519b64e2SMark Johnston SIMPLEBUS_PNP_INFO(compat_data); 1004159fbabSIan Lepore 1014159fbabSIan Lepore /* 1024159fbabSIan Lepore * A table relating pad names to the hardware timer number they can be mux'd to. 1034159fbabSIan Lepore */ 1044159fbabSIan Lepore struct padinfo { 1054159fbabSIan Lepore char * ballname; 1064159fbabSIan Lepore int tmr_num; 1074159fbabSIan Lepore }; 1084159fbabSIan Lepore static struct padinfo dmtpps_padinfo[] = { 1094159fbabSIan Lepore {"GPMC_ADVn_ALE", 4}, 1104159fbabSIan Lepore {"I2C0_SDA", 4}, 1114159fbabSIan Lepore {"MII1_TX_EN", 4}, 1124159fbabSIan Lepore {"XDMA_EVENT_INTR0", 4}, 1134159fbabSIan Lepore {"GPMC_BEn0_CLE", 5}, 1144159fbabSIan Lepore {"MDC", 5}, 1154159fbabSIan Lepore {"MMC0_DAT3", 5}, 1164159fbabSIan Lepore {"UART1_RTSn", 5}, 1174159fbabSIan Lepore {"GPMC_WEn", 6}, 1184159fbabSIan Lepore {"MDIO", 6}, 1194159fbabSIan Lepore {"MMC0_DAT2", 6}, 1204159fbabSIan Lepore {"UART1_CTSn", 6}, 1214159fbabSIan Lepore {"GPMC_OEn_REn", 7}, 1224159fbabSIan Lepore {"I2C0_SCL", 7}, 1234159fbabSIan Lepore {"UART0_CTSn", 7}, 1244159fbabSIan Lepore {"XDMA_EVENT_INTR1", 7}, 1254159fbabSIan Lepore {NULL, 0} 1264159fbabSIan Lepore }; 1274159fbabSIan Lepore 1284159fbabSIan Lepore /* 1294159fbabSIan Lepore * This is either brilliantly user-friendly, or utterly lame... 1304159fbabSIan Lepore * 1314159fbabSIan Lepore * The am335x chip is used on the popular Beaglebone boards. Those boards have 1324159fbabSIan Lepore * pins for all four capture-capable timers available on the P8 header. Allow 1334159fbabSIan Lepore * users to configure the input pin by giving the name of the header pin. 1344159fbabSIan Lepore */ 1354159fbabSIan Lepore struct nicknames { 1364159fbabSIan Lepore const char * nick; 1374159fbabSIan Lepore const char * name; 1384159fbabSIan Lepore }; 1394159fbabSIan Lepore static struct nicknames dmtpps_pin_nicks[] = { 1404159fbabSIan Lepore {"P8-7", "GPMC_ADVn_ALE"}, 1414159fbabSIan Lepore {"P8-9", "GPMC_BEn0_CLE"}, 1424159fbabSIan Lepore {"P8-10", "GPMC_WEn"}, 1434159fbabSIan Lepore {"P8-8", "GPMC_OEn_REn",}, 1444159fbabSIan Lepore {NULL, NULL} 1454159fbabSIan Lepore }; 1464159fbabSIan Lepore 1474159fbabSIan Lepore #define DMTIMER_READ4(sc, reg) bus_read_4((sc)->mem_res, (reg)) 1484159fbabSIan Lepore #define DMTIMER_WRITE4(sc, reg, val) bus_write_4((sc)->mem_res, (reg), (val)) 1494159fbabSIan Lepore 1504159fbabSIan Lepore /* 1514159fbabSIan Lepore * Translate a short friendly case-insensitive name to its canonical name. 1524159fbabSIan Lepore */ 1534159fbabSIan Lepore static const char * 1544159fbabSIan Lepore dmtpps_translate_nickname(const char *nick) 1554159fbabSIan Lepore { 1564159fbabSIan Lepore struct nicknames *nn; 1574159fbabSIan Lepore 1584159fbabSIan Lepore for (nn = dmtpps_pin_nicks; nn->nick != NULL; nn++) 1594159fbabSIan Lepore if (strcasecmp(nick, nn->nick) == 0) 1604159fbabSIan Lepore return nn->name; 1614159fbabSIan Lepore return (nick); 1624159fbabSIan Lepore } 1634159fbabSIan Lepore 1644159fbabSIan Lepore /* 1654159fbabSIan Lepore * See if our tunable is set to the name of the input pin. If not, that's NOT 1664159fbabSIan Lepore * an error, return 0. If so, try to configure that pin as a timer capture 1674159fbabSIan Lepore * input pin, and if that works, then we have our timer unit number and if it 1684159fbabSIan Lepore * fails that IS an error, return -1. 1694159fbabSIan Lepore */ 1704159fbabSIan Lepore static int 17159249a51SAndrew Turner dmtpps_find_tmr_num_by_tunable(void) 1724159fbabSIan Lepore { 1734159fbabSIan Lepore struct padinfo *pi; 1744159fbabSIan Lepore char iname[20]; 1754159fbabSIan Lepore char muxmode[12]; 1764159fbabSIan Lepore const char * ballname; 1774159fbabSIan Lepore int err; 1784159fbabSIan Lepore 1794159fbabSIan Lepore if (!TUNABLE_STR_FETCH("hw.am335x_dmtpps.input", iname, sizeof(iname))) 1804159fbabSIan Lepore return (0); 1814159fbabSIan Lepore ballname = dmtpps_translate_nickname(iname); 1824159fbabSIan Lepore for (pi = dmtpps_padinfo; pi->ballname != NULL; pi++) { 1834159fbabSIan Lepore if (strcmp(ballname, pi->ballname) != 0) 1844159fbabSIan Lepore continue; 1854159fbabSIan Lepore snprintf(muxmode, sizeof(muxmode), "timer%d", pi->tmr_num); 1864159fbabSIan Lepore err = ti_pinmux_padconf_set(pi->ballname, muxmode, 1874159fbabSIan Lepore PADCONF_INPUT); 1884159fbabSIan Lepore if (err != 0) { 1894159fbabSIan Lepore printf("am335x_dmtpps: unable to configure capture pin " 1904159fbabSIan Lepore "for %s to input mode\n", muxmode); 1914159fbabSIan Lepore return (-1); 1924159fbabSIan Lepore } else if (bootverbose) { 1934159fbabSIan Lepore printf("am335x_dmtpps: configured pin %s as input " 1944159fbabSIan Lepore "for %s\n", iname, muxmode); 1954159fbabSIan Lepore } 1964159fbabSIan Lepore return (pi->tmr_num); 1974159fbabSIan Lepore } 1984159fbabSIan Lepore 1994159fbabSIan Lepore /* Invalid name in the tunable, that's an error. */ 2004159fbabSIan Lepore printf("am335x_dmtpps: unknown pin name '%s'\n", iname); 2014159fbabSIan Lepore return (-1); 2024159fbabSIan Lepore } 2034159fbabSIan Lepore 2044159fbabSIan Lepore /* 2054159fbabSIan Lepore * Ask the pinmux driver whether any pin has been configured as a TIMER4..TIMER7 2064159fbabSIan Lepore * input pin. If so, return the timer number, if not return 0. 2074159fbabSIan Lepore */ 2084159fbabSIan Lepore static int 20959249a51SAndrew Turner dmtpps_find_tmr_num_by_padconf(void) 2104159fbabSIan Lepore { 2114159fbabSIan Lepore int err; 2124159fbabSIan Lepore unsigned int padstate; 2134159fbabSIan Lepore const char * padmux; 2144159fbabSIan Lepore struct padinfo *pi; 2154159fbabSIan Lepore char muxmode[12]; 2164159fbabSIan Lepore 2174159fbabSIan Lepore for (pi = dmtpps_padinfo; pi->ballname != NULL; pi++) { 2184159fbabSIan Lepore err = ti_pinmux_padconf_get(pi->ballname, &padmux, &padstate); 2194159fbabSIan Lepore snprintf(muxmode, sizeof(muxmode), "timer%d", pi->tmr_num); 2204159fbabSIan Lepore if (err == 0 && (padstate & RXACTIVE) != 0 && 2214159fbabSIan Lepore strcmp(muxmode, padmux) == 0) 2224159fbabSIan Lepore return (pi->tmr_num); 2234159fbabSIan Lepore } 2244159fbabSIan Lepore /* Nothing found, not an error. */ 2254159fbabSIan Lepore return (0); 2264159fbabSIan Lepore } 2274159fbabSIan Lepore 2284159fbabSIan Lepore /* 2294159fbabSIan Lepore * Figure out which hardware timer number to use based on input pin 2304159fbabSIan Lepore * configuration. This is done just once, the first time probe() runs. 2314159fbabSIan Lepore */ 2324159fbabSIan Lepore static int 23359249a51SAndrew Turner dmtpps_find_tmr_num(void) 2344159fbabSIan Lepore { 2354159fbabSIan Lepore int tmr_num; 2364159fbabSIan Lepore 2374159fbabSIan Lepore if ((tmr_num = dmtpps_find_tmr_num_by_tunable()) == 0) 2384159fbabSIan Lepore tmr_num = dmtpps_find_tmr_num_by_padconf(); 2394159fbabSIan Lepore 2404159fbabSIan Lepore if (tmr_num <= 0) { 2414159fbabSIan Lepore printf("am335x_dmtpps: PPS driver not enabled: unable to find " 2424159fbabSIan Lepore "or configure a capture input pin\n"); 2434159fbabSIan Lepore tmr_num = -1; /* Must return non-zero to prevent re-probing. */ 2444159fbabSIan Lepore } 2454159fbabSIan Lepore return (tmr_num); 2464159fbabSIan Lepore } 2474159fbabSIan Lepore 2484159fbabSIan Lepore static void 2494159fbabSIan Lepore dmtpps_set_hw_capture(struct dmtpps_softc *sc, bool force_off) 2504159fbabSIan Lepore { 2514159fbabSIan Lepore int newmode; 2524159fbabSIan Lepore 2534159fbabSIan Lepore if (force_off) 2544159fbabSIan Lepore newmode = 0; 2554159fbabSIan Lepore else 2564159fbabSIan Lepore newmode = sc->pps_state.ppsparam.mode & PPS_CAPTUREASSERT; 2574159fbabSIan Lepore 2584159fbabSIan Lepore if (newmode == sc->pps_curmode) 2594159fbabSIan Lepore return; 2604159fbabSIan Lepore sc->pps_curmode = newmode; 2614159fbabSIan Lepore 2624159fbabSIan Lepore if (newmode == PPS_CAPTUREASSERT) 2634159fbabSIan Lepore sc->tclr |= DMT_TCLR_CAPTRAN_LOHI; 2644159fbabSIan Lepore else 2654159fbabSIan Lepore sc->tclr &= ~DMT_TCLR_CAPTRAN_MASK; 2664159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); 2674159fbabSIan Lepore } 2684159fbabSIan Lepore 2694159fbabSIan Lepore static unsigned 2704159fbabSIan Lepore dmtpps_get_timecount(struct timecounter *tc) 2714159fbabSIan Lepore { 2724159fbabSIan Lepore struct dmtpps_softc *sc; 2734159fbabSIan Lepore 2744159fbabSIan Lepore sc = tc->tc_priv; 2754159fbabSIan Lepore 2764159fbabSIan Lepore return (DMTIMER_READ4(sc, DMT_TCRR)); 2774159fbabSIan Lepore } 2784159fbabSIan Lepore 2794159fbabSIan Lepore static void 2804159fbabSIan Lepore dmtpps_poll(struct timecounter *tc) 2814159fbabSIan Lepore { 2824159fbabSIan Lepore struct dmtpps_softc *sc; 2834159fbabSIan Lepore 2844159fbabSIan Lepore sc = tc->tc_priv; 2854159fbabSIan Lepore 2864159fbabSIan Lepore /* 2874159fbabSIan Lepore * If a new value has been latched we've got a PPS event. Capture the 2884159fbabSIan Lepore * timecounter data, then override the capcount field (pps_capture() 2894159fbabSIan Lepore * populates it from the current DMT_TCRR register) with the latched 2904159fbabSIan Lepore * value from the TCAR1 register. 2914159fbabSIan Lepore * 2924159fbabSIan Lepore * Note that we don't have the TCAR interrupt enabled, but the hardware 2934159fbabSIan Lepore * still provides the status bits in the "RAW" status register even when 2944159fbabSIan Lepore * they're masked from generating an irq. However, when clearing the 2954159fbabSIan Lepore * TCAR status to re-arm the capture for the next second, we have to 2964159fbabSIan Lepore * write to the IRQ status register, not the RAW register. Quirky. 297192122bdSIan Lepore * 298192122bdSIan Lepore * We do not need to hold a lock while capturing the pps data, because 299192122bdSIan Lepore * it is captured into an area of the pps_state struct which is read 300192122bdSIan Lepore * only by pps_event(). We do need to hold a lock while calling 301192122bdSIan Lepore * pps_event(), because it manipulates data which is also accessed from 302192122bdSIan Lepore * the ioctl(2) context by userland processes. 3034159fbabSIan Lepore */ 3044159fbabSIan Lepore if (DMTIMER_READ4(sc, DMT_IRQSTATUS_RAW) & DMT_IRQ_TCAR) { 3054159fbabSIan Lepore pps_capture(&sc->pps_state); 3064159fbabSIan Lepore sc->pps_state.capcount = DMTIMER_READ4(sc, DMT_TCAR1); 3074159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_TCAR); 3084159fbabSIan Lepore 309192122bdSIan Lepore mtx_lock_spin(&sc->pps_mtx); 3104159fbabSIan Lepore pps_event(&sc->pps_state, PPS_CAPTUREASSERT); 311192122bdSIan Lepore mtx_unlock_spin(&sc->pps_mtx); 312192122bdSIan Lepore } 3134159fbabSIan Lepore } 3144159fbabSIan Lepore 3154159fbabSIan Lepore static int 3164159fbabSIan Lepore dmtpps_open(struct cdev *dev, int flags, int fmt, 3174159fbabSIan Lepore struct thread *td) 3184159fbabSIan Lepore { 3194159fbabSIan Lepore struct dmtpps_softc *sc; 3204159fbabSIan Lepore 3214159fbabSIan Lepore sc = dev->si_drv1; 3224159fbabSIan Lepore 3234159fbabSIan Lepore /* 3244159fbabSIan Lepore * Begin polling for pps and enable capture in the hardware whenever the 3254159fbabSIan Lepore * device is open. Doing this stuff again is harmless if this isn't the 3264159fbabSIan Lepore * first open. 3274159fbabSIan Lepore */ 3284159fbabSIan Lepore sc->tc.tc_poll_pps = dmtpps_poll; 3294159fbabSIan Lepore dmtpps_set_hw_capture(sc, false); 3304159fbabSIan Lepore 3314159fbabSIan Lepore return 0; 3324159fbabSIan Lepore } 3334159fbabSIan Lepore 3344159fbabSIan Lepore static int 3354159fbabSIan Lepore dmtpps_close(struct cdev *dev, int flags, int fmt, 3364159fbabSIan Lepore struct thread *td) 3374159fbabSIan Lepore { 3384159fbabSIan Lepore struct dmtpps_softc *sc; 3394159fbabSIan Lepore 3404159fbabSIan Lepore sc = dev->si_drv1; 3414159fbabSIan Lepore 3424159fbabSIan Lepore /* 3434159fbabSIan Lepore * Stop polling and disable capture on last close. Use the force-off 3444159fbabSIan Lepore * flag to override the configured mode and turn off the hardware. 3454159fbabSIan Lepore */ 3464159fbabSIan Lepore sc->tc.tc_poll_pps = NULL; 3474159fbabSIan Lepore dmtpps_set_hw_capture(sc, true); 3484159fbabSIan Lepore 3494159fbabSIan Lepore return 0; 3504159fbabSIan Lepore } 3514159fbabSIan Lepore 3524159fbabSIan Lepore static int 3534159fbabSIan Lepore dmtpps_ioctl(struct cdev *dev, u_long cmd, caddr_t data, 3544159fbabSIan Lepore int flags, struct thread *td) 3554159fbabSIan Lepore { 3564159fbabSIan Lepore struct dmtpps_softc *sc; 3574159fbabSIan Lepore int err; 3584159fbabSIan Lepore 3594159fbabSIan Lepore sc = dev->si_drv1; 3604159fbabSIan Lepore 3614159fbabSIan Lepore /* Let the kernel do the heavy lifting for ioctl. */ 362192122bdSIan Lepore mtx_lock_spin(&sc->pps_mtx); 3634159fbabSIan Lepore err = pps_ioctl(cmd, data, &sc->pps_state); 364192122bdSIan Lepore mtx_unlock_spin(&sc->pps_mtx); 3654159fbabSIan Lepore if (err != 0) 3664159fbabSIan Lepore return (err); 3674159fbabSIan Lepore 3684159fbabSIan Lepore /* 3694159fbabSIan Lepore * The capture mode could have changed, set the hardware to whatever 3704159fbabSIan Lepore * mode is now current. Effectively a no-op if nothing changed. 3714159fbabSIan Lepore */ 3724159fbabSIan Lepore dmtpps_set_hw_capture(sc, false); 3734159fbabSIan Lepore 3744159fbabSIan Lepore return (err); 3754159fbabSIan Lepore } 3764159fbabSIan Lepore 3774159fbabSIan Lepore static struct cdevsw dmtpps_cdevsw = { 3784159fbabSIan Lepore .d_version = D_VERSION, 3794159fbabSIan Lepore .d_open = dmtpps_open, 3804159fbabSIan Lepore .d_close = dmtpps_close, 3814159fbabSIan Lepore .d_ioctl = dmtpps_ioctl, 3824159fbabSIan Lepore .d_name = PPS_CDEV_NAME, 3834159fbabSIan Lepore }; 3844159fbabSIan Lepore 3854159fbabSIan Lepore static int 3864159fbabSIan Lepore dmtpps_probe(device_t dev) 3874159fbabSIan Lepore { 3884159fbabSIan Lepore char strbuf[64]; 3894159fbabSIan Lepore int tmr_num; 3900050ea24SMichal Meloun uint64_t rev_address; 3914159fbabSIan Lepore 3924159fbabSIan Lepore if (!ofw_bus_status_okay(dev)) 3934159fbabSIan Lepore return (ENXIO); 3944159fbabSIan Lepore 3954159fbabSIan Lepore if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 3964159fbabSIan Lepore return (ENXIO); 3974159fbabSIan Lepore 3984159fbabSIan Lepore /* 3994159fbabSIan Lepore * If we haven't chosen which hardware timer to use yet, go do that now. 4004159fbabSIan Lepore * We need to know that to decide whether to return success for this 4014159fbabSIan Lepore * hardware timer instance or not. 4024159fbabSIan Lepore */ 4034159fbabSIan Lepore if (dmtpps_tmr_num == 0) 4044159fbabSIan Lepore dmtpps_tmr_num = dmtpps_find_tmr_num(); 4054159fbabSIan Lepore 4064159fbabSIan Lepore /* 4074159fbabSIan Lepore * Figure out which hardware timer is being probed and see if it matches 4084159fbabSIan Lepore * the configured timer number determined earlier. 4094159fbabSIan Lepore */ 4100050ea24SMichal Meloun rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); 4110050ea24SMichal Meloun switch (rev_address) { 4120050ea24SMichal Meloun case DMTIMER1_1MS_REV: 4130050ea24SMichal Meloun tmr_num = 1; 4140050ea24SMichal Meloun break; 4150050ea24SMichal Meloun case DMTIMER2_REV: 4160050ea24SMichal Meloun tmr_num = 2; 4170050ea24SMichal Meloun break; 4180050ea24SMichal Meloun case DMTIMER3_REV: 4190050ea24SMichal Meloun tmr_num = 3; 4200050ea24SMichal Meloun break; 4210050ea24SMichal Meloun case DMTIMER4_REV: 4220050ea24SMichal Meloun tmr_num = 4; 4230050ea24SMichal Meloun break; 4240050ea24SMichal Meloun case DMTIMER5_REV: 4250050ea24SMichal Meloun tmr_num = 5; 4260050ea24SMichal Meloun break; 4270050ea24SMichal Meloun case DMTIMER6_REV: 4280050ea24SMichal Meloun tmr_num = 6; 4290050ea24SMichal Meloun break; 4300050ea24SMichal Meloun case DMTIMER7_REV: 4310050ea24SMichal Meloun tmr_num = 7; 4320050ea24SMichal Meloun break; 4330050ea24SMichal Meloun default: 4340050ea24SMichal Meloun return (ENXIO); 4350050ea24SMichal Meloun } 4360050ea24SMichal Meloun 4374159fbabSIan Lepore if (dmtpps_tmr_num != tmr_num) 4384159fbabSIan Lepore return (ENXIO); 4394159fbabSIan Lepore 4404159fbabSIan Lepore snprintf(strbuf, sizeof(strbuf), "AM335x PPS-Capture DMTimer%d", 4414159fbabSIan Lepore tmr_num); 4424159fbabSIan Lepore device_set_desc_copy(dev, strbuf); 4434159fbabSIan Lepore 4444159fbabSIan Lepore return(BUS_PROBE_DEFAULT); 4454159fbabSIan Lepore } 4464159fbabSIan Lepore 4474159fbabSIan Lepore static int 4484159fbabSIan Lepore dmtpps_attach(device_t dev) 4494159fbabSIan Lepore { 4504159fbabSIan Lepore struct dmtpps_softc *sc; 451192122bdSIan Lepore struct make_dev_args mda; 4520050ea24SMichal Meloun int err; 4530050ea24SMichal Meloun clk_t sys_clkin; 4540050ea24SMichal Meloun uint64_t rev_address; 4554159fbabSIan Lepore 4564159fbabSIan Lepore sc = device_get_softc(dev); 4574159fbabSIan Lepore sc->dev = dev; 4584159fbabSIan Lepore 4590050ea24SMichal Meloun /* Figure out which hardware timer this is and set the name string. */ 4600050ea24SMichal Meloun rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); 4610050ea24SMichal Meloun switch (rev_address) { 4620050ea24SMichal Meloun case DMTIMER1_1MS_REV: 4630050ea24SMichal Meloun sc->tmr_num = 1; 4640050ea24SMichal Meloun break; 4650050ea24SMichal Meloun case DMTIMER2_REV: 4660050ea24SMichal Meloun sc->tmr_num = 2; 4670050ea24SMichal Meloun break; 4680050ea24SMichal Meloun case DMTIMER3_REV: 4690050ea24SMichal Meloun sc->tmr_num = 3; 4700050ea24SMichal Meloun break; 4710050ea24SMichal Meloun case DMTIMER4_REV: 4720050ea24SMichal Meloun sc->tmr_num = 4; 4730050ea24SMichal Meloun break; 4740050ea24SMichal Meloun case DMTIMER5_REV: 4750050ea24SMichal Meloun sc->tmr_num = 5; 4760050ea24SMichal Meloun break; 4770050ea24SMichal Meloun case DMTIMER6_REV: 4780050ea24SMichal Meloun sc->tmr_num = 6; 4790050ea24SMichal Meloun break; 4800050ea24SMichal Meloun case DMTIMER7_REV: 4810050ea24SMichal Meloun sc->tmr_num = 7; 4820050ea24SMichal Meloun break; 4830050ea24SMichal Meloun } 4840050ea24SMichal Meloun snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); 4850050ea24SMichal Meloun 4860050ea24SMichal Meloun /* expect one clock */ 4870050ea24SMichal Meloun err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck); 4880050ea24SMichal Meloun if (err != 0) { 4890050ea24SMichal Meloun device_printf(dev, "Cant find clock index 0. err: %d\n", err); 4900050ea24SMichal Meloun return (ENXIO); 4910050ea24SMichal Meloun } 4920050ea24SMichal Meloun 4930050ea24SMichal Meloun err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin); 4940050ea24SMichal Meloun if (err != 0) { 4950050ea24SMichal Meloun device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err); 4960050ea24SMichal Meloun return (ENXIO); 4970050ea24SMichal Meloun } 4980050ea24SMichal Meloun 4990050ea24SMichal Meloun /* Select M_OSC as DPLL parent */ 5000050ea24SMichal Meloun err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin); 5010050ea24SMichal Meloun if (err != 0) { 5020050ea24SMichal Meloun device_printf(dev, "Cant set mux to CLK_M_OSC\n"); 5030050ea24SMichal Meloun return (ENXIO); 5040050ea24SMichal Meloun } 5054159fbabSIan Lepore 5064159fbabSIan Lepore /* Enable clocks and power on the device. */ 5070050ea24SMichal Meloun err = ti_sysc_clock_enable(device_get_parent(dev)); 5080050ea24SMichal Meloun if (err != 0) { 5090050ea24SMichal Meloun device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err); 5104159fbabSIan Lepore return (ENXIO); 5110050ea24SMichal Meloun } 5124159fbabSIan Lepore 5130050ea24SMichal Meloun /* Get the base clock frequency. */ 5140050ea24SMichal Meloun err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq); 5150050ea24SMichal Meloun if (err != 0) { 5160050ea24SMichal Meloun device_printf(dev, "Cant get sysclk frequency, err %d\n", err); 5170050ea24SMichal Meloun return (ENXIO); 5180050ea24SMichal Meloun } 5194159fbabSIan Lepore /* Request the memory resources. */ 5204159fbabSIan Lepore sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 5214159fbabSIan Lepore &sc->mem_rid, RF_ACTIVE); 5224159fbabSIan Lepore if (sc->mem_res == NULL) { 5234159fbabSIan Lepore return (ENXIO); 5244159fbabSIan Lepore } 5254159fbabSIan Lepore 52628b3a4a6SIan Lepore /* 52728b3a4a6SIan Lepore * Configure the timer pulse/capture pin to input/capture mode. This is 52828b3a4a6SIan Lepore * required in addition to configuring the pin as input with the pinmux 52928b3a4a6SIan Lepore * controller (which was done via fdt data or tunable at probe time). 53028b3a4a6SIan Lepore */ 53128b3a4a6SIan Lepore sc->tclr = DMT_TCLR_GPO_CFG; 53228b3a4a6SIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); 53328b3a4a6SIan Lepore 5344159fbabSIan Lepore /* Set up timecounter hardware, start it. */ 5354159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TSICR, DMT_TSICR_RESET); 5364159fbabSIan Lepore while (DMTIMER_READ4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET) 5374159fbabSIan Lepore continue; 5384159fbabSIan Lepore 5394159fbabSIan Lepore sc->tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD; 5404159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TLDR, 0); 5414159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCRR, 0); 5424159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr); 5434159fbabSIan Lepore 5444159fbabSIan Lepore /* Register the timecounter. */ 5454159fbabSIan Lepore sc->tc.tc_name = sc->tmr_name; 5464159fbabSIan Lepore sc->tc.tc_get_timecount = dmtpps_get_timecount; 5474159fbabSIan Lepore sc->tc.tc_counter_mask = ~0u; 5480050ea24SMichal Meloun sc->tc.tc_frequency = sc->sysclk_freq; 5494159fbabSIan Lepore sc->tc.tc_quality = 1000; 5504159fbabSIan Lepore sc->tc.tc_priv = sc; 5514159fbabSIan Lepore 5524159fbabSIan Lepore tc_init(&sc->tc); 5534159fbabSIan Lepore 5544159fbabSIan Lepore /* 5554159fbabSIan Lepore * Indicate our PPS capabilities. Have the kernel init its part of the 5564159fbabSIan Lepore * pps_state struct and add its capabilities. 5574159fbabSIan Lepore * 5584159fbabSIan Lepore * While the hardware has a mode to capture each edge, it's not clear we 5594159fbabSIan Lepore * can use it that way, because there's only a single interrupt/status 5604159fbabSIan Lepore * bit to say something was captured, but not which edge it was. For 5614159fbabSIan Lepore * now, just say we can only capture assert events (the positive-going 5624159fbabSIan Lepore * edge of the pulse). 5634159fbabSIan Lepore */ 564192122bdSIan Lepore mtx_init(&sc->pps_mtx, "dmtpps", NULL, MTX_SPIN); 565192122bdSIan Lepore sc->pps_state.flags = PPSFLAG_MTX_SPIN; 5664159fbabSIan Lepore sc->pps_state.ppscap = PPS_CAPTUREASSERT; 5674159fbabSIan Lepore sc->pps_state.driver_abi = PPS_ABI_VERSION; 5684159fbabSIan Lepore sc->pps_state.driver_mtx = &sc->pps_mtx; 5694159fbabSIan Lepore pps_init_abi(&sc->pps_state); 5704159fbabSIan Lepore 5714159fbabSIan Lepore /* Create the PPS cdev. */ 572192122bdSIan Lepore make_dev_args_init(&mda); 573192122bdSIan Lepore mda.mda_flags = MAKEDEV_WAITOK; 574192122bdSIan Lepore mda.mda_devsw = &dmtpps_cdevsw; 575192122bdSIan Lepore mda.mda_cr = NULL; 576192122bdSIan Lepore mda.mda_uid = UID_ROOT; 577192122bdSIan Lepore mda.mda_gid = GID_WHEEL; 578192122bdSIan Lepore mda.mda_mode = 0600; 579192122bdSIan Lepore mda.mda_unit = device_get_unit(dev); 580192122bdSIan Lepore mda.mda_si_drv1 = sc; 581192122bdSIan Lepore if ((err = make_dev_s(&mda, &sc->pps_cdev, PPS_CDEV_NAME)) != 0) { 582192122bdSIan Lepore device_printf(dev, "Failed to create cdev %s\n", PPS_CDEV_NAME); 583192122bdSIan Lepore return (err); 584192122bdSIan Lepore } 5854159fbabSIan Lepore 5864159fbabSIan Lepore if (bootverbose) 5874159fbabSIan Lepore device_printf(sc->dev, "Using %s for PPS device /dev/%s\n", 5884159fbabSIan Lepore sc->tmr_name, PPS_CDEV_NAME); 5894159fbabSIan Lepore 5904159fbabSIan Lepore return (0); 5914159fbabSIan Lepore } 5924159fbabSIan Lepore 5934159fbabSIan Lepore static int 5944159fbabSIan Lepore dmtpps_detach(device_t dev) 5954159fbabSIan Lepore { 5964159fbabSIan Lepore 5974159fbabSIan Lepore /* 5984159fbabSIan Lepore * There is no way to remove a timecounter once it has been registered, 5994159fbabSIan Lepore * even if it's not in use, so we can never detach. If we were 6004159fbabSIan Lepore * dynamically loaded as a module this will prevent unloading. 6014159fbabSIan Lepore */ 6024159fbabSIan Lepore return (EBUSY); 6034159fbabSIan Lepore } 6044159fbabSIan Lepore 6054159fbabSIan Lepore static device_method_t dmtpps_methods[] = { 6064159fbabSIan Lepore DEVMETHOD(device_probe, dmtpps_probe), 6074159fbabSIan Lepore DEVMETHOD(device_attach, dmtpps_attach), 6084159fbabSIan Lepore DEVMETHOD(device_detach, dmtpps_detach), 6094159fbabSIan Lepore { 0, 0 } 6104159fbabSIan Lepore }; 6114159fbabSIan Lepore 6124159fbabSIan Lepore static driver_t dmtpps_driver = { 6134159fbabSIan Lepore "am335x_dmtpps", 6144159fbabSIan Lepore dmtpps_methods, 6154159fbabSIan Lepore sizeof(struct dmtpps_softc), 6164159fbabSIan Lepore }; 6174159fbabSIan Lepore 6184159fbabSIan Lepore static devclass_t dmtpps_devclass; 6194159fbabSIan Lepore 6204159fbabSIan Lepore DRIVER_MODULE(am335x_dmtpps, simplebus, dmtpps_driver, dmtpps_devclass, 0, 0); 6210050ea24SMichal Meloun MODULE_DEPEND(am335x_dmtpps, ti_sysc, 1, 1, 1); 622