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