diff mbox series

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

Message ID 1560873155-21570-1-git-send-email-hancock@sedsystems.ca
State Superseded
Delegated to: Stefano Babic
Headers show
Series [U-Boot] driver: watchdog: Add new iMX/LSCH2 WDT driver | expand

Commit Message

Robert Hancock June 18, 2019, 3:52 p.m. UTC
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

Comments

Daniel Sangorrin June 19, 2019, 4:56 a.m. UTC | #1
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
Stefan Roese June 19, 2019, 5:32 a.m. UTC | #2
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
Marek Vasut June 19, 2019, 2:34 p.m. UTC | #3
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.
Robert Hancock June 19, 2019, 3:41 p.m. UTC | #4
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.
>> <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
>
diff mbox series

Patch

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,
+};