From 10e7798be762cf09eabe87d329658403f44ab714 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 22 Apr 2019 04:15:22 +0000 Subject: [PATCH] MFC r336070, r336072-r336073, r336076 r336070: Add pnp info and a module makefile for the imx_wdog watchdog driver. r336072: Correctly calculate the value to put in the imx wdog countdown register. The correct value is seconds*2-1. The code was using just seconds*2, which led to being off by a half-second -- usually not a big deal, except when the value was the max (128) it overflowed so zero would get written to the countdown register, which equates to a timeout of a half second. r336073: Add support to the imx watchdog for the FDT "timeout-sec" property, by automatically initializing the watchdog using the given value. Also, attach at BUS_PASS_TIMER to extend watchdog protection to more of the kernel init process. r336076: Add a manpage for the imx5/6 watchdog driver. --- share/man/man4/man4.arm/Makefile | 2 + share/man/man4/man4.arm/imx_wdog.4 | 112 +++++++++++++++++++++++++++++ sys/arm/freescale/imx/imx_wdog.c | 78 ++++++++++++++------ sys/modules/imx/Makefile | 1 + sys/modules/imx/imx_wdog/Makefile | 14 ++++ 5 files changed, 184 insertions(+), 23 deletions(-) create mode 100644 share/man/man4/man4.arm/imx_wdog.4 create mode 100644 sys/modules/imx/imx_wdog/Makefile diff --git a/share/man/man4/man4.arm/Makefile b/share/man/man4/man4.arm/Makefile index 696d2c16e09..d9c35834525 100644 --- a/share/man/man4/man4.arm/Makefile +++ b/share/man/man4/man4.arm/Makefile @@ -4,11 +4,13 @@ PACKAGE=runtime-manuals MAN= cgem.4 \ devcfg.4 \ + imx_wdog.4 \ mge.4 \ npe.4 \ ti_adc.4 MLINKS= cgem.4 if_cgem.4 +MLINKS+= imx_wdog.4 imxwdt.4 MLINKS+= mge.4 if_mge.4 MLINKS+=npe.4 if_npe.4 diff --git a/share/man/man4/man4.arm/imx_wdog.4 b/share/man/man4/man4.arm/imx_wdog.4 new file mode 100644 index 00000000000..062c84b23b2 --- /dev/null +++ b/share/man/man4/man4.arm/imx_wdog.4 @@ -0,0 +1,112 @@ +.\" +.\" Copyright (c) 2018 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 ``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 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$ +.\" +.Dd July 7, 2018 +.Dt IMX_WDOG 4 +.Os +.Sh NAME +.Nm imx_wdog +.Nd device driver for the NXP i.MX5 and i.MX6 watchdog timer +.Sh SYNOPSIS +To compile this driver into the kernel, +place the following line in your +kernel configuration file: +.Bd -ragged -offset indent +.Cd "device imxwdt" +.Ed +.Pp +Alternatively, to load the driver as a +module at boot time, place the following line in +.Xr loader.conf 5 : +.Bd -literal -offset indent +imx_wdog_load="YES" +.Ed +.Sh DESCRIPTION +The +.Nm +driver provides +.Xr watchdog 4 +support for the watchdog timer present on NXP i.MX5 and i.MX6 processors. +The i.MX watchdog hardware supports programmable timeouts ranging from +0.5 to 128 seconds, in half-second increments. +Once activated, the watchdog hardware cannot be deactivated, but the +timeout period can be changed to any valid non-zero value. +.Pp +At power-on, a special 16-second +.Sq power-down timer +mode is automatically enabled by the hardware. +It will assert the external WDOG_B signal, which may be connected to +external hardware that causes the system to reset or power-down. +The power-down timer is often reset by the boot loader (typically U-Boot). +If the power-down timer is still active at the time when the normal +watchdog is first enabled, the +.Nm +driver automatically disables it. +.Pp +The +.Nm +driver supports the FDT +.Va fsl,external-reset +property by enabling the assertion of the WDOG_B external timeout signal +when the property is present. +When running this way, the need to reset the system due to watchdog +timeout is signaled by driving the WDOG_B line low; some external +entity is expected to assert the chip's POR pin in response. +The +.Nm +driver attempts to backstop this external reset by scheduling an +interrupt to occur as well. +The interrupt handler waits 1 second for the external reset to occur, +then it triggers a normal software reset. +Note that the WDOG_B signal can be configured to use a variety of +pins on the chip. +For the +.Va fsl,external-reset +property to be effective, the signal must be connected to an appropriate +pin by the system's FDT pinctrl data. +.Pp +The +.Nm +driver supports the FDT +.Va timeout-secs +property by enabling the watchdog as soon as the driver attaches, +using the given timeout value. +This extends watchdog protection to much of the system startup process, +but it still requires that +.Xr watchdogd 4 +be configured to service the watchdog. +.Sh SEE ALSO +.Xr fdt 4 , +.Xr watchdog 4 , +.Xr watchdog 8 , +.Xr watchdogd 8 , +.Xr watchdog 9 +.Sh HISTORY +The +.Nm +driver first appeared in +.Fx 10.0 . diff --git a/sys/arm/freescale/imx/imx_wdog.c b/sys/arm/freescale/imx/imx_wdog.c index 97f42c15e35..ab38ddfda4e 100644 --- a/sys/arm/freescale/imx/imx_wdog.c +++ b/sys/arm/freescale/imx/imx_wdog.c @@ -97,43 +97,52 @@ WR2(struct imx_wdog_softc *sc, bus_size_t offs, uint16_t val) bus_write_2(sc->sc_res[MEMRES], offs, val); } +static int +imx_wdog_enable(struct imx_wdog_softc *sc, u_int timeout) +{ + uint16_t reg; + + if (timeout < 1 || timeout > 128) + return (EINVAL); + + mtx_lock(&sc->sc_mtx); + if (timeout != sc->sc_timeout) { + sc->sc_timeout = timeout; + reg = RD2(sc, WDOG_CR_REG); + reg &= ~WDOG_CR_WT_MASK; + reg |= ((2 * timeout - 1) << WDOG_CR_WT_SHIFT); + 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); + } + mtx_unlock(&sc->sc_mtx); + + return (0); +} + 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); - } + if (imx_wdog_enable(sc, timeout) == 0) *error = 0; - } } - mtx_unlock(&sc->sc_mtx); } static int @@ -175,6 +184,7 @@ static int imx_wdog_attach(device_t dev) { struct imx_wdog_softc *sc; + pcell_t timeout; sc = device_get_softc(dev); sc->sc_dev = dev; @@ -208,6 +218,26 @@ imx_wdog_attach(device_t dev) sc->sc_pde_enabled = true; EVENTHANDLER_REGISTER(watchdog_list, imx_watchdog, sc, 0); + + /* If there is a timeout-sec property, activate the watchdog. */ + if (OF_getencprop(ofw_bus_get_node(sc->sc_dev), "timeout-sec", + &timeout, sizeof(timeout)) == sizeof(timeout)) { + if (timeout < 1 || timeout > 128) { + device_printf(sc->sc_dev, "ERROR: bad timeout-sec " + "property value %u, using 128\n", timeout); + timeout = 128; + } + imx_wdog_enable(sc, timeout); + device_printf(sc->sc_dev, "watchdog enabled using " + "timeout-sec property value %u\n", timeout); + } + + /* + * The watchdog hardware cannot be disabled, so there's little point in + * coding up a detach() routine to carefully tear everything down, just + * make the device busy so that detach can't happen. + */ + device_busy(sc->sc_dev); return (0); } @@ -225,4 +255,6 @@ static driver_t imx_wdog_driver = { static devclass_t imx_wdog_devclass; -DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, imx_wdog_devclass, 0, 0); +EARLY_DRIVER_MODULE(imx_wdog, simplebus, imx_wdog_driver, + imx_wdog_devclass, 0, 0, BUS_PASS_TIMER); +SIMPLEBUS_PNP_INFO(compat_data); diff --git a/sys/modules/imx/Makefile b/sys/modules/imx/Makefile index b20cb7a0149..75cb283c78d 100644 --- a/sys/modules/imx/Makefile +++ b/sys/modules/imx/Makefile @@ -5,5 +5,6 @@ SUBDIR = \ ../ffec \ imx_i2c \ imx_spi \ + imx_wdog \ .include diff --git a/sys/modules/imx/imx_wdog/Makefile b/sys/modules/imx/imx_wdog/Makefile new file mode 100644 index 00000000000..93e28c74e8e --- /dev/null +++ b/sys/modules/imx/imx_wdog/Makefile @@ -0,0 +1,14 @@ +# $FreeBSD$ + +.PATH: ${SRCTOP}/sys/arm/freescale/imx + +KMOD= imx_wdog +SRCS= imx_wdog.c + +# Generated files... +SRCS+= \ + bus_if.h \ + device_if.h \ + ofw_bus_if.h \ + +.include -- 2.45.0