1a2c472e7SAleksandr Rybalko /*- 294f8d6fdSAleksandr 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 51a2c472e7SAleksandr Rybalko #include <arm/freescale/imx/imx_wdogreg.h> 52a2c472e7SAleksandr Rybalko 53a2c472e7SAleksandr Rybalko struct imx_wdog_softc { 54a2c472e7SAleksandr Rybalko struct mtx sc_mtx; 55a2c472e7SAleksandr Rybalko device_t sc_dev; 56a2c472e7SAleksandr Rybalko bus_space_tag_t sc_bst; 57a2c472e7SAleksandr Rybalko bus_space_handle_t sc_bsh; 58a2c472e7SAleksandr Rybalko struct resource *sc_res[2]; 59a2c472e7SAleksandr Rybalko uint32_t sc_timeout; 60a2c472e7SAleksandr Rybalko }; 61a2c472e7SAleksandr Rybalko 62a2c472e7SAleksandr Rybalko static struct resource_spec imx_wdog_spec[] = { 63a2c472e7SAleksandr Rybalko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 64a2c472e7SAleksandr Rybalko { SYS_RES_IRQ, 0, RF_ACTIVE }, 65a2c472e7SAleksandr Rybalko { -1, 0 } 66a2c472e7SAleksandr Rybalko }; 67a2c472e7SAleksandr Rybalko 68398c1838SIan Lepore static struct ofw_compat_data compat_data[] = { 69398c1838SIan Lepore {"fsl,imx6sx-wdt", 1}, 70398c1838SIan Lepore {"fsl,imx6sl-wdt", 1}, 71398c1838SIan Lepore {"fsl,imx6q-wdt", 1}, 72398c1838SIan Lepore {"fsl,imx53-wdt", 1}, 73398c1838SIan Lepore {"fsl,imx51-wdt", 1}, 74398c1838SIan Lepore {"fsl,imx50-wdt", 1}, 75398c1838SIan Lepore {"fsl,imx35-wdt", 1}, 76398c1838SIan Lepore {"fsl,imx27-wdt", 1}, 77398c1838SIan Lepore {"fsl,imx25-wdt", 1}, 78398c1838SIan Lepore {"fsl,imx21-wdt", 1}, 79398c1838SIan Lepore {NULL, 0} 80398c1838SIan Lepore }; 81398c1838SIan Lepore 82a2c472e7SAleksandr Rybalko static void imx_watchdog(void *, u_int, int *); 83a2c472e7SAleksandr Rybalko static int imx_wdog_probe(device_t); 84a2c472e7SAleksandr Rybalko static int imx_wdog_attach(device_t); 85a2c472e7SAleksandr Rybalko 86a2c472e7SAleksandr Rybalko static device_method_t imx_wdog_methods[] = { 87a2c472e7SAleksandr Rybalko DEVMETHOD(device_probe, imx_wdog_probe), 88a2c472e7SAleksandr Rybalko DEVMETHOD(device_attach, imx_wdog_attach), 89a2c472e7SAleksandr Rybalko DEVMETHOD_END 90a2c472e7SAleksandr Rybalko }; 91a2c472e7SAleksandr Rybalko 92a2c472e7SAleksandr Rybalko static driver_t imx_wdog_driver = { 93a2c472e7SAleksandr Rybalko "imx_wdog", 94a2c472e7SAleksandr Rybalko imx_wdog_methods, 95a2c472e7SAleksandr Rybalko sizeof(struct imx_wdog_softc), 96a2c472e7SAleksandr Rybalko }; 97a2c472e7SAleksandr Rybalko static devclass_t imx_wdog_devclass; 98a2c472e7SAleksandr Rybalko DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); 99a2c472e7SAleksandr Rybalko 100398c1838SIan Lepore #define RD2(_sc, _r) \ 101398c1838SIan Lepore bus_space_read_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r)) 102398c1838SIan Lepore #define WR2(_sc, _r, _v) \ 103398c1838SIan Lepore bus_space_write_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r), (_v)) 104a2c472e7SAleksandr Rybalko 105a2c472e7SAleksandr Rybalko static void 106a2c472e7SAleksandr Rybalko imx_watchdog(void *arg, u_int cmd, int *error) 107a2c472e7SAleksandr Rybalko { 108a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 109a2c472e7SAleksandr Rybalko uint16_t reg; 110*6da71028SIan Lepore u_int timeout; 111a2c472e7SAleksandr Rybalko 112a2c472e7SAleksandr Rybalko sc = arg; 113a2c472e7SAleksandr Rybalko mtx_lock(&sc->sc_mtx); 114*6da71028SIan Lepore if (cmd == 0) { 115*6da71028SIan Lepore if (bootverbose) 116*6da71028SIan Lepore device_printf(sc->sc_dev, "Can not be disabled.\n"); 117*6da71028SIan Lepore *error = EOPNOTSUPP; 118*6da71028SIan Lepore } else { 119*6da71028SIan Lepore timeout = (u_int)((1ULL << (cmd & WD_INTERVAL)) / 1000000000U); 120a2c472e7SAleksandr Rybalko if (timeout > 1 && timeout < 128) { 121a2c472e7SAleksandr Rybalko if (timeout != sc->sc_timeout) { 122a2c472e7SAleksandr Rybalko sc->sc_timeout = timeout; 123398c1838SIan Lepore reg = RD2(sc, WDOG_CR_REG); 124a2c472e7SAleksandr Rybalko reg &= ~WDOG_CR_WT_MASK; 125a2c472e7SAleksandr Rybalko reg |= (timeout << (WDOG_CR_WT_SHIFT + 1)) & 126a2c472e7SAleksandr Rybalko WDOG_CR_WT_MASK; 127*6da71028SIan Lepore WR2(sc, WDOG_CR_REG, reg | WDOG_CR_WDE); 128*6da71028SIan Lepore } 129a2c472e7SAleksandr Rybalko /* Refresh counter */ 130398c1838SIan Lepore WR2(sc, WDOG_SR_REG, WDOG_SR_STEP1); 131398c1838SIan Lepore WR2(sc, WDOG_SR_REG, WDOG_SR_STEP2); 132a2c472e7SAleksandr Rybalko *error = 0; 133a2c472e7SAleksandr Rybalko } 134a2c472e7SAleksandr Rybalko } 135a2c472e7SAleksandr Rybalko mtx_unlock(&sc->sc_mtx); 136a2c472e7SAleksandr Rybalko } 137a2c472e7SAleksandr Rybalko 138a2c472e7SAleksandr Rybalko static int 139a2c472e7SAleksandr Rybalko imx_wdog_probe(device_t dev) 140a2c472e7SAleksandr Rybalko { 141a2c472e7SAleksandr Rybalko 142add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 143add35ed5SIan Lepore return (ENXIO); 144add35ed5SIan Lepore 145398c1838SIan Lepore if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 146a2c472e7SAleksandr Rybalko return (ENXIO); 147a2c472e7SAleksandr Rybalko 148398c1838SIan Lepore device_set_desc(dev, "Freescale i.MX Watchdog"); 149a2c472e7SAleksandr Rybalko return (0); 150a2c472e7SAleksandr Rybalko } 151a2c472e7SAleksandr Rybalko 152a2c472e7SAleksandr Rybalko static int 153a2c472e7SAleksandr Rybalko imx_wdog_attach(device_t dev) 154a2c472e7SAleksandr Rybalko { 155a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 156a2c472e7SAleksandr Rybalko 157a2c472e7SAleksandr Rybalko sc = device_get_softc(dev); 158a2c472e7SAleksandr Rybalko sc->sc_dev = dev; 159a2c472e7SAleksandr Rybalko 160a2c472e7SAleksandr Rybalko if (bus_alloc_resources(dev, imx_wdog_spec, sc->sc_res)) { 161a2c472e7SAleksandr Rybalko device_printf(dev, "could not allocate resources\n"); 162a2c472e7SAleksandr Rybalko return (ENXIO); 163a2c472e7SAleksandr Rybalko } 164a2c472e7SAleksandr Rybalko 165a2c472e7SAleksandr Rybalko mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF); 166a2c472e7SAleksandr Rybalko 167a2c472e7SAleksandr Rybalko sc->sc_dev = dev; 168a2c472e7SAleksandr Rybalko sc->sc_bst = rman_get_bustag(sc->sc_res[0]); 169a2c472e7SAleksandr Rybalko sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); 170a2c472e7SAleksandr Rybalko 171a2c472e7SAleksandr Rybalko /* TODO: handle interrupt */ 172a2c472e7SAleksandr Rybalko 173a2c472e7SAleksandr Rybalko EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0); 174a2c472e7SAleksandr Rybalko return (0); 175a2c472e7SAleksandr Rybalko } 176