diff mbox series

[3/4] watchdog: cortina_wdt: add support for HW WDT on CAxxxx SoCs

Message ID 1579513995-1822-4-git-send-email-alex.nemirovsky@cortina-access.com
State New
Headers show
Series Add Cortina Access basic DM drivers | expand

Commit Message

Alex Nemirovsky Jan. 20, 2020, 9:53 a.m. UTC
From: Jason Li <jason.li at cortina-access.com>

Add support for hardware watchdog timer on all Cortina Access
CAxxxx family of SoCs.

Signed-off-by: Jason Li <jason.li at cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>
---

 MAINTAINERS                    |   2 +
 drivers/watchdog/Kconfig       |   8 +++
 drivers/watchdog/Makefile      |   1 +
 drivers/watchdog/cortina_wdt.c | 144 +++++++++++++++++++++++++++++++++++++++++
 4 files changed, 155 insertions(+)
 create mode 100644 drivers/watchdog/cortina_wdt.c

Comments

Stefan Roese Jan. 20, 2020, 12:38 p.m. UTC | #1
On 20.01.20 10:53, Alex Nemirovsky wrote:
> From: Jason Li <jason.li at cortina-access.com>
> 
> Add support for hardware watchdog timer on all Cortina Access
> CAxxxx family of SoCs.
> 
> Signed-off-by: Jason Li <jason.li at cortina-access.com>
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>
> ---
> 
>   MAINTAINERS                    |   2 +
>   drivers/watchdog/Kconfig       |   8 +++
>   drivers/watchdog/Makefile      |   1 +
>   drivers/watchdog/cortina_wdt.c | 144 +++++++++++++++++++++++++++++++++++++++++
>   4 files changed, 155 insertions(+)
>   create mode 100644 drivers/watchdog/cortina_wdt.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b7b3359..f9334f9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -180,6 +180,7 @@ F:	board/cortina/common/*
>   F:	board/cortina/common/Kconfig
>   F:	board/cortina/common/armv8/lowlevel_init.S
>   F:	drivers/gpio/cortina_gpio.c
> +F:	drivers/watchdog/cortina_wdt.c
>   
>   ARM/CZ.NIC TURRIS MOX SUPPORT
>   M:	Marek Behun <marek.behun at nic.cz>
> @@ -662,6 +663,7 @@ F:	board/cortina/common/*
>   F:	board/cortina/common/Kconfig
>   F:	board/cortina/common/mips/*
>   F:	drivers/gpio/cortina_gpio.c
> +F:	drivers/watchdog/cortina_wdt.c
>   
>   MIPS MSCC
>   M:	Gregory CLEMENT <gregory.clement at bootlin.com>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 8c16d69..2f7dedb 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -99,6 +99,14 @@ config WDT_CDNS
>   	   Select this to enable Cadence watchdog timer, which can be found on some
>   	   Xilinx Microzed Platform.
>   
> +config WDT_CORTINA
> +	bool "Cortina Access CAxxxx watchdog timer support"
> +	depends on WDT
> +	help
> +	  Cortina Access CAxxxx watchdog timer support.
> +	  This driver support all CPU ISAs supported by Cortina
> +          Access CAxxxx SoCs.
> +
>   config WDT_MPC8xx
>   	bool "MPC8xx watchdog timer support"
>   	depends on WDT && MPC8xx
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 955caef..87f92a4 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
>   obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
>   obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
>   obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
> +obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
>   obj-$(CONFIG_WDT_ORION) += orion_wdt.o
>   obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
>   obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
> diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c
> new file mode 100644
> index 0000000..61df802
> --- /dev/null
> +++ b/drivers/watchdog/cortina_wdt.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2020 Cortina-Access
> + * Author: Jason Li <jason.li at cortina-access.com>
> + *
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <asm/io.h>
> +#include <wdt.h>
> +
> +#define CA_WDT_CTRL		0x00
> +#define CA_WDT_PS		0x04
> +#define CA_WDT_DIV		0x08
> +#define CA_WDT_LD		0x0C
> +#define CA_WDT_LOADE		0x10
> +#define CA_WDT_CNT		0x14
> +#define CA_WDT_IE		0x18
> +#define CA_WDT_INT		0x1C
> +#define CA_WDT_STAT		0x20
> +
> +/* CA_WDT_CTRL */
> +#define CTL_WDT_EN		BIT(0)
> +#define CTL_WDT_RSTEN		BIT(1)
> +#define CTL_WDT_CLK_SEL		BIT(2)
> +/* CA_WDT_LOADE */
> +#define WDT_UPD			BIT(0)
> +#define WDT_UPD_PS		BIT(1)
> +
> +/* Global config */
> +#define WDT_RESET_SUB		BIT(4)
> +#define WDT_RESET_ALL_BLOCK	BIT(6)
> +#define WDT_RESET_REMAP		BIT(7)
> +#define WDT_EXT_RESET		BIT(8)
> +#define WDT_RESET_DEFAULT	(WDT_EXT_RESET | WDT_RESET_REMAP |
> +				 WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
> +
> +struct ca_wdt_priv {
> +	void __iomem *base;
> +	void __iomem *global_config;
> +};
> +
> +static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Prescale using millisecond unit */
> +	writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
> +
> +	/* Millisecond */
> +	writel(1, priv->base + CA_WDT_DIV);
> +
> +	writel(timeout_ms, priv->base + CA_WDT_LD);
> +	writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
> +}
> +
> +static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +	unsigned int reg_v;
> +
> +	cortina_wdt_set_timeout(dev, timeout);
> +
> +	/* WDT Reset option */
> +	reg_v = readl(priv->global_config);
> +	reg_v |= WDT_RESET_DEFAULT;
> +	writel(reg_v, priv->global_config);
> +
> +	/* Enable WDT */
> +	reg_v = readl(priv->base);
> +	reg_v |= (CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
> +	writel(reg_v, priv->base);
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_stop(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Disable WDT */
> +	writel(0, priv->base);
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_reset(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Reload WDT counter */
> +	writel(WDT_UPD, priv->base + CA_WDT_LOADE);
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_expire_now(struct udevice *dev, ulong flags)
> +{
> +	/* Set 1ms timeout to reset system */
> +	cortina_wdt_set_timeout(dev, 1);
> +	hang();
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_probe(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	priv->base = dev_remap_addr_index(dev, 0);
> +	if (!priv->base)
> +		return -ENOENT;
> +
> +	priv->global_config = dev_remap_addr_index(dev, 1);
> +	if (!priv->global_config)
> +		return -ENOENT;
> +
> +	/* Stop WDT */
> +	cortina_wdt_stop(dev);
> +
> +	return 0;
> +}
> +
> +static const struct wdt_ops cortina_wdt_ops = {
> +	.start = cortina_wdt_start,
> +	.reset = cortina_wdt_reset,
> +	.stop = cortina_wdt_stop,
> +	.expire_now = cortina_wdt_expire_now,
> +};
> +
> +static const struct udevice_id cortina_wdt_ids[] = {
> +	{.compatible = "cortina,cortina-wdt"},
> +	{}
> +};
> +
> +U_BOOT_DRIVER(cortina_wdt) = {
> +	.name = "cortina_wdt",
> +	.id = UCLASS_WDT,
> +	.probe = cortina_wdt_probe,
> +	.of_match = cortina_wdt_ids,
> +	.ops = &cortina_wdt_ops,
> +};

Looks good.

Reviewed-by: Stefan Roese <sr at denx.de>

Thanks,
Stefan
Daniel Schwierzeck Jan. 20, 2020, 3:13 p.m. UTC | #2
Am 20.01.20 um 10:53 schrieb Alex Nemirovsky:
> From: Jason Li <jason.li at cortina-access.com>
> 
> Add support for hardware watchdog timer on all Cortina Access
> CAxxxx family of SoCs.
> 
> Signed-off-by: Jason Li <jason.li at cortina-access.com>
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>
> ---
> 
>  MAINTAINERS                    |   2 +
>  drivers/watchdog/Kconfig       |   8 +++
>  drivers/watchdog/Makefile      |   1 +
>  drivers/watchdog/cortina_wdt.c | 144 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 155 insertions(+)
>  create mode 100644 drivers/watchdog/cortina_wdt.c
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b7b3359..f9334f9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -180,6 +180,7 @@ F:	board/cortina/common/*
>  F:	board/cortina/common/Kconfig
>  F:	board/cortina/common/armv8/lowlevel_init.S
>  F:	drivers/gpio/cortina_gpio.c
> +F:	drivers/watchdog/cortina_wdt.c
>  
>  ARM/CZ.NIC TURRIS MOX SUPPORT
>  M:	Marek Behun <marek.behun at nic.cz>
> @@ -662,6 +663,7 @@ F:	board/cortina/common/*
>  F:	board/cortina/common/Kconfig
>  F:	board/cortina/common/mips/*
>  F:	drivers/gpio/cortina_gpio.c
> +F:	drivers/watchdog/cortina_wdt.c
>  
>  MIPS MSCC
>  M:	Gregory CLEMENT <gregory.clement at bootlin.com>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 8c16d69..2f7dedb 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -99,6 +99,14 @@ config WDT_CDNS
>  	   Select this to enable Cadence watchdog timer, which can be found on some
>  	   Xilinx Microzed Platform.
>  
> +config WDT_CORTINA
> +	bool "Cortina Access CAxxxx watchdog timer support"
> +	depends on WDT
> +	help
> +	  Cortina Access CAxxxx watchdog timer support.
> +	  This driver support all CPU ISAs supported by Cortina
> +          Access CAxxxx SoCs.
> +
>  config WDT_MPC8xx
>  	bool "MPC8xx watchdog timer support"
>  	depends on WDT && MPC8xx
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 955caef..87f92a4 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
>  obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
>  obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
>  obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
> +obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
>  obj-$(CONFIG_WDT_ORION) += orion_wdt.o
>  obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
>  obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
> diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c
> new file mode 100644
> index 0000000..61df802
> --- /dev/null
> +++ b/drivers/watchdog/cortina_wdt.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2020 Cortina-Access
> + * Author: Jason Li <jason.li at cortina-access.com>
> + *
> + */

same comment as in patch 2/4

> +
> +#include <common.h>
> +#include <dm.h>
> +#include <asm/io.h>
> +#include <wdt.h>
> +
> +#define CA_WDT_CTRL		0x00
> +#define CA_WDT_PS		0x04
> +#define CA_WDT_DIV		0x08
> +#define CA_WDT_LD		0x0C
> +#define CA_WDT_LOADE		0x10
> +#define CA_WDT_CNT		0x14
> +#define CA_WDT_IE		0x18
> +#define CA_WDT_INT		0x1C
> +#define CA_WDT_STAT		0x20
> +
> +/* CA_WDT_CTRL */
> +#define CTL_WDT_EN		BIT(0)
> +#define CTL_WDT_RSTEN		BIT(1)
> +#define CTL_WDT_CLK_SEL		BIT(2)
> +/* CA_WDT_LOADE */
> +#define WDT_UPD			BIT(0)
> +#define WDT_UPD_PS		BIT(1)
> +
> +/* Global config */
> +#define WDT_RESET_SUB		BIT(4)
> +#define WDT_RESET_ALL_BLOCK	BIT(6)
> +#define WDT_RESET_REMAP		BIT(7)
> +#define WDT_EXT_RESET		BIT(8)
> +#define WDT_RESET_DEFAULT	(WDT_EXT_RESET | WDT_RESET_REMAP |
> +				 WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
> +
> +struct ca_wdt_priv {
> +	void __iomem *base;
> +	void __iomem *global_config;
> +};
> +
> +static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Prescale using millisecond unit */
> +	writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
> +
> +	/* Millisecond */
> +	writel(1, priv->base + CA_WDT_DIV);
> +
> +	writel(timeout_ms, priv->base + CA_WDT_LD);
> +	writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
> +}
> +
> +static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +	unsigned int reg_v;
> +
> +	cortina_wdt_set_timeout(dev, timeout);
> +
> +	/* WDT Reset option */
> +	reg_v = readl(priv->global_config);
> +	reg_v |= WDT_RESET_DEFAULT;
> +	writel(reg_v, priv->global_config);
> +
> +	/* Enable WDT */
> +	reg_v = readl(priv->base);
> +	reg_v |= (CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
> +	writel(reg_v, priv->base);

setbits_32() ?

> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_stop(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Disable WDT */
> +	writel(0, priv->base);
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_reset(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	/* Reload WDT counter */
> +	writel(WDT_UPD, priv->base + CA_WDT_LOADE);
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_expire_now(struct udevice *dev, ulong flags)
> +{
> +	/* Set 1ms timeout to reset system */
> +	cortina_wdt_set_timeout(dev, 1);
> +	hang();
> +
> +	return 0;
> +}
> +
> +static int cortina_wdt_probe(struct udevice *dev)
> +{
> +	struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +	priv->base = dev_remap_addr_index(dev, 0);
> +	if (!priv->base)
> +		return -ENOENT;
> +
> +	priv->global_config = dev_remap_addr_index(dev, 1);
> +	if (!priv->global_config)
> +		return -ENOENT;
> +
> +	/* Stop WDT */
> +	cortina_wdt_stop(dev);
> +
> +	return 0;
> +}
> +
> +static const struct wdt_ops cortina_wdt_ops = {
> +	.start = cortina_wdt_start,
> +	.reset = cortina_wdt_reset,
> +	.stop = cortina_wdt_stop,
> +	.expire_now = cortina_wdt_expire_now,
> +};
> +
> +static const struct udevice_id cortina_wdt_ids[] = {
> +	{.compatible = "cortina,cortina-wdt"},
> +	{}
> +};
> +
> +U_BOOT_DRIVER(cortina_wdt) = {
> +	.name = "cortina_wdt",
> +	.id = UCLASS_WDT,
> +	.probe = cortina_wdt_probe,
> +	.of_match = cortina_wdt_ids,
> +	.ops = &cortina_wdt_ops,
> +};
>
Simon Glass Jan. 30, 2020, 2:18 a.m. UTC | #3
On Mon, 20 Jan 2020 at 02:53, Alex Nemirovsky
<Alex.Nemirovsky at cortina-access.com> wrote:
>
> From: Jason Li <jason.li at cortina-access.com>
>
> Add support for hardware watchdog timer on all Cortina Access
> CAxxxx family of SoCs.
>
> Signed-off-by: Jason Li <jason.li at cortina-access.com>
> Signed-off-by: Alex Nemirovsky <alex.nemirovsky at cortina-access.com>
> ---
>
>  MAINTAINERS                    |   2 +
>  drivers/watchdog/Kconfig       |   8 +++
>  drivers/watchdog/Makefile      |   1 +
>  drivers/watchdog/cortina_wdt.c | 144 +++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 155 insertions(+)
>  create mode 100644 drivers/watchdog/cortina_wdt.c
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index b7b3359..f9334f9 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -180,6 +180,7 @@ F:  board/cortina/common/*
>  F:     board/cortina/common/Kconfig
>  F:     board/cortina/common/armv8/lowlevel_init.S
>  F:     drivers/gpio/cortina_gpio.c
> +F:     drivers/watchdog/cortina_wdt.c
>
>  ARM/CZ.NIC TURRIS MOX SUPPORT
>  M:     Marek Behun <marek.behun at nic.cz>
> @@ -662,6 +663,7 @@ F:  board/cortina/common/*
>  F:     board/cortina/common/Kconfig
>  F:     board/cortina/common/mips/*
>  F:     drivers/gpio/cortina_gpio.c
> +F:     drivers/watchdog/cortina_wdt.c
>
>  MIPS MSCC
>  M:     Gregory CLEMENT <gregory.clement at bootlin.com>
> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
> index 8c16d69..2f7dedb 100644
> --- a/drivers/watchdog/Kconfig
> +++ b/drivers/watchdog/Kconfig
> @@ -99,6 +99,14 @@ config WDT_CDNS
>            Select this to enable Cadence watchdog timer, which can be found on some
>            Xilinx Microzed Platform.
>
> +config WDT_CORTINA
> +       bool "Cortina Access CAxxxx watchdog timer support"
> +       depends on WDT
> +       help
> +         Cortina Access CAxxxx watchdog timer support.
> +         This driver support all CPU ISAs supported by Cortina
> +          Access CAxxxx SoCs.
> +
>  config WDT_MPC8xx
>         bool "MPC8xx watchdog timer support"
>         depends on WDT && MPC8xx
> diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
> index 955caef..87f92a4 100644
> --- a/drivers/watchdog/Makefile
> +++ b/drivers/watchdog/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
>  obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
>  obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
>  obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
> +obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
>  obj-$(CONFIG_WDT_ORION) += orion_wdt.o
>  obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
>  obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
> diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c
> new file mode 100644
> index 0000000..61df802
> --- /dev/null
> +++ b/drivers/watchdog/cortina_wdt.c
> @@ -0,0 +1,144 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +
> +/*
> + * Copyright (C) 2020 Cortina-Access
> + * Author: Jason Li <jason.li at cortina-access.com>
> + *
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <asm/io.h>
> +#include <wdt.h>
> +
> +#define CA_WDT_CTRL            0x00

Use stryct?

> +#define CA_WDT_PS              0x04
> +#define CA_WDT_DIV             0x08
> +#define CA_WDT_LD              0x0C
> +#define CA_WDT_LOADE           0x10
> +#define CA_WDT_CNT             0x14
> +#define CA_WDT_IE              0x18
> +#define CA_WDT_INT             0x1C
> +#define CA_WDT_STAT            0x20
> +
> +/* CA_WDT_CTRL */
> +#define CTL_WDT_EN             BIT(0)
> +#define CTL_WDT_RSTEN          BIT(1)
> +#define CTL_WDT_CLK_SEL                BIT(2)
> +/* CA_WDT_LOADE */
> +#define WDT_UPD                        BIT(0)
> +#define WDT_UPD_PS             BIT(1)
> +
> +/* Global config */
> +#define WDT_RESET_SUB          BIT(4)
> +#define WDT_RESET_ALL_BLOCK    BIT(6)
> +#define WDT_RESET_REMAP                BIT(7)
> +#define WDT_EXT_RESET          BIT(8)
> +#define WDT_RESET_DEFAULT      (WDT_EXT_RESET | WDT_RESET_REMAP |
> +                                WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
> +

struct comment

> +struct ca_wdt_priv {
> +       void __iomem *base;
> +       void __iomem *global_config;
> +};
> +
> +static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
> +{
> +       struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +       /* Prescale using millisecond unit */
> +       writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
> +
> +       /* Millisecond */
> +       writel(1, priv->base + CA_WDT_DIV);
> +
> +       writel(timeout_ms, priv->base + CA_WDT_LD);
> +       writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
> +}
> +
> +static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
> +{
> +       struct ca_wdt_priv *priv = dev_get_priv(dev);
> +       unsigned int reg_v;
> +
> +       cortina_wdt_set_timeout(dev, timeout);
> +
> +       /* WDT Reset option */
> +       reg_v = readl(priv->global_config);
> +       reg_v |= WDT_RESET_DEFAULT;
> +       writel(reg_v, priv->global_config);

setbits_le32(), and below

> +
> +       /* Enable WDT */
> +       reg_v = readl(priv->base);
> +       reg_v |= (CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
> +       writel(reg_v, priv->base);
> +
> +       return 0;
> +}
> +
> +static int cortina_wdt_stop(struct udevice *dev)
> +{
> +       struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +       /* Disable WDT */
> +       writel(0, priv->base);
> +
> +       return 0;
> +}
> +
> +static int cortina_wdt_reset(struct udevice *dev)
> +{
> +       struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +       /* Reload WDT counter */
> +       writel(WDT_UPD, priv->base + CA_WDT_LOADE);
> +
> +       return 0;
> +}
> +
> +static int cortina_wdt_expire_now(struct udevice *dev, ulong flags)
> +{
> +       /* Set 1ms timeout to reset system */
> +       cortina_wdt_set_timeout(dev, 1);
> +       hang();

This hang() should be moved to the calling function, wdt_expire_now()
and drivers adjusted accordingly. This is a bit like the sysreset
case. This function should return -EINPROGRESS.

> +
> +       return 0;
> +}
> +
> +static int cortina_wdt_probe(struct udevice *dev)
> +{
> +       struct ca_wdt_priv *priv = dev_get_priv(dev);
> +
> +       priv->base = dev_remap_addr_index(dev, 0);
> +       if (!priv->base)
> +               return -ENOENT;

-EINVAL

> +
> +       priv->global_config = dev_remap_addr_index(dev, 1);
> +       if (!priv->global_config)
> +               return -ENOENT;

Same

BTW both of these should be in an ofdata_to_platadata() method.

> +
> +       /* Stop WDT */
> +       cortina_wdt_stop(dev);

Only this should be in the prove() method.

> +
> +       return 0;
> +}
> +
> +static const struct wdt_ops cortina_wdt_ops = {
> +       .start = cortina_wdt_start,
> +       .reset = cortina_wdt_reset,
> +       .stop = cortina_wdt_stop,
> +       .expire_now = cortina_wdt_expire_now,
> +};
> +
> +static const struct udevice_id cortina_wdt_ids[] = {
> +       {.compatible = "cortina,cortina-wdt"},
> +       {}
> +};
> +
> +U_BOOT_DRIVER(cortina_wdt) = {
> +       .name = "cortina_wdt",
> +       .id = UCLASS_WDT,
> +       .probe = cortina_wdt_probe,
> +       .of_match = cortina_wdt_ids,
> +       .ops = &cortina_wdt_ops,
> +};
> --
> 2.7.4
>

Regards,
Simon
diff mbox series

Patch

diff --git a/MAINTAINERS b/MAINTAINERS
index b7b3359..f9334f9 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -180,6 +180,7 @@  F:	board/cortina/common/*
 F:	board/cortina/common/Kconfig
 F:	board/cortina/common/armv8/lowlevel_init.S
 F:	drivers/gpio/cortina_gpio.c
+F:	drivers/watchdog/cortina_wdt.c
 
 ARM/CZ.NIC TURRIS MOX SUPPORT
 M:	Marek Behun <marek.behun at nic.cz>
@@ -662,6 +663,7 @@  F:	board/cortina/common/*
 F:	board/cortina/common/Kconfig
 F:	board/cortina/common/mips/*
 F:	drivers/gpio/cortina_gpio.c
+F:	drivers/watchdog/cortina_wdt.c
 
 MIPS MSCC
 M:	Gregory CLEMENT <gregory.clement at bootlin.com>
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8c16d69..2f7dedb 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -99,6 +99,14 @@  config WDT_CDNS
 	   Select this to enable Cadence watchdog timer, which can be found on some
 	   Xilinx Microzed Platform.
 
+config WDT_CORTINA
+	bool "Cortina Access CAxxxx watchdog timer support"
+	depends on WDT
+	help
+	  Cortina Access CAxxxx watchdog timer support.
+	  This driver support all CPU ISAs supported by Cortina
+          Access CAxxxx SoCs.
+
 config WDT_MPC8xx
 	bool "MPC8xx watchdog timer support"
 	depends on WDT && MPC8xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 955caef..87f92a4 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -20,6 +20,7 @@  obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
 obj-$(CONFIG_WDT_ARMADA_37XX) += armada-37xx-wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
 obj-$(CONFIG_WDT_BCM6345) += bcm6345_wdt.o
+obj-$(CONFIG_WDT_CORTINA) += cortina_wdt.o
 obj-$(CONFIG_WDT_ORION) += orion_wdt.o
 obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
 obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
diff --git a/drivers/watchdog/cortina_wdt.c b/drivers/watchdog/cortina_wdt.c
new file mode 100644
index 0000000..61df802
--- /dev/null
+++ b/drivers/watchdog/cortina_wdt.c
@@ -0,0 +1,144 @@ 
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
+ * Copyright (C) 2020 Cortina-Access
+ * Author: Jason Li <jason.li at cortina-access.com>
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <asm/io.h>
+#include <wdt.h>
+
+#define CA_WDT_CTRL		0x00
+#define CA_WDT_PS		0x04
+#define CA_WDT_DIV		0x08
+#define CA_WDT_LD		0x0C
+#define CA_WDT_LOADE		0x10
+#define CA_WDT_CNT		0x14
+#define CA_WDT_IE		0x18
+#define CA_WDT_INT		0x1C
+#define CA_WDT_STAT		0x20
+
+/* CA_WDT_CTRL */
+#define CTL_WDT_EN		BIT(0)
+#define CTL_WDT_RSTEN		BIT(1)
+#define CTL_WDT_CLK_SEL		BIT(2)
+/* CA_WDT_LOADE */
+#define WDT_UPD			BIT(0)
+#define WDT_UPD_PS		BIT(1)
+
+/* Global config */
+#define WDT_RESET_SUB		BIT(4)
+#define WDT_RESET_ALL_BLOCK	BIT(6)
+#define WDT_RESET_REMAP		BIT(7)
+#define WDT_EXT_RESET		BIT(8)
+#define WDT_RESET_DEFAULT	(WDT_EXT_RESET | WDT_RESET_REMAP |
+				 WDT_RESET_ALL_BLOCK | WDT_RESET_SUB)
+
+struct ca_wdt_priv {
+	void __iomem *base;
+	void __iomem *global_config;
+};
+
+static void cortina_wdt_set_timeout(struct udevice *dev, u64 timeout_ms)
+{
+	struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Prescale using millisecond unit */
+	writel(CORTINA_PER_IO_FREQ / 1000, priv->base + CA_WDT_PS);
+
+	/* Millisecond */
+	writel(1, priv->base + CA_WDT_DIV);
+
+	writel(timeout_ms, priv->base + CA_WDT_LD);
+	writel(WDT_UPD | WDT_UPD_PS, priv->base + CA_WDT_LOADE);
+}
+
+static int cortina_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	struct ca_wdt_priv *priv = dev_get_priv(dev);
+	unsigned int reg_v;
+
+	cortina_wdt_set_timeout(dev, timeout);
+
+	/* WDT Reset option */
+	reg_v = readl(priv->global_config);
+	reg_v |= WDT_RESET_DEFAULT;
+	writel(reg_v, priv->global_config);
+
+	/* Enable WDT */
+	reg_v = readl(priv->base);
+	reg_v |= (CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
+	writel(reg_v, priv->base);
+
+	return 0;
+}
+
+static int cortina_wdt_stop(struct udevice *dev)
+{
+	struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Disable WDT */
+	writel(0, priv->base);
+
+	return 0;
+}
+
+static int cortina_wdt_reset(struct udevice *dev)
+{
+	struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+	/* Reload WDT counter */
+	writel(WDT_UPD, priv->base + CA_WDT_LOADE);
+
+	return 0;
+}
+
+static int cortina_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	/* Set 1ms timeout to reset system */
+	cortina_wdt_set_timeout(dev, 1);
+	hang();
+
+	return 0;
+}
+
+static int cortina_wdt_probe(struct udevice *dev)
+{
+	struct ca_wdt_priv *priv = dev_get_priv(dev);
+
+	priv->base = dev_remap_addr_index(dev, 0);
+	if (!priv->base)
+		return -ENOENT;
+
+	priv->global_config = dev_remap_addr_index(dev, 1);
+	if (!priv->global_config)
+		return -ENOENT;
+
+	/* Stop WDT */
+	cortina_wdt_stop(dev);
+
+	return 0;
+}
+
+static const struct wdt_ops cortina_wdt_ops = {
+	.start = cortina_wdt_start,
+	.reset = cortina_wdt_reset,
+	.stop = cortina_wdt_stop,
+	.expire_now = cortina_wdt_expire_now,
+};
+
+static const struct udevice_id cortina_wdt_ids[] = {
+	{.compatible = "cortina,cortina-wdt"},
+	{}
+};
+
+U_BOOT_DRIVER(cortina_wdt) = {
+	.name = "cortina_wdt",
+	.id = UCLASS_WDT,
+	.probe = cortina_wdt_probe,
+	.of_match = cortina_wdt_ids,
+	.ops = &cortina_wdt_ops,
+};