From owner-svn-src-stable-11@freebsd.org Sat Mar 24 21:27:11 2018 Return-Path: Delivered-To: svn-src-stable-11@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 88C9EF4AA34; Sat, 24 Mar 2018 21:27:11 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 3278A8093C; Sat, 24 Mar 2018 21:27:11 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 29D7114C34; Sat, 24 Mar 2018 21:27:11 +0000 (UTC) (envelope-from ian@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id w2OLRBOs076519; Sat, 24 Mar 2018 21:27:11 GMT (envelope-from ian@FreeBSD.org) Received: (from ian@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id w2OLRACu076515; Sat, 24 Mar 2018 21:27:10 GMT (envelope-from ian@FreeBSD.org) Message-Id: <201803242127.w2OLRACu076515@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ian set sender to ian@FreeBSD.org using -f From: Ian Lepore Date: Sat, 24 Mar 2018 21:27:10 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r331498 - stable/11/sys/arm/freescale/imx X-SVN-Group: stable-11 X-SVN-Commit-Author: ian X-SVN-Commit-Paths: stable/11/sys/arm/freescale/imx X-SVN-Commit-Revision: 331498 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-11@freebsd.org X-Mailman-Version: 2.1.25 Precedence: list List-Id: SVN commit messages for only the 11-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 24 Mar 2018 21:27:12 -0000 Author: ian Date: Sat Mar 24 21:27:10 2018 New Revision: 331498 URL: https://svnweb.freebsd.org/changeset/base/331498 Log: MFC r328345, r328349, r328405, r328407, r328442 r328345: Reformat indentation to match other imx5/6 register definition headers, and tweak some comments. No functional changes. r328349: Make the trivial imx_soc_family() function an inline in imx_machdep.h. The imx_machdep.c file is on the fast path to non-existance and this would be the only thing left in it after some watchdog changes are completed. r328405: Minor cleanups... Move DRIVER_MODULE() and other boilerplate stuff to the bottom of the file, where it is in most imx5/6 drivers. Switch from an RD2 macro using bus_space_read_2() to an inline function using bus_read_2(); likewise for WR2. Use RESOURCE_SPEC_END to end the resource_spec list. Net effect should be no functional changes. r328407: Fix return style in RD2. Remove bogus return value from a void function in WR2 (I have no idea why that didn't result in a compile error). r328442: Add support to the imx5/6 watchdog for the external reset signal. Also, if the "power down" watchdog used by the ROM boot code is still active when the regular watchdog is activated, turn off the power-down watchdog. This adds support for the "fsl,ext-reset-output" FDT property. When present, that property indicates that a chip reset is accomplished by asserting the WDOG1_B external signal, which is supposed to trigger some external component such as a PMIC to ready the hardware for reset (for example, adjusting voltages from idle to full-power levels), and assert the POR signal to SoC when ready. To guard against misconfiguation leading to a non-rebootable system, the external reset signal is backstopped by code that asserts a normal internal chip reset if nothing responds to the external reset signal within one second. Modified: stable/11/sys/arm/freescale/imx/imx_machdep.c stable/11/sys/arm/freescale/imx/imx_machdep.h stable/11/sys/arm/freescale/imx/imx_wdog.c stable/11/sys/arm/freescale/imx/imx_wdogreg.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/arm/freescale/imx/imx_machdep.c ============================================================================== --- stable/11/sys/arm/freescale/imx/imx_machdep.c Sat Mar 24 21:22:28 2018 (r331497) +++ stable/11/sys/arm/freescale/imx/imx_machdep.c Sat Mar 24 21:27:10 2018 (r331498) @@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$"); #include #include +#include #include #include @@ -65,27 +66,51 @@ SYSCTL_STRING(_hw_imx, OID_AUTO, last_reset_reason, CT 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 @@ -104,11 +129,4 @@ imx_wdog_init_last_reset(vm_offset_t wdsr_phys) sysctl___hw_imx_last_reset_reason.oid_arg1 = "PowerOnReset"; } } - -u_int -imx_soc_family(void) -{ - return (imx_soc_type() >> IMXSOC_FAMSHIFT); -} - Modified: stable/11/sys/arm/freescale/imx/imx_machdep.h ============================================================================== --- stable/11/sys/arm/freescale/imx/imx_machdep.h Sat Mar 24 21:22:28 2018 (r331497) +++ stable/11/sys/arm/freescale/imx/imx_machdep.h Sat Mar 24 21:27:10 2018 (r331498) @@ -61,7 +61,12 @@ void imx_wdog_init_last_reset(vm_offset_t _wdsr_phys); #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 Modified: stable/11/sys/arm/freescale/imx/imx_wdog.c ============================================================================== --- stable/11/sys/arm/freescale/imx/imx_wdog.c Sat Mar 24 21:22:28 2018 (r331497) +++ stable/11/sys/arm/freescale/imx/imx_wdog.c Sat Mar 24 21:27:10 2018 (r331498) @@ -50,23 +50,27 @@ __FBSDID("$FreeBSD$"); #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}, @@ -81,28 +85,19 @@ static struct ofw_compat_data compat_data[] = { {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) @@ -131,6 +126,12 @@ imx_watchdog(void *arg, u_int cmd, int *error) /* 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; } } @@ -138,6 +139,27 @@ imx_watchdog(void *arg, u_int cmd, int *error) } 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) { @@ -166,12 +188,43 @@ imx_wdog_attach(device_t dev) 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); Modified: stable/11/sys/arm/freescale/imx/imx_wdogreg.h ============================================================================== --- stable/11/sys/arm/freescale/imx/imx_wdogreg.h Sat Mar 24 21:22:28 2018 (r331497) +++ stable/11/sys/arm/freescale/imx/imx_wdogreg.h Sat Mar 24 21:27:10 2018 (r331498) @@ -34,31 +34,31 @@ #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 */