On Wed, Aug 21, 2019 at 10:37:41PM -0400, Anson Huang wrote:
> The i.MX7ULP Watchdog Timer (WDOG) module is an independent timer
> that is available for system use.
> It provides a safety feature to ensure that software is executing
> as planned and that the CPU is not stuck in an infinite loop or
> executing unintended code. If the WDOG module is not serviced
> (refreshed) within a certain period, it resets the MCU.
>
> Add driver support for i.MX7ULP watchdog.
>
> Signed-off-by: Anson Huang
Reviewed-by: Guenter Roeck
> ---
> Changes since V3:
> - pass clk directly for reset action to avoid dereference from
> structure;
> - use constant instead of variable for wdog clock rate, as it is fixed
> as 1KHz.
> ---
> drivers/watchdog/Kconfig | 13 +++
> drivers/watchdog/Makefile | 1 +
> drivers/watchdog/imx7ulp_wdt.c | 243
> +
> 3 files changed, 257 insertions(+)
> create mode 100644 drivers/watchdog/imx7ulp_wdt.c
>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index a8f5c81..d68e5b5 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -724,6 +724,19 @@ config IMX_SC_WDT
> To compile this driver as a module, choose M here: the
> module will be called imx_sc_wdt.
>
> +config IMX7ULP_WDT
> + tristate "IMX7ULP Watchdog"
> + depends on ARCH_MXC || COMPILE_TEST
> + select WATCHDOG_CORE
> + help
> + This is the driver for the hardware watchdog on the Freescale
> + IMX7ULP and later processors. If you have one of these
> + processors and wish to have watchdog support enabled,
> + say Y, otherwise say N.
> +
> + To compile this driver as a module, choose M here: the
> + module will be called imx7ulp_wdt.
> +
> config UX500_WATCHDOG
> tristate "ST-Ericsson Ux500 watchdog"
> depends on MFD_DB8500_PRCMU
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index b5a0aed..2ee352b 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -67,6 +67,7 @@ obj-$(CONFIG_TS4800_WATCHDOG) += ts4800_wdt.o
> obj-$(CONFIG_TS72XX_WATCHDOG) += ts72xx_wdt.o
> obj-$(CONFIG_IMX2_WDT) += imx2_wdt.o
> obj-$(CONFIG_IMX_SC_WDT) += imx_sc_wdt.o
> +obj-$(CONFIG_IMX7ULP_WDT) += imx7ulp_wdt.o
> obj-$(CONFIG_UX500_WATCHDOG) += ux500_wdt.o
> obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
> obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
> diff --git a/drivers/watchdog/imx7ulp_wdt.c b/drivers/watchdog/imx7ulp_wdt.c
> new file mode 100644
> index 000..5ce5102
> --- /dev/null
> +++ b/drivers/watchdog/imx7ulp_wdt.c
> @@ -0,0 +1,243 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Copyright 2019 NXP.
> + */
> +
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +#include
> +
> +#define WDOG_CS 0x0
> +#define WDOG_CS_CMD32EN BIT(13)
> +#define WDOG_CS_ULK BIT(11)
> +#define WDOG_CS_RCS BIT(10)
> +#define WDOG_CS_EN BIT(7)
> +#define WDOG_CS_UPDATE BIT(5)
> +
> +#define WDOG_CNT 0x4
> +#define WDOG_TOVAL 0x8
> +
> +#define REFRESH_SEQ0 0xA602
> +#define REFRESH_SEQ1 0xB480
> +#define REFRESH ((REFRESH_SEQ1 << 16) | REFRESH_SEQ0)
> +
> +#define UNLOCK_SEQ0 0xC520
> +#define UNLOCK_SEQ1 0xD928
> +#define UNLOCK ((UNLOCK_SEQ1 << 16) | UNLOCK_SEQ0)
> +
> +#define DEFAULT_TIMEOUT 60
> +#define MAX_TIMEOUT 128
> +#define WDOG_CLOCK_RATE 1000
> +
> +static bool nowayout = WATCHDOG_NOWAYOUT;
> +module_param(nowayout, bool, );
> +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started
> (default="
> + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
> +
> +struct imx7ulp_wdt_device {
> + struct notifier_block restart_handler;
> + struct watchdog_device wdd;
> + void __iomem *base;
> + struct clk *clk;
> +};
> +
> +static inline void imx7ulp_wdt_enable(void __iomem *base, bool enable)
> +{
> + u32 val = readl(base + WDOG_CS);
> +
> + writel(UNLOCK, base + WDOG_CNT);
> + if (enable)
> + writel(val | WDOG_CS_EN, base + WDOG_CS);
> + else
> + writel(val & ~WDOG_CS_EN, base + WDOG_CS);
> +}
> +
> +static inline bool imx7ulp_wdt_is_enabled(void __iomem *base)
> +{
> + u32 val = readl(base + WDOG_CS);
> +
> + return val & WDOG_CS_EN;
> +}
> +
> +static int imx7ulp_wdt_ping(struct watchdog_device *wdog)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> +
> + writel(REFRESH, wdt->base + WDOG_CNT);
> +
> + return 0;
> +}
> +
> +static int imx7ulp_wdt_start(struct watchdog_device *wdog)
> +{
> + struct imx7ulp_wdt_device *wdt = watchdog_get_drvdata(wdog);
> +
> + imx7ulp_wdt_enable(wdt->base, true);
> +
> + return 0;
> +}
> +
> +static int imx7ulp_wdt_stop(struct watchdog_device *wdog)
> +{
> + struct