[U-Boot] [PATCH] driver: watchdog: Add new iMX/LSCH2 WDT driver

This is a new watchdog timer driver for iMX and LSCH2 using the WDT framework and driver model. This allows ensuring that U-Boot uses the same watchdog timer instance and same settings (ex: internal or external reset) specified in the device tree.
This driver can be used in preference to the old imx_watchdog driver for boards which have been converted to use the driver model.
Signed-off-by: Robert Hancock hancock@sedsystems.ca --- drivers/watchdog/Kconfig | 14 ++++-- drivers/watchdog/Makefile | 3 ++ drivers/watchdog/imx_wdt.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/imx_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dbafb74..0e8c8e5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -27,11 +27,11 @@ config BCM2835_WDT hardware, with a max timeout of ~15secs.
config IMX_WATCHDOG - bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + bool "Enable legacy Watchdog Timer support for IMX and LSCH2 of NXP" select HW_WATCHDOG help - Select this to enable the IMX and LSCH2 of Layerscape watchdog - driver. + Select this to enable the IMX and LSCH2 of Layerscape legacy watchdog + driver (not using driver model).
config OMAP_WATCHDOG bool "TI OMAP watchdog driver" @@ -109,6 +109,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform.
+config WDT_IMX + bool "iMX/LSCH2 watchdog timer support" + depends on WDT && (ARCH_MX25 || ARCH_MX31 || ARCH_MX35 || ARCH_MX5 || ARCH_MX6 || ARCH_MX7 || ARCH_VF610) + imply WATCHDOG + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver using driver model. + config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e3f4fdb..49dd457 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -5,11 +5,13 @@
obj-$(CONFIG_WDT_AT91) += at91sam9_wdt.o obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o +ifndef CONFIG_WDT_IMX ifneq (,$(filter $(SOC), mx25 mx31 mx35 mx5 mx6 mx7 vf610)) obj-y += imx_watchdog.o else obj-$(CONFIG_IMX_WATCHDOG) += imx_watchdog.o endif +endif obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -24,6 +26,7 @@ obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_IMX) += imx_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/imx_wdt.c b/drivers/watchdog/imx_wdt.c new file mode 100644 index 0000000..1b4a5e6 --- /dev/null +++ b/drivers/watchdog/imx_wdt.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * imx_wdt.c - WDT driver for Freescale/NXP i.MX on-chip watchdog + * Copyright (c) 2019 SED Systems, a division of Calian Ltd. + * + * Based on Linux 4.19 drivers/watchdog/imx2_wdt.c which is: + * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. w.sang@pengutronix.de + * Copyright (C) 2014 Freescale Semiconductor, Inc. + * + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <fsl_wdog.h> + +struct imx_wdt_priv { + struct watchdog_regs *regs; + bool ext_reset; +}; + +static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + u16 timeout_reg = (timeout / 500) - 1; + u16 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS | + WCR_WDA | SET_WCR_WT(timeout_reg); + + if (priv->ext_reset) + wcr |= WCR_WDT; + + debug("%s timeout %llu, wcr %04hX\n", __func__, timeout, wcr); + + writew(wcr, &priv->regs->wcr); + + return 0; +} + +static int imx_wdt_reset(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + writew(0x5555, &priv->regs->wsr); + writew(0xaaaa, &priv->regs->wsr); + return 0; +} + +static int imx_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + u16 wcr = WCR_WDE; + + if (priv->ext_reset) + wcr |= WCR_SRS; /* do not assert internal reset */ + else + wcr |= WCR_WDA; /* do not assert external reset */ + + debug("%s wcr %04hX\n", __func__, wcr); + + /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */ + writew(wcr, &priv->regs->wcr); + writew(wcr, &priv->regs->wcr); + writew(wcr, &priv->regs->wcr); + + return 0; +} + +static int imx_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + + priv->regs = devfdt_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs); + + priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output"); + + debug("%s: ext_reset %d\n", __func__, (int)priv->ext_reset); + return 0; +} + +static const struct wdt_ops imx_wdt_ops = { + .start = imx_wdt_start, + .reset = imx_wdt_reset, + .expire_now = imx_wdt_expire_now, +}; + +static const struct udevice_id imx_wdt_ids[] = { + { .compatible = "fsl,imx21-wdt", }, + {} +}; + +static int imx_wdt_probe(struct udevice *dev) +{ + debug("%s() wdt%u\n", __func__, dev->seq); + + return 0; +} + +U_BOOT_DRIVER(imx_wdt) = { + .name = "imx_wdt", + .id = UCLASS_WDT, + .of_match = imx_wdt_ids, + .probe = imx_wdt_probe, + .priv_auto_alloc_size = sizeof(struct imx_wdt_priv), + .ofdata_to_platdata = imx_wdt_ofdata_to_platdata, + .ops = &imx_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +};

Hello Robert,
I am not an expert on this, but I have been modifying a watchdog driver lately. Please check my comments below, although they may need a review from the corresponding maintainer:
-----Original Message----- From: U-Boot u-boot-bounces@lists.denx.de On Behalf Of Robert Hancock Sent: Wednesday, June 19, 2019 12:53 AM To: u-boot@lists.denx.de Subject: [U-Boot] [PATCH] driver: watchdog: Add new iMX/LSCH2 WDT driver
This is a new watchdog timer driver for iMX and LSCH2 using the WDT framework and driver model. This allows ensuring that U-Boot uses the same watchdog timer instance and same settings (ex: internal or external reset) specified in the device tree.
This driver can be used in preference to the old imx_watchdog driver for boards which have been converted to use the driver model.
Signed-off-by: Robert Hancock hancock@sedsystems.ca
drivers/watchdog/Kconfig | 14 ++++-- drivers/watchdog/Makefile | 3 ++ drivers/watchdog/imx_wdt.c | 112
Why don't you overwrite drivers/watchdog/imx_watchdog.c?
+++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/imx_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dbafb74..0e8c8e5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -27,11 +27,11 @@ config BCM2835_WDT hardware, with a max timeout of ~15secs.
config IMX_WATCHDOG
- bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
- bool "Enable legacy Watchdog Timer support for IMX and LSCH2 of NXP" select HW_WATCHDOG
Here HW_WATCHDOG is selected but...
help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
driver.
Select this to enable the IMX and LSCH2 of Layerscape legacy watchdog
driver (not using driver model).
config OMAP_WATCHDOG bool "TI OMAP watchdog driver" @@ -109,6 +109,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform.
+config WDT_IMX
- bool "iMX/LSCH2 watchdog timer support"
- depends on WDT && (ARCH_MX25 || ARCH_MX31 || ARCH_MX35 || ARCH_MX5 || ARCH_MX6 ||
ARCH_MX7 || ARCH_VF610)
- imply WATCHDOG
here you imply WATCHDOG. # Actually, I have a patch for Kconfig pending to avoid this situation.
I have seen somewhere (include/watchdog.h I think) that these two options are incompatible. I believe that the new way is to use WATCHDOG so probably you can safely discard HW_WATCHDOG.
- help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
driver using driver model.
config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e3f4fdb..49dd457 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -5,11 +5,13 @@
obj-$(CONFIG_WDT_AT91) += at91sam9_wdt.o obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o +ifndef CONFIG_WDT_IMX ifneq (,$(filter $(SOC), mx25 mx31 mx35 mx5 mx6 mx7 vf610)) obj-y += imx_watchdog.o else obj-$(CONFIG_IMX_WATCHDOG) += imx_watchdog.o endif +endif obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -24,6 +26,7 @@ obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_IMX) += imx_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/imx_wdt.c b/drivers/watchdog/imx_wdt.c new file mode 100644 index 0000000..1b4a5e6 --- /dev/null +++ b/drivers/watchdog/imx_wdt.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- imx_wdt.c - WDT driver for Freescale/NXP i.MX on-chip watchdog
- Copyright (c) 2019 SED Systems, a division of Calian Ltd.
- Based on Linux 4.19 drivers/watchdog/imx2_wdt.c which is:
- Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. w.sang@pengutronix.de
- Copyright (C) 2014 Freescale Semiconductor, Inc.
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <fsl_wdog.h>
+struct imx_wdt_priv {
- struct watchdog_regs *regs;
- bool ext_reset;
+};
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- u16 timeout_reg = (timeout / 500) - 1;
I think that using "do_div" (from div64.h) here is better (optimized). Also, you are not casting the u64, don't you get any warning? Don't you need to check if the timeout value is higher than what you can store in 16 bits?
- u16 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
WCR_WDA | SET_WCR_WT(timeout_reg);
- if (priv->ext_reset)
wcr |= WCR_WDT;
- debug("%s timeout %llu, wcr %04hX\n", __func__, timeout, wcr);
- writew(wcr, &priv->regs->wcr);
- return 0;
+}
+static int imx_wdt_reset(struct udevice *dev) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- writew(0x5555, &priv->regs->wsr);
- writew(0xaaaa, &priv->regs->wsr);
- return 0;
+}
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- u16 wcr = WCR_WDE;
- if (priv->ext_reset)
wcr |= WCR_SRS; /* do not assert internal reset */
- else
wcr |= WCR_WDA; /* do not assert external reset */
- debug("%s wcr %04hX\n", __func__, wcr);
- /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
- writew(wcr, &priv->regs->wcr);
- writew(wcr, &priv->regs->wcr);
- writew(wcr, &priv->regs->wcr);
- return 0;
+}
+static int imx_wdt_ofdata_to_platdata(struct udevice *dev) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- priv->regs = devfdt_get_addr_ptr(dev);
- if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
- priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
- debug("%s: ext_reset %d\n", __func__, (int)priv->ext_reset);
- return 0;
+}
+static const struct wdt_ops imx_wdt_ops = {
- .start = imx_wdt_start,
- .reset = imx_wdt_reset,
- .expire_now = imx_wdt_expire_now,
Is there any reason for not implementing "stop"?
+};
+static const struct udevice_id imx_wdt_ids[] = {
- { .compatible = "fsl,imx21-wdt", },
- {}
+};
+static int imx_wdt_probe(struct udevice *dev) +{
- debug("%s() wdt%u\n", __func__, dev->seq);
- return 0;
+}
+U_BOOT_DRIVER(imx_wdt) = {
- .name = "imx_wdt",
- .id = UCLASS_WDT,
- .of_match = imx_wdt_ids,
- .probe = imx_wdt_probe,
- .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
- .ofdata_to_platdata = imx_wdt_ofdata_to_platdata,
- .ops = &imx_wdt_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};
Btw, have you tested that CMD_WDT works?
Thanks, Daniel
-- 1.8.3.1
U-Boot mailing list U-Boot@lists.denx.de https://lists.denx.de/listinfo/u-boot

On 6/19/19 6:56 AM, daniel.sangorrin@toshiba.co.jp wrote:
Hello Robert,
I am not an expert on this, but I have been modifying a watchdog driver lately. Please check my comments below, although they may need a review from the corresponding maintainer:
-----Original Message----- From: U-Boot u-boot-bounces@lists.denx.de On Behalf Of Robert Hancock Sent: Wednesday, June 19, 2019 12:53 AM To: u-boot@lists.denx.de Subject: [U-Boot] [PATCH] driver: watchdog: Add new iMX/LSCH2 WDT driver
This is a new watchdog timer driver for iMX and LSCH2 using the WDT framework and driver model. This allows ensuring that U-Boot uses the same watchdog timer instance and same settings (ex: internal or external reset) specified in the device tree.
This driver can be used in preference to the old imx_watchdog driver for boards which have been converted to use the driver model.
Signed-off-by: Robert Hancock hancock@sedsystems.ca
drivers/watchdog/Kconfig | 14 ++++-- drivers/watchdog/Makefile | 3 ++ drivers/watchdog/imx_wdt.c | 112
Why don't you overwrite drivers/watchdog/imx_watchdog.c?
Because there are still non-DM systems using it. However, I posted patches to add DM and DT probing support for imx_watchdog, so use that.

Hi Robert,
(Cc'ing Marek and Heiko)
On 18.06.19 17:52, Robert Hancock wrote:
This is a new watchdog timer driver for iMX and LSCH2 using the WDT framework and driver model. This allows ensuring that U-Boot uses the same watchdog timer instance and same settings (ex: internal or external reset) specified in the device tree.
This driver can be used in preference to the old imx_watchdog driver for boards which have been converted to use the driver model.
Signed-off-by: Robert Hancock hancock@sedsystems.ca
Marek just recently added DM (WDT) support to the imx driver:
https://patchwork.ozlabs.org/patch/1112591/ https://patchwork.ozlabs.org/patch/1112592/
Please take a look at this driver.
Thanks, Stefan
drivers/watchdog/Kconfig | 14 ++++-- drivers/watchdog/Makefile | 3 ++ drivers/watchdog/imx_wdt.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/imx_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dbafb74..0e8c8e5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -27,11 +27,11 @@ config BCM2835_WDT hardware, with a max timeout of ~15secs.
config IMX_WATCHDOG
- bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP"
- bool "Enable legacy Watchdog Timer support for IMX and LSCH2 of NXP" select HW_WATCHDOG help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
driver.
Select this to enable the IMX and LSCH2 of Layerscape legacy watchdog
driver (not using driver model).
config OMAP_WATCHDOG bool "TI OMAP watchdog driver"
@@ -109,6 +109,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform.
+config WDT_IMX
- bool "iMX/LSCH2 watchdog timer support"
- depends on WDT && (ARCH_MX25 || ARCH_MX31 || ARCH_MX35 || ARCH_MX5 || ARCH_MX6 || ARCH_MX7 || ARCH_VF610)
- imply WATCHDOG
- help
Select this to enable the IMX and LSCH2 of Layerscape watchdog
driver using driver model.
- config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e3f4fdb..49dd457 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -5,11 +5,13 @@
obj-$(CONFIG_WDT_AT91) += at91sam9_wdt.o obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o +ifndef CONFIG_WDT_IMX ifneq (,$(filter $(SOC), mx25 mx31 mx35 mx5 mx6 mx7 vf610)) obj-y += imx_watchdog.o else obj-$(CONFIG_IMX_WATCHDOG) += imx_watchdog.o endif +endif obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -24,6 +26,7 @@ obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_IMX) += imx_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/imx_wdt.c b/drivers/watchdog/imx_wdt.c new file mode 100644 index 0000000..1b4a5e6 --- /dev/null +++ b/drivers/watchdog/imx_wdt.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- imx_wdt.c - WDT driver for Freescale/NXP i.MX on-chip watchdog
- Copyright (c) 2019 SED Systems, a division of Calian Ltd.
- Based on Linux 4.19 drivers/watchdog/imx2_wdt.c which is:
- Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. w.sang@pengutronix.de
- Copyright (C) 2014 Freescale Semiconductor, Inc.
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <fsl_wdog.h>
+struct imx_wdt_priv {
- struct watchdog_regs *regs;
- bool ext_reset;
+};
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- u16 timeout_reg = (timeout / 500) - 1;
- u16 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS |
WCR_WDA | SET_WCR_WT(timeout_reg);
- if (priv->ext_reset)
wcr |= WCR_WDT;
- debug("%s timeout %llu, wcr %04hX\n", __func__, timeout, wcr);
- writew(wcr, &priv->regs->wcr);
- return 0;
+}
+static int imx_wdt_reset(struct udevice *dev) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- writew(0x5555, &priv->regs->wsr);
- writew(0xaaaa, &priv->regs->wsr);
- return 0;
+}
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- u16 wcr = WCR_WDE;
- if (priv->ext_reset)
wcr |= WCR_SRS; /* do not assert internal reset */
- else
wcr |= WCR_WDA; /* do not assert external reset */
- debug("%s wcr %04hX\n", __func__, wcr);
- /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */
- writew(wcr, &priv->regs->wcr);
- writew(wcr, &priv->regs->wcr);
- writew(wcr, &priv->regs->wcr);
- return 0;
+}
+static int imx_wdt_ofdata_to_platdata(struct udevice *dev) +{
- struct imx_wdt_priv *priv = dev_get_priv(dev);
- priv->regs = devfdt_get_addr_ptr(dev);
- if (IS_ERR(priv->regs))
return PTR_ERR(priv->regs);
- priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
- debug("%s: ext_reset %d\n", __func__, (int)priv->ext_reset);
- return 0;
+}
+static const struct wdt_ops imx_wdt_ops = {
- .start = imx_wdt_start,
- .reset = imx_wdt_reset,
- .expire_now = imx_wdt_expire_now,
+};
+static const struct udevice_id imx_wdt_ids[] = {
- { .compatible = "fsl,imx21-wdt", },
- {}
+};
+static int imx_wdt_probe(struct udevice *dev) +{
- debug("%s() wdt%u\n", __func__, dev->seq);
- return 0;
+}
+U_BOOT_DRIVER(imx_wdt) = {
- .name = "imx_wdt",
- .id = UCLASS_WDT,
- .of_match = imx_wdt_ids,
- .probe = imx_wdt_probe,
- .priv_auto_alloc_size = sizeof(struct imx_wdt_priv),
- .ofdata_to_platdata = imx_wdt_ofdata_to_platdata,
- .ops = &imx_wdt_ops,
- .flags = DM_FLAG_PRE_RELOC,
+};
Viele Grüße, Stefan

On 2019-06-18 11:32 p.m., Stefan Roese wrote:
Hi Robert,
(Cc'ing Marek and Heiko)
On 18.06.19 17:52, Robert Hancock wrote:
This is a new watchdog timer driver for iMX and LSCH2 using the WDT framework and driver model. This allows ensuring that U-Boot uses the same watchdog timer instance and same settings (ex: internal or external reset) specified in the device tree.
This driver can be used in preference to the old imx_watchdog driver for boards which have been converted to use the driver model.
Signed-off-by: Robert Hancock hancock@sedsystems.ca
Marek just recently added DM (WDT) support to the imx driver:
https://patchwork.ozlabs.org/patch/1112591/ https://patchwork.ozlabs.org/patch/1112592/
Please take a look at this driver.
It looks like that may be a better base for this support. There are a few things in my version that are still missing in the existing imx driver such as the external reset output handling and the better immediate reset handling, but if Marek's patch is being accepted I can implement that support on top of those changes.
Thanks, Stefan
drivers/watchdog/Kconfig | 14 ++++-- drivers/watchdog/Makefile | 3 ++ drivers/watchdog/imx_wdt.c | 112 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 drivers/watchdog/imx_wdt.c
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index dbafb74..0e8c8e5 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -27,11 +27,11 @@ config BCM2835_WDT hardware, with a max timeout of ~15secs. config IMX_WATCHDOG - bool "Enable Watchdog Timer support for IMX and LSCH2 of NXP" + bool "Enable legacy Watchdog Timer support for IMX and LSCH2 of NXP" select HW_WATCHDOG help - Select this to enable the IMX and LSCH2 of Layerscape watchdog - driver. + Select this to enable the IMX and LSCH2 of Layerscape legacy watchdog + driver (not using driver model). config OMAP_WATCHDOG bool "TI OMAP watchdog driver" @@ -109,6 +109,14 @@ config WDT_CDNS Select this to enable Cadence watchdog timer, which can be found on some Xilinx Microzed Platform. +config WDT_IMX + bool "iMX/LSCH2 watchdog timer support" + depends on WDT && (ARCH_MX25 || ARCH_MX31 || ARCH_MX35 || ARCH_MX5 || ARCH_MX6 || ARCH_MX7 || ARCH_VF610) + imply WATCHDOG + help + Select this to enable the IMX and LSCH2 of Layerscape watchdog + driver using driver model.
config WDT_MPC8xx bool "MPC8xx watchdog timer support" depends on WDT && MPC8xx diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index e3f4fdb..49dd457 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -5,11 +5,13 @@ obj-$(CONFIG_WDT_AT91) += at91sam9_wdt.o obj-$(CONFIG_FTWDT010_WATCHDOG) += ftwdt010_wdt.o +ifndef CONFIG_WDT_IMX ifneq (,$(filter $(SOC), mx25 mx31 mx35 mx5 mx6 mx7 vf610)) obj-y += imx_watchdog.o else obj-$(CONFIG_IMX_WATCHDOG) += imx_watchdog.o endif +endif obj-$(CONFIG_S5P) += s5p_wdt.o obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o @@ -24,6 +26,7 @@ obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o +obj-$(CONFIG_WDT_IMX) += imx_wdt.o obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o diff --git a/drivers/watchdog/imx_wdt.c b/drivers/watchdog/imx_wdt.c new file mode 100644 index 0000000..1b4a5e6 --- /dev/null +++ b/drivers/watchdog/imx_wdt.c @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: GPL-2.0+ +/*
- imx_wdt.c - WDT driver for Freescale/NXP i.MX on-chip watchdog
- Copyright (c) 2019 SED Systems, a division of Calian Ltd.
- Based on Linux 4.19 drivers/watchdog/imx2_wdt.c which is:
- * Copyright (C) 2010 Wolfram Sang, Pengutronix e.K.
- * Copyright (C) 2014 Freescale Semiconductor, Inc.
- */
+#include <common.h> +#include <dm.h> +#include <errno.h> +#include <wdt.h> +#include <asm/io.h> +#include <asm/arch/imx-regs.h> +#include <fsl_wdog.h>
+struct imx_wdt_priv { + struct watchdog_regs *regs; + bool ext_reset; +};
+static int imx_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + u16 timeout_reg = (timeout / 500) - 1; + u16 wcr = WCR_WDZST | WCR_WDBG | WCR_WDE | WCR_SRS | + WCR_WDA | SET_WCR_WT(timeout_reg);
+ if (priv->ext_reset) + wcr |= WCR_WDT;
+ debug("%s timeout %llu, wcr %04hX\n", __func__, timeout, wcr);
+ writew(wcr, &priv->regs->wcr);
+ return 0; +}
+static int imx_wdt_reset(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev);
+ writew(0x5555, &priv->regs->wsr); + writew(0xaaaa, &priv->regs->wsr); + return 0; +}
+static int imx_wdt_expire_now(struct udevice *dev, ulong flags) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev); + u16 wcr = WCR_WDE;
+ if (priv->ext_reset) + wcr |= WCR_SRS; /* do not assert internal reset */ + else + wcr |= WCR_WDA; /* do not assert external reset */
+ debug("%s wcr %04hX\n", __func__, wcr);
+ /* Write 3 times to ensure it works, due to IMX6Q errata ERR004346 */ + writew(wcr, &priv->regs->wcr); + writew(wcr, &priv->regs->wcr); + writew(wcr, &priv->regs->wcr);
+ return 0; +}
+static int imx_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct imx_wdt_priv *priv = dev_get_priv(dev);
+ priv->regs = devfdt_get_addr_ptr(dev); + if (IS_ERR(priv->regs)) + return PTR_ERR(priv->regs);
+ priv->ext_reset = dev_read_bool(dev, "fsl,ext-reset-output");
+ debug("%s: ext_reset %d\n", __func__, (int)priv->ext_reset); + return 0; +}
+static const struct wdt_ops imx_wdt_ops = { + .start = imx_wdt_start, + .reset = imx_wdt_reset, + .expire_now = imx_wdt_expire_now, +};
+static const struct udevice_id imx_wdt_ids[] = { + { .compatible = "fsl,imx21-wdt", }, + {} +};
+static int imx_wdt_probe(struct udevice *dev) +{ + debug("%s() wdt%u\n", __func__, dev->seq);
+ return 0; +}
+U_BOOT_DRIVER(imx_wdt) = { + .name = "imx_wdt", + .id = UCLASS_WDT, + .of_match = imx_wdt_ids, + .probe = imx_wdt_probe, + .priv_auto_alloc_size = sizeof(struct imx_wdt_priv), + .ofdata_to_platdata = imx_wdt_ofdata_to_platdata, + .ops = &imx_wdt_ops, + .flags = DM_FLAG_PRE_RELOC, +};
Viele Grüße, Stefan
participants (4)
-
daniel.sangorrin@toshiba.co.jp
-
Marek Vasut
-
Robert Hancock
-
Stefan Roese