Browse Source

watchdog: cortina_wdt: add support for HW WDT on CAxxxx SoCs

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

Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Reviewed-by: Stefan Roese <sr@denx.de>
Signed-off-by: Jason Li <jason.li@cortina-access.com>
Signed-off-by: Alex Nemirovsky <alex.nemirovsky@cortina-access.com>
Jason Li 4 years ago
parent
commit
7f54b83870
3 changed files with 148 additions and 0 deletions
  1. 8 0
      drivers/watchdog/Kconfig
  2. 1 0
      drivers/watchdog/Makefile
  3. 139 0
      drivers/watchdog/cortina_wdt.c

+ 8 - 0
drivers/watchdog/Kconfig

@@ -107,6 +107,14 @@ config WDT_CDNS
 	   Select this to enable Cadence watchdog timer, which can be found on some
 	   Select this to enable Cadence watchdog timer, which can be found on some
 	   Xilinx Microzed Platform.
 	   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
 config WDT_MPC8xx
 	bool "MPC8xx watchdog timer support"
 	bool "MPC8xx watchdog timer support"
 	depends on WDT && MPC8xx
 	depends on WDT && MPC8xx

+ 1 - 0
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_ARMADA_37XX) += armada-37xx-wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
 obj-$(CONFIG_WDT_ASPEED) += ast_wdt.o
 obj-$(CONFIG_WDT_BCM6345) += bcm6345_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_ORION) += orion_wdt.o
 obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
 obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
 obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o
 obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o

+ 139 - 0
drivers/watchdog/cortina_wdt.c

@@ -0,0 +1,139 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2020 Cortina-Access
+ *
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <hang.h>
+#include <asm/io.h>
+#include <wdt.h>
+#include <linux/bitops.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);
+
+	cortina_wdt_set_timeout(dev, timeout);
+
+	/* WDT Reset option */
+	setbits_32(priv->global_config, WDT_RESET_DEFAULT);
+
+	/* Enable WDT */
+	setbits_32(priv->base, CTL_WDT_EN | CTL_WDT_RSTEN | CTL_WDT_CLK_SEL);
+
+	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,ca-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,
+};