From mboxrd@z Thu Jan 1 00:00:00 1970 From: Lubomir Rintel Date: Tue, 17 Nov 2020 22:00:13 +0100 Subject: [PATCH RFC 15/20] watchdog: Add Ingenic JZ4730 watchdog timer driver In-Reply-To: <20201117210018.751469-1-lkundrak@v3.sk> References: <20201117210018.751469-1-lkundrak@v3.sk> Message-ID: <20201117210018.751469-16-lkundrak@v3.sk> List-Id: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit To: u-boot@lists.denx.de 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 --- 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 + */ + +#include +#include +#include +#include +#include +#include +#include + +#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