Index: stable/11/sys/arm/freescale/imx/imx_machdep.c =================================================================== --- stable/11/sys/arm/freescale/imx/imx_machdep.c (revision 331497) +++ stable/11/sys/arm/freescale/imx/imx_machdep.c (revision 331498) @@ -1,114 +1,132 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Ian Lepore * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_platform.h" #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include +#include #include #include #include SYSCTL_NODE(_hw, OID_AUTO, imx, CTLFLAG_RW, NULL, "i.MX container"); static int last_reset_status; SYSCTL_UINT(_hw_imx, OID_AUTO, last_reset_status, CTLFLAG_RD, &last_reset_status, 0, "Last reset status register"); SYSCTL_STRING(_hw_imx, OID_AUTO, last_reset_reason, CTLFLAG_RD, "unknown", 0, "Last reset reason"); /* * This code which manipulates the watchdog hardware is here to implement * cpu_reset() because the watchdog is the only way for software to reset the * chip. Why here and not in imx_wdog.c? Because there's no requirement that * the watchdog driver be compiled in, but it's nice to be able to reboot even * if it's not. */ void imx_wdog_cpu_reset(vm_offset_t wdcr_physaddr) { - volatile uint16_t * pcr; + volatile uint16_t cr, *pcr; + if ((pcr = devmap_ptov(wdcr_physaddr, sizeof(*pcr))) == NULL) { + printf("imx_wdog_cpu_reset(): " + "cannot find control register... locking up now."); + for (;;) + cpu_spinwait(); + } + cr = *pcr; + /* - * Trigger an immediate reset by clearing the SRS bit in the watchdog - * control register. The reset happens on the next cycle of the wdog - * 32KHz clock, so hang out in a spin loop until the reset takes effect. + * If the watchdog hardware has been set up to trigger an external reset + * signal on watchdog timeout, then we do software-requested rebooting + * the same way, by asserting the external reset signal. * + * Asserting external reset is supposed to result in some external + * component asserting the POR pin on the SoC, possibly after adjusting + * and stabilizing system voltages, or taking other system-wide reset + * actions. Just in case there is some kind of misconfiguration, we + * hang out and do nothing for a full second, then continue on into + * the code to assert a software reset as well. + */ + if (cr & WDOG_CR_WDT) { + cr &= ~WDOG_CR_WDA; /* Assert active-low ext reset bit. */ + *pcr = cr; + DELAY(1000000); + printf("imx_wdog_cpu_reset(): " + "External reset failed, trying internal cpu-reset\n"); + DELAY(10000); /* Time for printf to appear */ + } + + /* * Imx6 erratum ERR004346 says the SRS bit has to be cleared twice * within the same cycle of the 32khz clock to reliably trigger the * reset. Writing it 3 times in a row ensures at least 2 of the writes * happen in the same 32k clock cycle. */ - if ((pcr = devmap_ptov(wdcr_physaddr, sizeof(*pcr))) == NULL) { - printf("cpu_reset() can't find its control register... locking up now."); - } else { - *pcr &= ~WDOG_CR_SRS; - *pcr &= ~WDOG_CR_SRS; - *pcr &= ~WDOG_CR_SRS; - } + cr &= ~WDOG_CR_SRS; /* Assert active-low software reset bit. */ + *pcr = cr; + *pcr = cr; + *pcr = cr; + + /* Reset happens on the next tick of the 32khz clock, wait for it. */ for (;;) - continue; + cpu_spinwait(); } void imx_wdog_init_last_reset(vm_offset_t wdsr_phys) { volatile uint16_t * psr; if ((psr = devmap_ptov(wdsr_phys, sizeof(*psr))) == NULL) return; last_reset_status = *psr; if (last_reset_status & WDOG_RSR_SFTW) { sysctl___hw_imx_last_reset_reason.oid_arg1 = "SoftwareReset"; } else if (last_reset_status & WDOG_RSR_TOUT) { sysctl___hw_imx_last_reset_reason.oid_arg1 = "WatchdogTimeout"; } else if (last_reset_status & WDOG_RSR_POR) { sysctl___hw_imx_last_reset_reason.oid_arg1 = "PowerOnReset"; } } - -u_int -imx_soc_family(void) -{ - return (imx_soc_type() >> IMXSOC_FAMSHIFT); -} - Index: stable/11/sys/arm/freescale/imx/imx_machdep.h =================================================================== --- stable/11/sys/arm/freescale/imx/imx_machdep.h (revision 331497) +++ stable/11/sys/arm/freescale/imx/imx_machdep.h (revision 331498) @@ -1,67 +1,72 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2013 Ian Lepore * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #ifndef IMX_MACHDEP_H #define IMX_MACHDEP_H #include #include SYSCTL_DECL(_hw_imx); /* Common functions, implemented in imx_machdep.c. */ void imx_wdog_cpu_reset(vm_offset_t _wdcr_phys) __attribute__((__noreturn__)); void imx_wdog_init_last_reset(vm_offset_t _wdsr_phys); /* From here down, routines are implemented in imxNN_machdep.c. */ /* * SoC identity. * According to the documentation, there is such a thing as an i.MX6 Dual * (non-lite flavor). However, Freescale doesn't seem to have assigned it a * number in their code for determining the SoC type in u-boot. * * To-do: put silicon revision numbers into the low-order bits somewhere. */ #define IMXSOC_51 0x51000000 #define IMXSOC_53 0x53000000 #define IMXSOC_6SL 0x60000000 #define IMXSOC_6DL 0x61000000 #define IMXSOC_6S 0x62000000 #define IMXSOC_6Q 0x63000000 #define IMXSOC_6UL 0x64000000 #define IMXSOC_FAMSHIFT 28 u_int imx_soc_type(void); -u_int imx_soc_family(void); + +static inline u_int +imx_soc_family(void) +{ + return (imx_soc_type() >> IMXSOC_FAMSHIFT); +} #endif Index: stable/11/sys/arm/freescale/imx/imx_wdog.c =================================================================== --- stable/11/sys/arm/freescale/imx/imx_wdog.c (revision 331497) +++ stable/11/sys/arm/freescale/imx/imx_wdog.c (revision 331498) @@ -1,177 +1,230 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012, 2013 The FreeBSD Foundation * All rights reserved. * * This software was developed by Oleksandr Rybalko under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include #include struct imx_wdog_softc { struct mtx sc_mtx; device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; struct resource *sc_res[2]; + void *sc_ih; uint32_t sc_timeout; + bool sc_pde_enabled; }; static struct resource_spec imx_wdog_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { SYS_RES_IRQ, 0, RF_ACTIVE }, - { -1, 0 } + RESOURCE_SPEC_END }; +#define MEMRES 0 +#define IRQRES 1 + static struct ofw_compat_data compat_data[] = { {"fsl,imx6sx-wdt", 1}, {"fsl,imx6sl-wdt", 1}, {"fsl,imx6q-wdt", 1}, {"fsl,imx53-wdt", 1}, {"fsl,imx51-wdt", 1}, {"fsl,imx50-wdt", 1}, {"fsl,imx35-wdt", 1}, {"fsl,imx27-wdt", 1}, {"fsl,imx25-wdt", 1}, {"fsl,imx21-wdt", 1}, {NULL, 0} }; -static void imx_watchdog(void *, u_int, int *); -static int imx_wdog_probe(device_t); -static int imx_wdog_attach(device_t); +static inline uint16_t +RD2(struct imx_wdog_softc *sc, bus_size_t offs) +{ -static device_method_t imx_wdog_methods[] = { - DEVMETHOD(device_probe, imx_wdog_probe), - DEVMETHOD(device_attach, imx_wdog_attach), - DEVMETHOD_END -}; + return (bus_read_2(sc->sc_res[MEMRES], offs)); +} -static driver_t imx_wdog_driver = { - "imx_wdog", - imx_wdog_methods, - sizeof(struct imx_wdog_softc), -}; -static devclass_t imx_wdog_devclass; -DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); +static inline void +WR2(struct imx_wdog_softc *sc, bus_size_t offs, uint16_t val) +{ -#define RD2(_sc, _r) \ - bus_space_read_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r)) -#define WR2(_sc, _r, _v) \ - bus_space_write_2((_sc)->sc_bst, (_sc)->sc_bsh, (_r), (_v)) + bus_write_2(sc->sc_res[MEMRES], offs, val); +} static void imx_watchdog(void *arg, u_int cmd, int *error) { struct imx_wdog_softc *sc; uint16_t reg; u_int timeout; sc = arg; mtx_lock(&sc->sc_mtx); if (cmd == 0) { if (bootverbose) device_printf(sc->sc_dev, "Can not be disabled.\n"); *error = EOPNOTSUPP; } else { timeout = (u_int)((1ULL << (cmd & WD_INTERVAL)) / 1000000000U); if (timeout > 1 && timeout < 128) { if (timeout != sc->sc_timeout) { sc->sc_timeout = timeout; reg = RD2(sc, WDOG_CR_REG); reg &= ~WDOG_CR_WT_MASK; reg |= (timeout << (WDOG_CR_WT_SHIFT + 1)) & WDOG_CR_WT_MASK; WR2(sc, WDOG_CR_REG, reg | WDOG_CR_WDE); } /* Refresh counter */ WR2(sc, WDOG_SR_REG, WDOG_SR_STEP1); WR2(sc, WDOG_SR_REG, WDOG_SR_STEP2); + /* Watchdog active, can disable rom-boot watchdog. */ + if (sc->sc_pde_enabled) { + sc->sc_pde_enabled = false; + reg = RD2(sc, WDOG_MCR_REG); + WR2(sc, WDOG_MCR_REG, reg & ~WDOG_MCR_PDE); + } *error = 0; } } mtx_unlock(&sc->sc_mtx); } static int +imx_wdog_intr(void *arg) +{ + struct imx_wdog_softc *sc = arg; + + /* + * When configured for external reset, the actual reset is supposed to + * happen when some external device responds to the assertion of the + * WDOG_B signal by asserting the POR signal to the chip. This + * interrupt handler is a backstop mechanism; it is set up to fire + * simultaneously with WDOG_B, and if the external reset happens we'll + * never actually make it to here. If we do make it here, just trigger + * a software reset. That code will see that external reset is + * configured, and it will wait for 1 second for it to take effect, then + * it will do a software reset as a fallback. + */ + imx_wdog_cpu_reset(BUS_SPACE_PHYSADDR(sc->sc_res[MEMRES], WDOG_CR_REG)); + + return (FILTER_HANDLED); /* unreached */ +} + +static int imx_wdog_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); device_set_desc(dev, "Freescale i.MX Watchdog"); return (0); } static int imx_wdog_attach(device_t dev) { struct imx_wdog_softc *sc; sc = device_get_softc(dev); sc->sc_dev = dev; if (bus_alloc_resources(dev, imx_wdog_spec, sc->sc_res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } mtx_init(&sc->sc_mtx, device_get_nameunit(dev), "imx_wdt", MTX_DEF); - sc->sc_dev = dev; - sc->sc_bst = rman_get_bustag(sc->sc_res[0]); - sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); + /* + * If we're configured to assert an external reset signal, set up the + * hardware to do so, and install an interrupt handler whose only + * purpose is to backstop the external reset. Don't worry if the + * interrupt setup fails, since it's only a backstop measure. + */ + if (ofw_bus_has_prop(sc->sc_dev, "fsl,ext-reset-output")) { + WR2(sc, WDOG_CR_REG, WDOG_CR_WDT | RD2(sc, WDOG_CR_REG)); + bus_setup_intr(sc->sc_dev, sc->sc_res[IRQRES], + INTR_TYPE_MISC | INTR_MPSAFE, imx_wdog_intr, NULL, sc, + &sc->sc_ih); + WR2(sc, WDOG_ICR_REG, WDOG_ICR_WIE); /* Enable, count is 0. */ + } - /* TODO: handle interrupt */ + /* + * Note whether the rom-boot so-called "power-down" watchdog is active, + * so we can disable it when the regular watchdog is first enabled. + */ + if (RD2(sc, WDOG_MCR_REG) & WDOG_MCR_PDE) + sc->sc_pde_enabled = true; EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0); return (0); } + +static device_method_t imx_wdog_methods[] = { + DEVMETHOD(device_probe, imx_wdog_probe), + DEVMETHOD(device_attach, imx_wdog_attach), + DEVMETHOD_END +}; + +static driver_t imx_wdog_driver = { + "imx_wdog", + imx_wdog_methods, + sizeof(struct imx_wdog_softc), +}; + +static devclass_t imx_wdog_devclass; + +DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); Index: stable/11/sys/arm/freescale/imx/imx_wdogreg.h =================================================================== --- stable/11/sys/arm/freescale/imx/imx_wdogreg.h (revision 331497) +++ stable/11/sys/arm/freescale/imx/imx_wdogreg.h (revision 331498) @@ -1,64 +1,64 @@ /*- * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * * Copyright (c) 2012, 2013 The FreeBSD Foundation * All rights reserved. * * This software was developed by Oleksandr Rybalko under sponsorship * from the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ */ #define WDOG_CLK_FREQ 32768 #define WDOG_CR_REG 0x00 /* Control Register */ -#define WDOG_CR_WT_MASK 0xff00 /* Count of 0.5 sec */ -#define WDOG_CR_WT_SHIFT 8 -#define WDOG_CR_WDW (1 << 7) /* Suspend WDog */ -#define WDOG_CR_WDA (1 << 5) /* Don't touch ipp_wdog */ -#define WDOG_CR_SRS (1 << 4) /* Don't touch sys_reset */ -#define WDOG_CR_WDT (1 << 3) /* Assert ipp_wdog on tout */ -#define WDOG_CR_WDE (1 << 2) /* WDog Enable */ -#define WDOG_CR_WDBG (1 << 1) /* Suspend when DBG mode */ -#define WDOG_CR_WDZST (1 << 0) /* Suspend when LP mode */ +#define WDOG_CR_WT_MASK 0xff00 /* Count; 0.5 sec units */ +#define WDOG_CR_WT_SHIFT 8 +#define WDOG_CR_WDW (1u << 7) /* Suspend when in WAIT mode */ +#define WDOG_CR_WDA (1u << 5) /* Don't assert ext reset */ +#define WDOG_CR_SRS (1u << 4) /* Don't assert soft reset */ +#define WDOG_CR_WDT (1u << 3) /* Assert ext reset on timeout */ +#define WDOG_CR_WDE (1u << 2) /* Watchdog Enable */ +#define WDOG_CR_WDBG (1u << 1) /* Suspend when DBG mode */ +#define WDOG_CR_WDZST (1u << 0) /* Suspend when LP mode */ #define WDOG_SR_REG 0x02 /* Service Register */ -#define WDOG_SR_STEP1 0x5555 -#define WDOG_SR_STEP2 0xaaaa +#define WDOG_SR_STEP1 0x5555 +#define WDOG_SR_STEP2 0xaaaa #define WDOG_RSR_REG 0x04 /* Reset Status Register */ -#define WDOG_RSR_POR (1 << 4) /* Due to Power-On Reset */ -#define WDOG_RSR_TOUT (1 << 1) /* Due WDog timeout reset */ -#define WDOG_RSR_SFTW (1 << 0) /* Due Soft reset */ +#define WDOG_RSR_POR (1u << 4) /* Due to Power-On Reset */ +#define WDOG_RSR_TOUT (1u << 1) /* Due WDog timeout reset */ +#define WDOG_RSR_SFTW (1u << 0) /* Due Soft reset */ #define WDOG_ICR_REG 0x06 /* Interrupt Control Register */ -#define WDOG_ICR_WIE (1 << 15) /* Enable Interrupt */ -#define WDOG_ICR_WTIS (1 << 14) /* Interrupt has occurred */ -#define WDOG_ICR_WTCT_MASK 0x00ff -#define WDOG_ICR_WTCT_SHIFT 0 /* Interrupt hold time */ +#define WDOG_ICR_WIE (1u << 15) /* Enable Interrupt */ +#define WDOG_ICR_WTIS (1u << 14) /* Interrupt has occurred */ +#define WDOG_ICR_WTCT_MASK 0x00ff /* Interrupt lead time in 0.5s */ +#define WDOG_ICR_WTCT_SHIFT 0 /* units before reset occurs */ #define WDOG_MCR_REG 0x08 /* Miscellaneous Control Register */ -#define WDOG_MCR_PDE (1 << 0) +#define WDOG_MCR_PDE (1u << 0) /* Power-down enable */ Index: stable/11 =================================================================== --- stable/11 (revision 331497) +++ stable/11 (revision 331498) Property changes on: stable/11 ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r328345,328349,328405,328407,328442