1a2c472e7SAleksandr Rybalko /*- 2af3dc4a7SPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3af3dc4a7SPedro F. Giffuni * 494f8d6fdSAleksandr Rybalko * Copyright (c) 2012, 2013 The FreeBSD Foundation 5a2c472e7SAleksandr Rybalko * All rights reserved. 6a2c472e7SAleksandr Rybalko * 7a2c472e7SAleksandr Rybalko * This software was developed by Oleksandr Rybalko under sponsorship 8a2c472e7SAleksandr Rybalko * from the FreeBSD Foundation. 9a2c472e7SAleksandr Rybalko * 10a2c472e7SAleksandr Rybalko * Redistribution and use in source and binary forms, with or without 11a2c472e7SAleksandr Rybalko * modification, are permitted provided that the following conditions 12a2c472e7SAleksandr Rybalko * are met: 13a2c472e7SAleksandr Rybalko * 1. Redistributions of source code must retain the above copyright 14a2c472e7SAleksandr Rybalko * notice, this list of conditions and the following disclaimer. 15a2c472e7SAleksandr Rybalko * 2. Redistributions in binary form must reproduce the above copyright 16a2c472e7SAleksandr Rybalko * notice, this list of conditions and the following disclaimer in the 17a2c472e7SAleksandr Rybalko * documentation and/or other materials provided with the distribution. 18a2c472e7SAleksandr Rybalko * 19a2c472e7SAleksandr Rybalko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 20a2c472e7SAleksandr Rybalko * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21a2c472e7SAleksandr Rybalko * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22a2c472e7SAleksandr Rybalko * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 23a2c472e7SAleksandr Rybalko * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24a2c472e7SAleksandr Rybalko * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25a2c472e7SAleksandr Rybalko * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26a2c472e7SAleksandr Rybalko * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27a2c472e7SAleksandr Rybalko * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28a2c472e7SAleksandr Rybalko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29a2c472e7SAleksandr Rybalko * SUCH DAMAGE. 30a2c472e7SAleksandr Rybalko */ 31a2c472e7SAleksandr Rybalko 32a2c472e7SAleksandr Rybalko #include <sys/cdefs.h> 33a2c472e7SAleksandr Rybalko __FBSDID("$FreeBSD$"); 34a2c472e7SAleksandr Rybalko 35a2c472e7SAleksandr Rybalko #include <sys/param.h> 36a2c472e7SAleksandr Rybalko #include <sys/systm.h> 37a2c472e7SAleksandr Rybalko #include <sys/kernel.h> 38a2c472e7SAleksandr Rybalko #include <sys/module.h> 39a2c472e7SAleksandr Rybalko #include <sys/time.h> 40a2c472e7SAleksandr Rybalko #include <sys/bus.h> 41a2c472e7SAleksandr Rybalko #include <sys/resource.h> 42a2c472e7SAleksandr Rybalko #include <sys/rman.h> 43a2c472e7SAleksandr Rybalko #include <sys/watchdog.h> 44a2c472e7SAleksandr Rybalko 45a2c472e7SAleksandr Rybalko #include <machine/bus.h> 46a2c472e7SAleksandr Rybalko #include <machine/intr.h> 47a2c472e7SAleksandr Rybalko 48a2c472e7SAleksandr Rybalko #include <dev/ofw/openfirm.h> 49a2c472e7SAleksandr Rybalko #include <dev/ofw/ofw_bus.h> 50a2c472e7SAleksandr Rybalko #include <dev/ofw/ofw_bus_subr.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 struct resource *sc_res[2]; 58a2c472e7SAleksandr Rybalko uint32_t sc_timeout; 59a2c472e7SAleksandr Rybalko }; 60a2c472e7SAleksandr Rybalko 61a2c472e7SAleksandr Rybalko static struct resource_spec imx_wdog_spec[] = { 62a2c472e7SAleksandr Rybalko { SYS_RES_MEMORY, 0, RF_ACTIVE }, 63a2c472e7SAleksandr Rybalko { SYS_RES_IRQ, 0, RF_ACTIVE }, 64*76ecefceSIan Lepore RESOURCE_SPEC_END 65a2c472e7SAleksandr Rybalko }; 66a2c472e7SAleksandr Rybalko 67*76ecefceSIan Lepore #define MEMRES 0 68*76ecefceSIan Lepore #define IRQRES 1 69*76ecefceSIan Lepore 70398c1838SIan Lepore static struct ofw_compat_data compat_data[] = { 71398c1838SIan Lepore {"fsl,imx6sx-wdt", 1}, 72398c1838SIan Lepore {"fsl,imx6sl-wdt", 1}, 73398c1838SIan Lepore {"fsl,imx6q-wdt", 1}, 74398c1838SIan Lepore {"fsl,imx53-wdt", 1}, 75398c1838SIan Lepore {"fsl,imx51-wdt", 1}, 76398c1838SIan Lepore {"fsl,imx50-wdt", 1}, 77398c1838SIan Lepore {"fsl,imx35-wdt", 1}, 78398c1838SIan Lepore {"fsl,imx27-wdt", 1}, 79398c1838SIan Lepore {"fsl,imx25-wdt", 1}, 80398c1838SIan Lepore {"fsl,imx21-wdt", 1}, 81398c1838SIan Lepore {NULL, 0} 82398c1838SIan Lepore }; 83398c1838SIan Lepore 84*76ecefceSIan Lepore static inline uint16_t 85*76ecefceSIan Lepore RD2(struct imx_wdog_softc *sc, bus_size_t offs) 86*76ecefceSIan Lepore { 87a2c472e7SAleksandr Rybalko 88*76ecefceSIan Lepore return bus_read_2(sc->sc_res[MEMRES], offs); 89*76ecefceSIan Lepore } 90a2c472e7SAleksandr Rybalko 91*76ecefceSIan Lepore static inline void 92*76ecefceSIan Lepore WR2(struct imx_wdog_softc *sc, bus_size_t offs, uint16_t val) 93*76ecefceSIan Lepore { 94a2c472e7SAleksandr Rybalko 95*76ecefceSIan Lepore return bus_write_2(sc->sc_res[MEMRES], offs, val); 96*76ecefceSIan Lepore } 97a2c472e7SAleksandr Rybalko 98a2c472e7SAleksandr Rybalko static void 99a2c472e7SAleksandr Rybalko imx_watchdog(void *arg, u_int cmd, int *error) 100a2c472e7SAleksandr Rybalko { 101a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 102a2c472e7SAleksandr Rybalko uint16_t reg; 1036da71028SIan Lepore u_int timeout; 104a2c472e7SAleksandr Rybalko 105a2c472e7SAleksandr Rybalko sc = arg; 106a2c472e7SAleksandr Rybalko mtx_lock(&sc->sc_mtx); 1076da71028SIan Lepore if (cmd == 0) { 1086da71028SIan Lepore if (bootverbose) 1096da71028SIan Lepore device_printf(sc->sc_dev, "Can not be disabled.\n"); 1106da71028SIan Lepore *error = EOPNOTSUPP; 1116da71028SIan Lepore } else { 1126da71028SIan Lepore timeout = (u_int)((1ULL << (cmd & WD_INTERVAL)) / 1000000000U); 113a2c472e7SAleksandr Rybalko if (timeout > 1 && timeout < 128) { 114a2c472e7SAleksandr Rybalko if (timeout != sc->sc_timeout) { 115a2c472e7SAleksandr Rybalko sc->sc_timeout = timeout; 116398c1838SIan Lepore reg = RD2(sc, WDOG_CR_REG); 117a2c472e7SAleksandr Rybalko reg &= ~WDOG_CR_WT_MASK; 118a2c472e7SAleksandr Rybalko reg |= (timeout << (WDOG_CR_WT_SHIFT + 1)) & 119a2c472e7SAleksandr Rybalko WDOG_CR_WT_MASK; 1206da71028SIan Lepore WR2(sc, WDOG_CR_REG, reg | WDOG_CR_WDE); 1216da71028SIan Lepore } 122a2c472e7SAleksandr Rybalko /* Refresh counter */ 123398c1838SIan Lepore WR2(sc, WDOG_SR_REG, WDOG_SR_STEP1); 124398c1838SIan Lepore WR2(sc, WDOG_SR_REG, WDOG_SR_STEP2); 125a2c472e7SAleksandr Rybalko *error = 0; 126a2c472e7SAleksandr Rybalko } 127a2c472e7SAleksandr Rybalko } 128a2c472e7SAleksandr Rybalko mtx_unlock(&sc->sc_mtx); 129a2c472e7SAleksandr Rybalko } 130a2c472e7SAleksandr Rybalko 131a2c472e7SAleksandr Rybalko static int 132a2c472e7SAleksandr Rybalko imx_wdog_probe(device_t dev) 133a2c472e7SAleksandr Rybalko { 134a2c472e7SAleksandr Rybalko 135add35ed5SIan Lepore if (!ofw_bus_status_okay(dev)) 136add35ed5SIan Lepore return (ENXIO); 137add35ed5SIan Lepore 138398c1838SIan Lepore if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 139a2c472e7SAleksandr Rybalko return (ENXIO); 140a2c472e7SAleksandr Rybalko 141398c1838SIan Lepore device_set_desc(dev, "Freescale i.MX Watchdog"); 142a2c472e7SAleksandr Rybalko return (0); 143a2c472e7SAleksandr Rybalko } 144a2c472e7SAleksandr Rybalko 145a2c472e7SAleksandr Rybalko static int 146a2c472e7SAleksandr Rybalko imx_wdog_attach(device_t dev) 147a2c472e7SAleksandr Rybalko { 148a2c472e7SAleksandr Rybalko struct imx_wdog_softc *sc; 149a2c472e7SAleksandr Rybalko 150a2c472e7SAleksandr Rybalko sc = device_get_softc(dev); 151a2c472e7SAleksandr Rybalko sc->sc_dev = dev; 152a2c472e7SAleksandr Rybalko 153a2c472e7SAleksandr Rybalko if (bus_alloc_resources(dev, imx_wdog_spec, sc->sc_res)) { 154a2c472e7SAleksandr Rybalko device_printf(dev, "could not allocate resources\n"); 155a2c472e7SAleksandr Rybalko return (ENXIO); 156a2c472e7SAleksandr Rybalko } 157a2c472e7SAleksandr Rybalko 158a2c472e7SAleksandr Rybalko mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF); 159a2c472e7SAleksandr Rybalko 160a2c472e7SAleksandr Rybalko /* TODO: handle interrupt */ 161a2c472e7SAleksandr Rybalko 162a2c472e7SAleksandr Rybalko EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0); 163a2c472e7SAleksandr Rybalko return (0); 164a2c472e7SAleksandr Rybalko } 165*76ecefceSIan Lepore 166*76ecefceSIan Lepore static device_method_t imx_wdog_methods[] = { 167*76ecefceSIan Lepore DEVMETHOD(device_probe, imx_wdog_probe), 168*76ecefceSIan Lepore DEVMETHOD(device_attach, imx_wdog_attach), 169*76ecefceSIan Lepore DEVMETHOD_END 170*76ecefceSIan Lepore }; 171*76ecefceSIan Lepore 172*76ecefceSIan Lepore static driver_t imx_wdog_driver = { 173*76ecefceSIan Lepore "imx_wdog", 174*76ecefceSIan Lepore imx_wdog_methods, 175*76ecefceSIan Lepore sizeof(struct imx_wdog_softc), 176*76ecefceSIan Lepore }; 177*76ecefceSIan Lepore 178*76ecefceSIan Lepore static devclass_t imx_wdog_devclass; 179*76ecefceSIan Lepore 180*76ecefceSIan Lepore DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); 181