1*a2c472e7SAleksandr Rybalko /*- 2*a2c472e7SAleksandr Rybalko * Copyright (c) 2012 The FreeBSD Foundation 3*a2c472e7SAleksandr Rybalko * All rights reserved. 4*a2c472e7SAleksandr Rybalko * 5*a2c472e7SAleksandr Rybalko * This software was developed by Oleksandr Rybalko under sponsorship 6*a2c472e7SAleksandr Rybalko * from the FreeBSD Foundation. 7*a2c472e7SAleksandr Rybalko * 8*a2c472e7SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 9*a2c472e7SAleksandr Rybalko * modification, are permitted provided that the following conditions 10*a2c472e7SAleksandr Rybalko * are met: 11*a2c472e7SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 12*a2c472e7SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 13*a2c472e7SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 14*a2c472e7SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 15*a2c472e7SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 16*a2c472e7SAleksandr Rybalko * 17*a2c472e7SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18*a2c472e7SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*a2c472e7SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*a2c472e7SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21*a2c472e7SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*a2c472e7SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*a2c472e7SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*a2c472e7SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*a2c472e7SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*a2c472e7SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*a2c472e7SAleksandr Rybalko * SUCH DAMAGE. 28*a2c472e7SAleksandr Rybalko */ 29*a2c472e7SAleksandr Rybalko 30*a2c472e7SAleksandr Rybalko #include <sys/cdefs.h> 31*a2c472e7SAleksandr Rybalko __FBSDID("$FreeBSD$"); 32*a2c472e7SAleksandr Rybalko 33*a2c472e7SAleksandr Rybalko #include <sys/param.h> 34*a2c472e7SAleksandr Rybalko #include <sys/systm.h> 35*a2c472e7SAleksandr Rybalko #include <sys/kernel.h> 36*a2c472e7SAleksandr Rybalko #include <sys/module.h> 37*a2c472e7SAleksandr Rybalko #include <sys/time.h> 38*a2c472e7SAleksandr Rybalko #include <sys/bus.h> 39*a2c472e7SAleksandr Rybalko #include <sys/resource.h> 40*a2c472e7SAleksandr Rybalko #include <sys/rman.h> 41*a2c472e7SAleksandr Rybalko #include <sys/watchdog.h> 42*a2c472e7SAleksandr Rybalko 43*a2c472e7SAleksandr Rybalko #include <machine/bus.h> 44*a2c472e7SAleksandr Rybalko #include <machine/intr.h> 45*a2c472e7SAleksandr Rybalko 46*a2c472e7SAleksandr Rybalko #include <dev/fdt/fdt_common.h> 47*a2c472e7SAleksandr Rybalko #include <dev/ofw/openfirm.h> 48*a2c472e7SAleksandr Rybalko #include <dev/ofw/ofw_bus.h> 49*a2c472e7SAleksandr Rybalko #include <dev/ofw/ofw_bus_subr.h> 50*a2c472e7SAleksandr Rybalko #include <machine/fdt.h> 51*a2c472e7SAleksandr Rybalko 52*a2c472e7SAleksandr Rybalko #include <arm/freescale/imx/imx_wdogreg.h> 53*a2c472e7SAleksandr Rybalko 54*a2c472e7SAleksandr Rybalko struct imx_wdog_softc { 55*a2c472e7SAleksandr Rybalko struct mtx sc_mtx; 56*a2c472e7SAleksandr Rybalko device_t sc_dev; 57*a2c472e7SAleksandr Rybalko bus_space_tag_t sc_bst; 58*a2c472e7SAleksandr Rybalko bus_space_handle_t sc_bsh; 59*a2c472e7SAleksandr Rybalko struct resource *sc_res[2]; 60*a2c472e7SAleksandr Rybalko uint32_t sc_timeout; 61*a2c472e7SAleksandr Rybalko }; 62*a2c472e7SAleksandr Rybalko 63*a2c472e7SAleksandr Rybalko static struct resource_spec imx_wdog_spec[] = { 64*a2c472e7SAleksandr Rybalko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 65*a2c472e7SAleksandr Rybalko { SYS_RES_IRQ, 0, RF_ACTIVE }, 66*a2c472e7SAleksandr Rybalko { -1, 0 } 67*a2c472e7SAleksandr Rybalko }; 68*a2c472e7SAleksandr Rybalko 69*a2c472e7SAleksandr Rybalko static void imx_watchdog(void *, u_int, int *); 70*a2c472e7SAleksandr Rybalko static int imx_wdog_probe(device_t); 71*a2c472e7SAleksandr Rybalko static int imx_wdog_attach(device_t); 72*a2c472e7SAleksandr Rybalko 73*a2c472e7SAleksandr Rybalko static device_method_t imx_wdog_methods[] = { 74*a2c472e7SAleksandr Rybalko DEVMETHOD(device_probe, imx_wdog_probe), 75*a2c472e7SAleksandr Rybalko DEVMETHOD(device_attach, imx_wdog_attach), 76*a2c472e7SAleksandr Rybalko DEVMETHOD_END 77*a2c472e7SAleksandr Rybalko }; 78*a2c472e7SAleksandr Rybalko 79*a2c472e7SAleksandr Rybalko static driver_t imx_wdog_driver = { 80*a2c472e7SAleksandr Rybalko "imx_wdog", 81*a2c472e7SAleksandr Rybalko imx_wdog_methods, 82*a2c472e7SAleksandr Rybalko sizeof(struct imx_wdog_softc), 83*a2c472e7SAleksandr Rybalko }; 84*a2c472e7SAleksandr Rybalko static devclass_t imx_wdog_devclass; 85*a2c472e7SAleksandr Rybalko DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); 86*a2c472e7SAleksandr Rybalko 87*a2c472e7SAleksandr Rybalko 88*a2c472e7SAleksandr Rybalko static void 89*a2c472e7SAleksandr Rybalko imx_watchdog(void *arg, u_int cmd, int *error) 90*a2c472e7SAleksandr Rybalko { 91*a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 92*a2c472e7SAleksandr Rybalko uint16_t reg; 93*a2c472e7SAleksandr Rybalko int timeout; 94*a2c472e7SAleksandr Rybalko 95*a2c472e7SAleksandr Rybalko sc = arg; 96*a2c472e7SAleksandr Rybalko mtx_lock(&sc->sc_mtx); 97*a2c472e7SAleksandr Rybalko 98*a2c472e7SAleksandr Rybalko /* Refresh counter, since we feels good */ 99*a2c472e7SAleksandr Rybalko WRITE(sc, WDOG_SR_REG, WDOG_SR_STEP1); 100*a2c472e7SAleksandr Rybalko WRITE(sc, WDOG_SR_REG, WDOG_SR_STEP2); 101*a2c472e7SAleksandr Rybalko 102*a2c472e7SAleksandr Rybalko /* We don't require precession, so "-10" (/1024) is ok */ 103*a2c472e7SAleksandr Rybalko timeout = (1 << ((cmd & WD_INTERVAL) - 10)) / 1000000; 104*a2c472e7SAleksandr Rybalko if (timeout > 1 && timeout < 128) { 105*a2c472e7SAleksandr Rybalko if (timeout != sc->sc_timeout) { 106*a2c472e7SAleksandr Rybalko device_printf(sc->sc_dev, 107*a2c472e7SAleksandr Rybalko "WARNING: watchdog can't be disabled!!!"); 108*a2c472e7SAleksandr Rybalko sc->sc_timeout = timeout; 109*a2c472e7SAleksandr Rybalko reg = READ(sc, WDOG_CR_REG); 110*a2c472e7SAleksandr Rybalko reg &= ~WDOG_CR_WT_MASK; 111*a2c472e7SAleksandr Rybalko reg |= (timeout << (WDOG_CR_WT_SHIFT + 1)) & 112*a2c472e7SAleksandr Rybalko WDOG_CR_WT_MASK; 113*a2c472e7SAleksandr Rybalko WRITE(sc, WDOG_CR_REG, reg); 114*a2c472e7SAleksandr Rybalko /* Refresh counter */ 115*a2c472e7SAleksandr Rybalko WRITE(sc, WDOG_SR_REG, WDOG_SR_STEP1); 116*a2c472e7SAleksandr Rybalko WRITE(sc, WDOG_SR_REG, WDOG_SR_STEP2); 117*a2c472e7SAleksandr Rybalko *error = 0; 118*a2c472e7SAleksandr Rybalko } else { 119*a2c472e7SAleksandr Rybalko *error = EOPNOTSUPP; 120*a2c472e7SAleksandr Rybalko } 121*a2c472e7SAleksandr Rybalko } else { 122*a2c472e7SAleksandr Rybalko device_printf(sc->sc_dev, "Can not be disabled.\n"); 123*a2c472e7SAleksandr Rybalko *error = EOPNOTSUPP; 124*a2c472e7SAleksandr Rybalko } 125*a2c472e7SAleksandr Rybalko mtx_unlock(&sc->sc_mtx); 126*a2c472e7SAleksandr Rybalko 127*a2c472e7SAleksandr Rybalko } 128*a2c472e7SAleksandr Rybalko 129*a2c472e7SAleksandr Rybalko static int 130*a2c472e7SAleksandr Rybalko imx_wdog_probe(device_t dev) 131*a2c472e7SAleksandr Rybalko { 132*a2c472e7SAleksandr Rybalko 133*a2c472e7SAleksandr Rybalko if (!ofw_bus_is_compatible(dev, "fsl,imx51-wdt")) 134*a2c472e7SAleksandr Rybalko return (ENXIO); 135*a2c472e7SAleksandr Rybalko 136*a2c472e7SAleksandr Rybalko device_set_desc(dev, "Freescale i.MX5xx Watchdog Timer"); 137*a2c472e7SAleksandr Rybalko return (0); 138*a2c472e7SAleksandr Rybalko } 139*a2c472e7SAleksandr Rybalko 140*a2c472e7SAleksandr Rybalko static int 141*a2c472e7SAleksandr Rybalko imx_wdog_attach(device_t dev) 142*a2c472e7SAleksandr Rybalko { 143*a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 144*a2c472e7SAleksandr Rybalko 145*a2c472e7SAleksandr Rybalko sc = device_get_softc(dev); 146*a2c472e7SAleksandr Rybalko sc->sc_dev = dev; 147*a2c472e7SAleksandr Rybalko 148*a2c472e7SAleksandr Rybalko if (bus_alloc_resources(dev, imx_wdog_spec, sc->sc_res)) { 149*a2c472e7SAleksandr Rybalko device_printf(dev, "could not allocate resources\n"); 150*a2c472e7SAleksandr Rybalko return (ENXIO); 151*a2c472e7SAleksandr Rybalko } 152*a2c472e7SAleksandr Rybalko 153*a2c472e7SAleksandr Rybalko mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF); 154*a2c472e7SAleksandr Rybalko 155*a2c472e7SAleksandr Rybalko sc->sc_dev = dev; 156*a2c472e7SAleksandr Rybalko sc->sc_bst = rman_get_bustag(sc->sc_res[0]); 157*a2c472e7SAleksandr Rybalko sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); 158*a2c472e7SAleksandr Rybalko 159*a2c472e7SAleksandr Rybalko /* TODO: handle interrupt */ 160*a2c472e7SAleksandr Rybalko 161*a2c472e7SAleksandr Rybalko EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0); 162*a2c472e7SAleksandr Rybalko return (0); 163*a2c472e7SAleksandr Rybalko } 164