[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