From: Jason Li <[email protected]>

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

Signed-off-by: Jason Li <[email protected]>
Signed-off-by: Alex Nemirovsky <[email protected]>
---

 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 <[email protected]>
@@ -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 <[email protected]>
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 <[email protected]>
+ *
+ */
+
+#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,
+};
-- 
2.7.4

Reply via email to