[PATCH RFC 15/20] watchdog: Add Ingenic JZ4730 watchdog timer driver

Lubomir Rintel lkundrak at v3.sk
Tue Nov 17 22:00:13 CET 2020


This adds support for the watchdog timer on JZ4730 SoC.

Once started, the hardware can't be told to stop counting. It is
especially inconvenient given the stock kernel on Skytone Alpha 400
(a JZ4730-based laptop) won't poke the watchdog.

We nevertheless want to keep the driver around in order to be able to
reset the processor. For now, the driver uses a timeout of 0 to mean it
shouldn't set a timout, which should be good enough for the Alpha 400
boards. There's probaby a nicer solution.

Signed-off-by: Lubomir Rintel <lkundrak at v3.sk>
---
 drivers/watchdog/Kconfig      |  8 ++++
 drivers/watchdog/Makefile     |  1 +
 drivers/watchdog/jz4730_wdt.c | 86 +++++++++++++++++++++++++++++++++++
 3 files changed, 95 insertions(+)
 create mode 100644 drivers/watchdog/jz4730_wdt.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 4532a40e458..ff81344b337 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -118,6 +118,14 @@ config WDT_CORTINA
 	  This driver support all CPU ISAs supported by Cortina
 	  Access CAxxxx SoCs.
 
+config WDT_JZ4730
+	bool "Ingenic JZ4730 watchdog timer support"
+	depends on WDT && SOC_JZ4730
+	default y
+	help
+	  Select this to enable watchdog timer, which can be found on
+	  Ingenic JZ4730 chips.
+
 config WDT_MPC8xx
 	bool "MPC8xx watchdog timer support"
 	depends on WDT && MPC8xx
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 01b8231f2bf..ca46befe29d 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -23,6 +23,7 @@ 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_JZ4730) += jz4730_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/jz4730_wdt.c b/drivers/watchdog/jz4730_wdt.c
new file mode 100644
index 00000000000..6a63f3cbb6f
--- /dev/null
+++ b/drivers/watchdog/jz4730_wdt.c
@@ -0,0 +1,86 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * JZ4730 Watchdog Timer driver.
+ *
+ * Copyright (c) 2020 Lubomir Rintel <lkundrak at v3.sk>
+ */
+
+#include <common.h>
+#include <clk.h>
+#include <dm.h>
+#include <wdt.h>
+#include <div64.h>
+#include <linux/bitops.h>
+#include <asm/io.h>
+
+#define WDT_WTCSR	0x00
+#define WDT_WTCNT	0x04
+
+#define WDT_WTCSR_START BIT(4)
+
+struct jz4730_wdt_priv {
+	void __iomem *base;
+	unsigned long clk_rate;
+	u32 timeout;
+};
+
+static int jz4730_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+	struct jz4730_wdt_priv *priv = dev_get_priv(dev);
+	u64 timeout = timeout_ms * priv->clk_rate;
+
+	do_div(timeout, 1000);
+	priv->timeout = U32_MAX - max_t(u32, timeout, 32);
+	wdt_reset(dev);
+	if (timeout)
+		writeb(WDT_WTCSR_START, priv->base + WDT_WTCSR);
+
+	return 0;
+}
+
+static int jz4730_wdt_reset(struct udevice *dev)
+{
+	struct jz4730_wdt_priv *priv = dev_get_priv(dev);
+
+	writel(priv->timeout, priv->base + WDT_WTCNT);
+
+	return 0;
+}
+
+static const struct wdt_ops jz4730_wdt_ops = {
+	.start = jz4730_wdt_start,
+	.reset = jz4730_wdt_reset,
+};
+
+static int jz4730_wdt_probe(struct udevice *dev)
+{
+	struct jz4730_wdt_priv *priv = dev_get_priv(dev);
+	struct clk clk;
+	int ret;
+
+	priv->base = dev_remap_addr(dev);
+	if (!priv->base)
+		return -EINVAL;
+
+	ret = clk_get_by_index(dev, 0, &clk);
+	if (ret)
+		return ret;
+
+	priv->clk_rate = clk_get_rate(&clk);
+
+	return 0;
+}
+
+static const struct udevice_id jz4730_wdt_ids[] = {
+	{ .compatible = "ingenic,jz4730-watchdog" },
+	{ }
+};
+
+U_BOOT_DRIVER(wdt_jz4730) = {
+	.name = "wdt_jz4730",
+	.id = UCLASS_WDT,
+	.of_match = jz4730_wdt_ids,
+	.ops = &jz4730_wdt_ops,
+	.priv_auto_alloc_size = sizeof(struct jz4730_wdt_priv),
+	.probe = jz4730_wdt_probe,
+};
-- 
2.28.0



More information about the U-Boot mailing list