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>
440050ea24SMichal Meloun #include "opt_platform.h"
450050ea24SMichal Meloun
464159fbabSIan Lepore #include <sys/param.h>
474159fbabSIan Lepore #include <sys/systm.h>
484159fbabSIan Lepore #include <sys/bus.h>
494159fbabSIan Lepore #include <sys/conf.h>
504159fbabSIan Lepore #include <sys/kernel.h>
5153117a36SIan Lepore #include <sys/lock.h>
524159fbabSIan Lepore #include <sys/module.h>
534159fbabSIan Lepore #include <sys/malloc.h>
542d5913e4SIan Lepore #include <sys/mutex.h>
554159fbabSIan Lepore #include <sys/rman.h>
564159fbabSIan Lepore #include <sys/timepps.h>
574159fbabSIan Lepore #include <sys/timetc.h>
584159fbabSIan Lepore #include <machine/bus.h>
594159fbabSIan Lepore
604159fbabSIan Lepore #include <dev/ofw/openfirm.h>
614159fbabSIan Lepore #include <dev/ofw/ofw_bus.h>
624159fbabSIan Lepore #include <dev/ofw/ofw_bus_subr.h>
63be82b3a0SEmmanuel Vadot #include <dev/clk/clk.h>
644159fbabSIan Lepore
650050ea24SMichal Meloun #include <arm/ti/ti_sysc.h>
664159fbabSIan Lepore #include <arm/ti/ti_pinmux.h>
674159fbabSIan Lepore #include <arm/ti/am335x/am335x_scm_padconf.h>
684159fbabSIan Lepore
694159fbabSIan Lepore #include "am335x_dmtreg.h"
704159fbabSIan Lepore
714159fbabSIan Lepore #define PPS_CDEV_NAME "dmtpps"
724159fbabSIan Lepore
734159fbabSIan Lepore struct dmtpps_softc {
744159fbabSIan Lepore device_t dev;
754159fbabSIan Lepore int mem_rid;
764159fbabSIan Lepore struct resource * mem_res;
774159fbabSIan Lepore int tmr_num; /* N from hwmod str "timerN" */
784159fbabSIan Lepore char tmr_name[12]; /* "DMTimerN" */
794159fbabSIan Lepore uint32_t tclr; /* Cached TCLR register. */
804159fbabSIan Lepore struct timecounter tc;
814159fbabSIan Lepore int pps_curmode; /* Edge mode now set in hw. */
824159fbabSIan Lepore struct cdev * pps_cdev;
834159fbabSIan Lepore struct pps_state pps_state;
844159fbabSIan Lepore struct mtx pps_mtx;
850050ea24SMichal Meloun clk_t clk_fck;
860050ea24SMichal Meloun uint64_t sysclk_freq;
874159fbabSIan Lepore };
884159fbabSIan Lepore
894159fbabSIan Lepore static int dmtpps_tmr_num; /* Set by probe() */
904159fbabSIan Lepore
914159fbabSIan Lepore /* List of compatible strings for FDT tree */
924159fbabSIan Lepore static struct ofw_compat_data compat_data[] = {
934159fbabSIan Lepore {"ti,am335x-timer", 1},
944159fbabSIan Lepore {"ti,am335x-timer-1ms", 1},
954159fbabSIan Lepore {NULL, 0},
964159fbabSIan Lepore };
97519b64e2SMark Johnston SIMPLEBUS_PNP_INFO(compat_data);
984159fbabSIan Lepore
994159fbabSIan Lepore /*
1004159fbabSIan Lepore * A table relating pad names to the hardware timer number they can be mux'd to.
1014159fbabSIan Lepore */
1024159fbabSIan Lepore struct padinfo {
1034159fbabSIan Lepore char * ballname;
1044159fbabSIan Lepore int tmr_num;
1054159fbabSIan Lepore };
1064159fbabSIan Lepore static struct padinfo dmtpps_padinfo[] = {
1074159fbabSIan Lepore {"GPMC_ADVn_ALE", 4},
1084159fbabSIan Lepore {"I2C0_SDA", 4},
1094159fbabSIan Lepore {"MII1_TX_EN", 4},
1104159fbabSIan Lepore {"XDMA_EVENT_INTR0", 4},
1114159fbabSIan Lepore {"GPMC_BEn0_CLE", 5},
1124159fbabSIan Lepore {"MDC", 5},
1134159fbabSIan Lepore {"MMC0_DAT3", 5},
1144159fbabSIan Lepore {"UART1_RTSn", 5},
1154159fbabSIan Lepore {"GPMC_WEn", 6},
1164159fbabSIan Lepore {"MDIO", 6},
1174159fbabSIan Lepore {"MMC0_DAT2", 6},
1184159fbabSIan Lepore {"UART1_CTSn", 6},
1194159fbabSIan Lepore {"GPMC_OEn_REn", 7},
1204159fbabSIan Lepore {"I2C0_SCL", 7},
1214159fbabSIan Lepore {"UART0_CTSn", 7},
1224159fbabSIan Lepore {"XDMA_EVENT_INTR1", 7},
1234159fbabSIan Lepore {NULL, 0}
1244159fbabSIan Lepore };
1254159fbabSIan Lepore
1264159fbabSIan Lepore /*
1274159fbabSIan Lepore * This is either brilliantly user-friendly, or utterly lame...
1284159fbabSIan Lepore *
1294159fbabSIan Lepore * The am335x chip is used on the popular Beaglebone boards. Those boards have
1304159fbabSIan Lepore * pins for all four capture-capable timers available on the P8 header. Allow
1314159fbabSIan Lepore * users to configure the input pin by giving the name of the header pin.
1324159fbabSIan Lepore */
1334159fbabSIan Lepore struct nicknames {
1344159fbabSIan Lepore const char * nick;
1354159fbabSIan Lepore const char * name;
1364159fbabSIan Lepore };
1374159fbabSIan Lepore static struct nicknames dmtpps_pin_nicks[] = {
1384159fbabSIan Lepore {"P8-7", "GPMC_ADVn_ALE"},
1394159fbabSIan Lepore {"P8-9", "GPMC_BEn0_CLE"},
1404159fbabSIan Lepore {"P8-10", "GPMC_WEn"},
1414159fbabSIan Lepore {"P8-8", "GPMC_OEn_REn",},
1424159fbabSIan Lepore {NULL, NULL}
1434159fbabSIan Lepore };
1444159fbabSIan Lepore
1454159fbabSIan Lepore #define DMTIMER_READ4(sc, reg) bus_read_4((sc)->mem_res, (reg))
1464159fbabSIan Lepore #define DMTIMER_WRITE4(sc, reg, val) bus_write_4((sc)->mem_res, (reg), (val))
1474159fbabSIan Lepore
1484159fbabSIan Lepore /*
1494159fbabSIan Lepore * Translate a short friendly case-insensitive name to its canonical name.
1504159fbabSIan Lepore */
1514159fbabSIan Lepore static const char *
dmtpps_translate_nickname(const char * nick)1524159fbabSIan Lepore dmtpps_translate_nickname(const char *nick)
1534159fbabSIan Lepore {
1544159fbabSIan Lepore struct nicknames *nn;
1554159fbabSIan Lepore
1564159fbabSIan Lepore for (nn = dmtpps_pin_nicks; nn->nick != NULL; nn++)
1574159fbabSIan Lepore if (strcasecmp(nick, nn->nick) == 0)
1584159fbabSIan Lepore return nn->name;
1594159fbabSIan Lepore return (nick);
1604159fbabSIan Lepore }
1614159fbabSIan Lepore
1624159fbabSIan Lepore /*
1634159fbabSIan Lepore * See if our tunable is set to the name of the input pin. If not, that's NOT
1644159fbabSIan Lepore * an error, return 0. If so, try to configure that pin as a timer capture
1654159fbabSIan Lepore * input pin, and if that works, then we have our timer unit number and if it
1664159fbabSIan Lepore * fails that IS an error, return -1.
1674159fbabSIan Lepore */
1684159fbabSIan Lepore static int
dmtpps_find_tmr_num_by_tunable(void)16959249a51SAndrew Turner dmtpps_find_tmr_num_by_tunable(void)
1704159fbabSIan Lepore {
1714159fbabSIan Lepore struct padinfo *pi;
1724159fbabSIan Lepore char iname[20];
1734159fbabSIan Lepore char muxmode[12];
1744159fbabSIan Lepore const char * ballname;
1754159fbabSIan Lepore int err;
1764159fbabSIan Lepore
1774159fbabSIan Lepore if (!TUNABLE_STR_FETCH("hw.am335x_dmtpps.input", iname, sizeof(iname)))
1784159fbabSIan Lepore return (0);
1794159fbabSIan Lepore ballname = dmtpps_translate_nickname(iname);
1804159fbabSIan Lepore for (pi = dmtpps_padinfo; pi->ballname != NULL; pi++) {
1814159fbabSIan Lepore if (strcmp(ballname, pi->ballname) != 0)
1824159fbabSIan Lepore continue;
1834159fbabSIan Lepore snprintf(muxmode, sizeof(muxmode), "timer%d", pi->tmr_num);
1844159fbabSIan Lepore err = ti_pinmux_padconf_set(pi->ballname, muxmode,
1854159fbabSIan Lepore PADCONF_INPUT);
1864159fbabSIan Lepore if (err != 0) {
1874159fbabSIan Lepore printf("am335x_dmtpps: unable to configure capture pin "
1884159fbabSIan Lepore "for %s to input mode\n", muxmode);
1894159fbabSIan Lepore return (-1);
1904159fbabSIan Lepore } else if (bootverbose) {
1914159fbabSIan Lepore printf("am335x_dmtpps: configured pin %s as input "
1924159fbabSIan Lepore "for %s\n", iname, muxmode);
1934159fbabSIan Lepore }
1944159fbabSIan Lepore return (pi->tmr_num);
1954159fbabSIan Lepore }
1964159fbabSIan Lepore
1974159fbabSIan Lepore /* Invalid name in the tunable, that's an error. */
1984159fbabSIan Lepore printf("am335x_dmtpps: unknown pin name '%s'\n", iname);
1994159fbabSIan Lepore return (-1);
2004159fbabSIan Lepore }
2014159fbabSIan Lepore
2024159fbabSIan Lepore /*
2034159fbabSIan Lepore * Ask the pinmux driver whether any pin has been configured as a TIMER4..TIMER7
2044159fbabSIan Lepore * input pin. If so, return the timer number, if not return 0.
2054159fbabSIan Lepore */
2064159fbabSIan Lepore static int
dmtpps_find_tmr_num_by_padconf(void)20759249a51SAndrew Turner dmtpps_find_tmr_num_by_padconf(void)
2084159fbabSIan Lepore {
2094159fbabSIan Lepore int err;
2104159fbabSIan Lepore unsigned int padstate;
2114159fbabSIan Lepore const char * padmux;
2124159fbabSIan Lepore struct padinfo *pi;
2134159fbabSIan Lepore char muxmode[12];
2144159fbabSIan Lepore
2154159fbabSIan Lepore for (pi = dmtpps_padinfo; pi->ballname != NULL; pi++) {
2164159fbabSIan Lepore err = ti_pinmux_padconf_get(pi->ballname, &padmux, &padstate);
2174159fbabSIan Lepore snprintf(muxmode, sizeof(muxmode), "timer%d", pi->tmr_num);
2184159fbabSIan Lepore if (err == 0 && (padstate & RXACTIVE) != 0 &&
2194159fbabSIan Lepore strcmp(muxmode, padmux) == 0)
2204159fbabSIan Lepore return (pi->tmr_num);
2214159fbabSIan Lepore }
2224159fbabSIan Lepore /* Nothing found, not an error. */
2234159fbabSIan Lepore return (0);
2244159fbabSIan Lepore }
2254159fbabSIan Lepore
2264159fbabSIan Lepore /*
2274159fbabSIan Lepore * Figure out which hardware timer number to use based on input pin
2284159fbabSIan Lepore * configuration. This is done just once, the first time probe() runs.
2294159fbabSIan Lepore */
2304159fbabSIan Lepore static int
dmtpps_find_tmr_num(void)23159249a51SAndrew Turner dmtpps_find_tmr_num(void)
2324159fbabSIan Lepore {
2334159fbabSIan Lepore int tmr_num;
2344159fbabSIan Lepore
2354159fbabSIan Lepore if ((tmr_num = dmtpps_find_tmr_num_by_tunable()) == 0)
2364159fbabSIan Lepore tmr_num = dmtpps_find_tmr_num_by_padconf();
2374159fbabSIan Lepore
2384159fbabSIan Lepore if (tmr_num <= 0) {
2394159fbabSIan Lepore printf("am335x_dmtpps: PPS driver not enabled: unable to find "
2404159fbabSIan Lepore "or configure a capture input pin\n");
2414159fbabSIan Lepore tmr_num = -1; /* Must return non-zero to prevent re-probing. */
2424159fbabSIan Lepore }
2434159fbabSIan Lepore return (tmr_num);
2444159fbabSIan Lepore }
2454159fbabSIan Lepore
2464159fbabSIan Lepore static void
dmtpps_set_hw_capture(struct dmtpps_softc * sc,bool force_off)2474159fbabSIan Lepore dmtpps_set_hw_capture(struct dmtpps_softc *sc, bool force_off)
2484159fbabSIan Lepore {
2494159fbabSIan Lepore int newmode;
2504159fbabSIan Lepore
2514159fbabSIan Lepore if (force_off)
2524159fbabSIan Lepore newmode = 0;
2534159fbabSIan Lepore else
2544159fbabSIan Lepore newmode = sc->pps_state.ppsparam.mode & PPS_CAPTUREASSERT;
2554159fbabSIan Lepore
2564159fbabSIan Lepore if (newmode == sc->pps_curmode)
2574159fbabSIan Lepore return;
2584159fbabSIan Lepore sc->pps_curmode = newmode;
2594159fbabSIan Lepore
2604159fbabSIan Lepore if (newmode == PPS_CAPTUREASSERT)
2614159fbabSIan Lepore sc->tclr |= DMT_TCLR_CAPTRAN_LOHI;
2624159fbabSIan Lepore else
2634159fbabSIan Lepore sc->tclr &= ~DMT_TCLR_CAPTRAN_MASK;
2644159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
2654159fbabSIan Lepore }
2664159fbabSIan Lepore
2674159fbabSIan Lepore static unsigned
dmtpps_get_timecount(struct timecounter * tc)2684159fbabSIan Lepore dmtpps_get_timecount(struct timecounter *tc)
2694159fbabSIan Lepore {
2704159fbabSIan Lepore struct dmtpps_softc *sc;
2714159fbabSIan Lepore
2724159fbabSIan Lepore sc = tc->tc_priv;
2734159fbabSIan Lepore
2744159fbabSIan Lepore return (DMTIMER_READ4(sc, DMT_TCRR));
2754159fbabSIan Lepore }
2764159fbabSIan Lepore
2774159fbabSIan Lepore static void
dmtpps_poll(struct timecounter * tc)2784159fbabSIan Lepore dmtpps_poll(struct timecounter *tc)
2794159fbabSIan Lepore {
2804159fbabSIan Lepore struct dmtpps_softc *sc;
2814159fbabSIan Lepore
2824159fbabSIan Lepore sc = tc->tc_priv;
2834159fbabSIan Lepore
2844159fbabSIan Lepore /*
2854159fbabSIan Lepore * If a new value has been latched we've got a PPS event. Capture the
2864159fbabSIan Lepore * timecounter data, then override the capcount field (pps_capture()
2874159fbabSIan Lepore * populates it from the current DMT_TCRR register) with the latched
2884159fbabSIan Lepore * value from the TCAR1 register.
2894159fbabSIan Lepore *
2904159fbabSIan Lepore * Note that we don't have the TCAR interrupt enabled, but the hardware
2914159fbabSIan Lepore * still provides the status bits in the "RAW" status register even when
2924159fbabSIan Lepore * they're masked from generating an irq. However, when clearing the
2934159fbabSIan Lepore * TCAR status to re-arm the capture for the next second, we have to
2944159fbabSIan Lepore * write to the IRQ status register, not the RAW register. Quirky.
295192122bdSIan Lepore *
296192122bdSIan Lepore * We do not need to hold a lock while capturing the pps data, because
297192122bdSIan Lepore * it is captured into an area of the pps_state struct which is read
298192122bdSIan Lepore * only by pps_event(). We do need to hold a lock while calling
299192122bdSIan Lepore * pps_event(), because it manipulates data which is also accessed from
300192122bdSIan Lepore * the ioctl(2) context by userland processes.
3014159fbabSIan Lepore */
3024159fbabSIan Lepore if (DMTIMER_READ4(sc, DMT_IRQSTATUS_RAW) & DMT_IRQ_TCAR) {
3034159fbabSIan Lepore pps_capture(&sc->pps_state);
3044159fbabSIan Lepore sc->pps_state.capcount = DMTIMER_READ4(sc, DMT_TCAR1);
3054159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_IRQSTATUS, DMT_IRQ_TCAR);
3064159fbabSIan Lepore
307192122bdSIan Lepore mtx_lock_spin(&sc->pps_mtx);
3084159fbabSIan Lepore pps_event(&sc->pps_state, PPS_CAPTUREASSERT);
309192122bdSIan Lepore mtx_unlock_spin(&sc->pps_mtx);
310192122bdSIan Lepore }
3114159fbabSIan Lepore }
3124159fbabSIan Lepore
3134159fbabSIan Lepore static int
dmtpps_open(struct cdev * dev,int flags,int fmt,struct thread * td)3144159fbabSIan Lepore dmtpps_open(struct cdev *dev, int flags, int fmt,
3154159fbabSIan Lepore struct thread *td)
3164159fbabSIan Lepore {
3174159fbabSIan Lepore struct dmtpps_softc *sc;
3184159fbabSIan Lepore
3194159fbabSIan Lepore sc = dev->si_drv1;
3204159fbabSIan Lepore
3214159fbabSIan Lepore /*
3224159fbabSIan Lepore * Begin polling for pps and enable capture in the hardware whenever the
3234159fbabSIan Lepore * device is open. Doing this stuff again is harmless if this isn't the
3244159fbabSIan Lepore * first open.
3254159fbabSIan Lepore */
3264159fbabSIan Lepore sc->tc.tc_poll_pps = dmtpps_poll;
3274159fbabSIan Lepore dmtpps_set_hw_capture(sc, false);
3284159fbabSIan Lepore
3294159fbabSIan Lepore return 0;
3304159fbabSIan Lepore }
3314159fbabSIan Lepore
3324159fbabSIan Lepore static int
dmtpps_close(struct cdev * dev,int flags,int fmt,struct thread * td)3334159fbabSIan Lepore dmtpps_close(struct cdev *dev, int flags, int fmt,
3344159fbabSIan Lepore struct thread *td)
3354159fbabSIan Lepore {
3364159fbabSIan Lepore struct dmtpps_softc *sc;
3374159fbabSIan Lepore
3384159fbabSIan Lepore sc = dev->si_drv1;
3394159fbabSIan Lepore
3404159fbabSIan Lepore /*
3414159fbabSIan Lepore * Stop polling and disable capture on last close. Use the force-off
3424159fbabSIan Lepore * flag to override the configured mode and turn off the hardware.
3434159fbabSIan Lepore */
3444159fbabSIan Lepore sc->tc.tc_poll_pps = NULL;
3454159fbabSIan Lepore dmtpps_set_hw_capture(sc, true);
3464159fbabSIan Lepore
3474159fbabSIan Lepore return 0;
3484159fbabSIan Lepore }
3494159fbabSIan Lepore
3504159fbabSIan Lepore static int
dmtpps_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int flags,struct thread * td)3514159fbabSIan Lepore dmtpps_ioctl(struct cdev *dev, u_long cmd, caddr_t data,
3524159fbabSIan Lepore int flags, struct thread *td)
3534159fbabSIan Lepore {
3544159fbabSIan Lepore struct dmtpps_softc *sc;
3554159fbabSIan Lepore int err;
3564159fbabSIan Lepore
3574159fbabSIan Lepore sc = dev->si_drv1;
3584159fbabSIan Lepore
3594159fbabSIan Lepore /* Let the kernel do the heavy lifting for ioctl. */
360192122bdSIan Lepore mtx_lock_spin(&sc->pps_mtx);
3614159fbabSIan Lepore err = pps_ioctl(cmd, data, &sc->pps_state);
362192122bdSIan Lepore mtx_unlock_spin(&sc->pps_mtx);
3634159fbabSIan Lepore if (err != 0)
3644159fbabSIan Lepore return (err);
3654159fbabSIan Lepore
3664159fbabSIan Lepore /*
3674159fbabSIan Lepore * The capture mode could have changed, set the hardware to whatever
3684159fbabSIan Lepore * mode is now current. Effectively a no-op if nothing changed.
3694159fbabSIan Lepore */
3704159fbabSIan Lepore dmtpps_set_hw_capture(sc, false);
3714159fbabSIan Lepore
3724159fbabSIan Lepore return (err);
3734159fbabSIan Lepore }
3744159fbabSIan Lepore
3754159fbabSIan Lepore static struct cdevsw dmtpps_cdevsw = {
3764159fbabSIan Lepore .d_version = D_VERSION,
3774159fbabSIan Lepore .d_open = dmtpps_open,
3784159fbabSIan Lepore .d_close = dmtpps_close,
3794159fbabSIan Lepore .d_ioctl = dmtpps_ioctl,
3804159fbabSIan Lepore .d_name = PPS_CDEV_NAME,
3814159fbabSIan Lepore };
3824159fbabSIan Lepore
3834159fbabSIan Lepore static int
dmtpps_probe(device_t dev)3844159fbabSIan Lepore dmtpps_probe(device_t dev)
3854159fbabSIan Lepore {
3864159fbabSIan Lepore int tmr_num;
3870050ea24SMichal Meloun uint64_t rev_address;
3884159fbabSIan Lepore
3894159fbabSIan Lepore if (!ofw_bus_status_okay(dev))
3904159fbabSIan Lepore return (ENXIO);
3914159fbabSIan Lepore
3924159fbabSIan Lepore if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
3934159fbabSIan Lepore return (ENXIO);
3944159fbabSIan Lepore
3954159fbabSIan Lepore /*
3964159fbabSIan Lepore * If we haven't chosen which hardware timer to use yet, go do that now.
3974159fbabSIan Lepore * We need to know that to decide whether to return success for this
3984159fbabSIan Lepore * hardware timer instance or not.
3994159fbabSIan Lepore */
4004159fbabSIan Lepore if (dmtpps_tmr_num == 0)
4014159fbabSIan Lepore dmtpps_tmr_num = dmtpps_find_tmr_num();
4024159fbabSIan Lepore
4034159fbabSIan Lepore /*
4044159fbabSIan Lepore * Figure out which hardware timer is being probed and see if it matches
4054159fbabSIan Lepore * the configured timer number determined earlier.
4064159fbabSIan Lepore */
4070050ea24SMichal Meloun rev_address = ti_sysc_get_rev_address(device_get_parent(dev));
4080050ea24SMichal Meloun switch (rev_address) {
4090050ea24SMichal Meloun case DMTIMER1_1MS_REV:
4100050ea24SMichal Meloun tmr_num = 1;
4110050ea24SMichal Meloun break;
4120050ea24SMichal Meloun case DMTIMER2_REV:
4130050ea24SMichal Meloun tmr_num = 2;
4140050ea24SMichal Meloun break;
4150050ea24SMichal Meloun case DMTIMER3_REV:
4160050ea24SMichal Meloun tmr_num = 3;
4170050ea24SMichal Meloun break;
4180050ea24SMichal Meloun case DMTIMER4_REV:
4190050ea24SMichal Meloun tmr_num = 4;
4200050ea24SMichal Meloun break;
4210050ea24SMichal Meloun case DMTIMER5_REV:
4220050ea24SMichal Meloun tmr_num = 5;
4230050ea24SMichal Meloun break;
4240050ea24SMichal Meloun case DMTIMER6_REV:
4250050ea24SMichal Meloun tmr_num = 6;
4260050ea24SMichal Meloun break;
4270050ea24SMichal Meloun case DMTIMER7_REV:
4280050ea24SMichal Meloun tmr_num = 7;
4290050ea24SMichal Meloun break;
4300050ea24SMichal Meloun default:
4310050ea24SMichal Meloun return (ENXIO);
4320050ea24SMichal Meloun }
4330050ea24SMichal Meloun
4344159fbabSIan Lepore if (dmtpps_tmr_num != tmr_num)
4354159fbabSIan Lepore return (ENXIO);
4364159fbabSIan Lepore
437*3ce9b2eeSMark Johnston device_set_descf(dev, "AM335x PPS-Capture DMTimer%d", tmr_num);
4384159fbabSIan Lepore
4394159fbabSIan Lepore return(BUS_PROBE_DEFAULT);
4404159fbabSIan Lepore }
4414159fbabSIan Lepore
4424159fbabSIan Lepore static int
dmtpps_attach(device_t dev)4434159fbabSIan Lepore dmtpps_attach(device_t dev)
4444159fbabSIan Lepore {
4454159fbabSIan Lepore struct dmtpps_softc *sc;
446192122bdSIan Lepore struct make_dev_args mda;
4470050ea24SMichal Meloun int err;
4480050ea24SMichal Meloun clk_t sys_clkin;
4490050ea24SMichal Meloun uint64_t rev_address;
4504159fbabSIan Lepore
4514159fbabSIan Lepore sc = device_get_softc(dev);
4524159fbabSIan Lepore sc->dev = dev;
4534159fbabSIan Lepore
4540050ea24SMichal Meloun /* Figure out which hardware timer this is and set the name string. */
4550050ea24SMichal Meloun rev_address = ti_sysc_get_rev_address(device_get_parent(dev));
4560050ea24SMichal Meloun switch (rev_address) {
4570050ea24SMichal Meloun case DMTIMER1_1MS_REV:
4580050ea24SMichal Meloun sc->tmr_num = 1;
4590050ea24SMichal Meloun break;
4600050ea24SMichal Meloun case DMTIMER2_REV:
4610050ea24SMichal Meloun sc->tmr_num = 2;
4620050ea24SMichal Meloun break;
4630050ea24SMichal Meloun case DMTIMER3_REV:
4640050ea24SMichal Meloun sc->tmr_num = 3;
4650050ea24SMichal Meloun break;
4660050ea24SMichal Meloun case DMTIMER4_REV:
4670050ea24SMichal Meloun sc->tmr_num = 4;
4680050ea24SMichal Meloun break;
4690050ea24SMichal Meloun case DMTIMER5_REV:
4700050ea24SMichal Meloun sc->tmr_num = 5;
4710050ea24SMichal Meloun break;
4720050ea24SMichal Meloun case DMTIMER6_REV:
4730050ea24SMichal Meloun sc->tmr_num = 6;
4740050ea24SMichal Meloun break;
4750050ea24SMichal Meloun case DMTIMER7_REV:
4760050ea24SMichal Meloun sc->tmr_num = 7;
4770050ea24SMichal Meloun break;
4780050ea24SMichal Meloun }
4790050ea24SMichal Meloun snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num);
4800050ea24SMichal Meloun
4810050ea24SMichal Meloun /* expect one clock */
4820050ea24SMichal Meloun err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck);
4830050ea24SMichal Meloun if (err != 0) {
4840050ea24SMichal Meloun device_printf(dev, "Cant find clock index 0. err: %d\n", err);
4850050ea24SMichal Meloun return (ENXIO);
4860050ea24SMichal Meloun }
4870050ea24SMichal Meloun
4880050ea24SMichal Meloun err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin);
4890050ea24SMichal Meloun if (err != 0) {
4900050ea24SMichal Meloun device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err);
4910050ea24SMichal Meloun return (ENXIO);
4920050ea24SMichal Meloun }
4930050ea24SMichal Meloun
4940050ea24SMichal Meloun /* Select M_OSC as DPLL parent */
4950050ea24SMichal Meloun err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin);
4960050ea24SMichal Meloun if (err != 0) {
4970050ea24SMichal Meloun device_printf(dev, "Cant set mux to CLK_M_OSC\n");
4980050ea24SMichal Meloun return (ENXIO);
4990050ea24SMichal Meloun }
5004159fbabSIan Lepore
5014159fbabSIan Lepore /* Enable clocks and power on the device. */
5020050ea24SMichal Meloun err = ti_sysc_clock_enable(device_get_parent(dev));
5030050ea24SMichal Meloun if (err != 0) {
5040050ea24SMichal Meloun device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err);
5054159fbabSIan Lepore return (ENXIO);
5060050ea24SMichal Meloun }
5074159fbabSIan Lepore
5080050ea24SMichal Meloun /* Get the base clock frequency. */
5090050ea24SMichal Meloun err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq);
5100050ea24SMichal Meloun if (err != 0) {
5110050ea24SMichal Meloun device_printf(dev, "Cant get sysclk frequency, err %d\n", err);
5120050ea24SMichal Meloun return (ENXIO);
5130050ea24SMichal Meloun }
5144159fbabSIan Lepore /* Request the memory resources. */
5154159fbabSIan Lepore sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
5164159fbabSIan Lepore &sc->mem_rid, RF_ACTIVE);
5174159fbabSIan Lepore if (sc->mem_res == NULL) {
5184159fbabSIan Lepore return (ENXIO);
5194159fbabSIan Lepore }
5204159fbabSIan Lepore
52128b3a4a6SIan Lepore /*
52228b3a4a6SIan Lepore * Configure the timer pulse/capture pin to input/capture mode. This is
52328b3a4a6SIan Lepore * required in addition to configuring the pin as input with the pinmux
52428b3a4a6SIan Lepore * controller (which was done via fdt data or tunable at probe time).
52528b3a4a6SIan Lepore */
52628b3a4a6SIan Lepore sc->tclr = DMT_TCLR_GPO_CFG;
52728b3a4a6SIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
52828b3a4a6SIan Lepore
5294159fbabSIan Lepore /* Set up timecounter hardware, start it. */
5304159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TSICR, DMT_TSICR_RESET);
5314159fbabSIan Lepore while (DMTIMER_READ4(sc, DMT_TIOCP_CFG) & DMT_TIOCP_RESET)
5324159fbabSIan Lepore continue;
5334159fbabSIan Lepore
5344159fbabSIan Lepore sc->tclr |= DMT_TCLR_START | DMT_TCLR_AUTOLOAD;
5354159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TLDR, 0);
5364159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCRR, 0);
5374159fbabSIan Lepore DMTIMER_WRITE4(sc, DMT_TCLR, sc->tclr);
5384159fbabSIan Lepore
5394159fbabSIan Lepore /* Register the timecounter. */
5404159fbabSIan Lepore sc->tc.tc_name = sc->tmr_name;
5414159fbabSIan Lepore sc->tc.tc_get_timecount = dmtpps_get_timecount;
5424159fbabSIan Lepore sc->tc.tc_counter_mask = ~0u;
5430050ea24SMichal Meloun sc->tc.tc_frequency = sc->sysclk_freq;
5444159fbabSIan Lepore sc->tc.tc_quality = 1000;
5454159fbabSIan Lepore sc->tc.tc_priv = sc;
5464159fbabSIan Lepore
5474159fbabSIan Lepore tc_init(&sc->tc);
5484159fbabSIan Lepore
5494159fbabSIan Lepore /*
5504159fbabSIan Lepore * Indicate our PPS capabilities. Have the kernel init its part of the
5514159fbabSIan Lepore * pps_state struct and add its capabilities.
5524159fbabSIan Lepore *
5534159fbabSIan Lepore * While the hardware has a mode to capture each edge, it's not clear we
5544159fbabSIan Lepore * can use it that way, because there's only a single interrupt/status
5554159fbabSIan Lepore * bit to say something was captured, but not which edge it was. For
5564159fbabSIan Lepore * now, just say we can only capture assert events (the positive-going
5574159fbabSIan Lepore * edge of the pulse).
5584159fbabSIan Lepore */
559192122bdSIan Lepore mtx_init(&sc->pps_mtx, "dmtpps", NULL, MTX_SPIN);
560192122bdSIan Lepore sc->pps_state.flags = PPSFLAG_MTX_SPIN;
5614159fbabSIan Lepore sc->pps_state.ppscap = PPS_CAPTUREASSERT;
5624159fbabSIan Lepore sc->pps_state.driver_abi = PPS_ABI_VERSION;
5634159fbabSIan Lepore sc->pps_state.driver_mtx = &sc->pps_mtx;
5644159fbabSIan Lepore pps_init_abi(&sc->pps_state);
5654159fbabSIan Lepore
5664159fbabSIan Lepore /* Create the PPS cdev. */
567192122bdSIan Lepore make_dev_args_init(&mda);
568192122bdSIan Lepore mda.mda_flags = MAKEDEV_WAITOK;
569192122bdSIan Lepore mda.mda_devsw = &dmtpps_cdevsw;
570192122bdSIan Lepore mda.mda_cr = NULL;
571192122bdSIan Lepore mda.mda_uid = UID_ROOT;
572192122bdSIan Lepore mda.mda_gid = GID_WHEEL;
573192122bdSIan Lepore mda.mda_mode = 0600;
574192122bdSIan Lepore mda.mda_unit = device_get_unit(dev);
575192122bdSIan Lepore mda.mda_si_drv1 = sc;
576192122bdSIan Lepore if ((err = make_dev_s(&mda, &sc->pps_cdev, PPS_CDEV_NAME)) != 0) {
577192122bdSIan Lepore device_printf(dev, "Failed to create cdev %s\n", PPS_CDEV_NAME);
578192122bdSIan Lepore return (err);
579192122bdSIan Lepore }
5804159fbabSIan Lepore
5814159fbabSIan Lepore if (bootverbose)
5824159fbabSIan Lepore device_printf(sc->dev, "Using %s for PPS device /dev/%s\n",
5834159fbabSIan Lepore sc->tmr_name, PPS_CDEV_NAME);
5844159fbabSIan Lepore
5854159fbabSIan Lepore return (0);
5864159fbabSIan Lepore }
5874159fbabSIan Lepore
5884159fbabSIan Lepore static int
dmtpps_detach(device_t dev)5894159fbabSIan Lepore dmtpps_detach(device_t dev)
5904159fbabSIan Lepore {
5914159fbabSIan Lepore
5924159fbabSIan Lepore /*
5934159fbabSIan Lepore * There is no way to remove a timecounter once it has been registered,
5944159fbabSIan Lepore * even if it's not in use, so we can never detach. If we were
5954159fbabSIan Lepore * dynamically loaded as a module this will prevent unloading.
5964159fbabSIan Lepore */
5974159fbabSIan Lepore return (EBUSY);
5984159fbabSIan Lepore }
5994159fbabSIan Lepore
6004159fbabSIan Lepore static device_method_t dmtpps_methods[] = {
6014159fbabSIan Lepore DEVMETHOD(device_probe, dmtpps_probe),
6024159fbabSIan Lepore DEVMETHOD(device_attach, dmtpps_attach),
6034159fbabSIan Lepore DEVMETHOD(device_detach, dmtpps_detach),
6044159fbabSIan Lepore { 0, 0 }
6054159fbabSIan Lepore };
6064159fbabSIan Lepore
6074159fbabSIan Lepore static driver_t dmtpps_driver = {
6084159fbabSIan Lepore "am335x_dmtpps",
6094159fbabSIan Lepore dmtpps_methods,
6104159fbabSIan Lepore sizeof(struct dmtpps_softc),
6114159fbabSIan Lepore };
6124159fbabSIan Lepore
6138537e671SJohn Baldwin DRIVER_MODULE(am335x_dmtpps, simplebus, dmtpps_driver, 0, 0);
6140050ea24SMichal Meloun MODULE_DEPEND(am335x_dmtpps, ti_sysc, 1, 1, 1);
615