From 2ea4d3f8a545c70697fe3ce25090d02bec38ec38 Mon Sep 17 00:00:00 2001 From: Chris Packham Date: Tue, 16 Dec 2025 17:14:38 +1300 Subject: watchdog: orion_wdt: Add support for armada-xp Update the orion_wdt.c to support armada-xp and similar SoCs. The WDT block used in armada-xp is fairly close to the armada-380 with just a few differences that can be handled based on the compatible property. Signed-off-by: Chris Packham Reviewed-by: Stefan Roese --- drivers/watchdog/orion_wdt.c | 99 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 93 insertions(+), 6 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index a2000b968c9..5e89303d284 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -40,8 +40,14 @@ struct orion_wdt_priv { #define TIMER_A370_STATUS 0x04 #define WDT_AXP_FIXED_ENABLE_BIT BIT(10) +#define TIMER1_FIXED_ENABLE_BIT BIT(12) #define WDT_A370_EXPIRED BIT(31) +struct orion_watchdog_data { + int (*plat_start)(struct udevice *dev, u64 timeout, ulong flags); + int (*plat_stop)(struct udevice *dev); +}; + static int orion_wdt_reset(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); @@ -53,7 +59,59 @@ static int orion_wdt_reset(struct udevice *dev) return 0; } -static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +static int armadaxp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + priv->timeout = DIV_ROUND_UP(timeout_ms, 1000); + + /* Fix the wdt and timer1 clock freqency to 25MHz */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= (WDT_AXP_FIXED_ENABLE_BIT | TIMER1_FIXED_ENABLE_BIT); + writel(reg, priv->reg + TIMER_CTRL); + + /* Set watchdog duration */ + writel(priv->clk_rate * priv->timeout, + priv->reg + priv->wdt_counter_offset); + + /* Clear the watchdog expiration bit */ + reg = readl(priv->reg + TIMER_A370_STATUS); + reg &= ~WDT_A370_EXPIRED; + writel(reg, priv->reg + TIMER_A370_STATUS); + + /* Enable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg |= WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + /* Enable reset on watchdog */ + reg = readl(priv->rstout); + reg |= RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + return 0; +} + +static int armadaxp_wdt_stop(struct udevice *dev) +{ + struct orion_wdt_priv *priv = dev_get_priv(dev); + u32 reg; + + /* Disable reset on watchdog */ + reg = readl(priv->rstout); + reg &= ~RSTOUT_ENABLE_BIT; + writel(reg, priv->rstout); + + /* Disable watchdog timer */ + reg = readl(priv->reg + TIMER_CTRL); + reg &= ~WDT_ENABLE_BIT; + writel(reg, priv->reg + TIMER_CTRL); + + return 0; +} + +static int armada380_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; @@ -91,7 +149,7 @@ static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) return 0; } -static int orion_wdt_stop(struct udevice *dev) +static int armada380_wdt_stop(struct udevice *dev) { struct orion_wdt_priv *priv = dev_get_priv(dev); u32 reg; @@ -113,6 +171,22 @@ static int orion_wdt_stop(struct udevice *dev) return 0; } +static int orion_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) +{ + struct orion_watchdog_data *data = + (struct orion_watchdog_data *)dev_get_driver_data(dev); + + return data->plat_start(dev, timeout_ms, flags); +} + +static int orion_wdt_stop(struct udevice *dev) +{ + struct orion_watchdog_data *data = + (struct orion_watchdog_data *)dev_get_driver_data(dev); + + return data->plat_stop(dev); +} + static inline bool save_reg_from_ofdata(struct udevice *dev, int index, void __iomem **reg, int *offset) { @@ -141,8 +215,10 @@ static int orion_wdt_of_to_plat(struct udevice *dev) if (!save_reg_from_ofdata(dev, 1, &priv->rstout, NULL)) goto err; - if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) - goto err; + if (device_is_compatible(dev, "marvell,armada-380-wdt")) { + if (!save_reg_from_ofdata(dev, 2, &priv->rstout_mask, NULL)) + goto err; + } return 0; err: @@ -173,9 +249,20 @@ static const struct wdt_ops orion_wdt_ops = { .stop = orion_wdt_stop, }; +static struct orion_watchdog_data armada380_data = { + .plat_start = armada380_wdt_start, + .plat_stop = armada380_wdt_stop, +}; + +static struct orion_watchdog_data armadaxp_data = { + .plat_start = armadaxp_wdt_start, + .plat_stop = armadaxp_wdt_stop, +}; + static const struct udevice_id orion_wdt_ids[] = { - { .compatible = "marvell,armada-380-wdt" }, - {} + { .compatible = "marvell,armada-380-wdt", .data = (ulong)&armada380_data}, + { .compatible = "marvell,armada-xp-wdt", .data = (ulong)&armadaxp_data}, + { } }; U_BOOT_DRIVER(orion_wdt) = { -- cgit v1.3.1 From d98e11bcbcbde2d7448a30cec45d80a9215d3f98 Mon Sep 17 00:00:00 2001 From: Tom Rini Date: Mon, 16 Mar 2026 19:24:48 -0600 Subject: watchdog: Correct dependencies for WDT_MAX6370 As exposed by "make randconfig", we have an issue with the dependencies for WDT_MAX6370. It needs to select both GPIO and DM_GPIO not just DM_GPIO. Signed-off-by: Tom Rini --- drivers/watchdog/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'drivers') diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9ea617f1e43..0e6e6830fc8 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -217,6 +217,7 @@ config SPL_WDT_GPIO config WDT_MAX6370 bool "MAX6370 watchdog timer support" depends on WDT + select GPIO select DM_GPIO help Select this to enable max6370 watchdog timer. -- cgit v1.3.1 From d62801d09441acfebe2c8b7da66de70e6e5ad492 Mon Sep 17 00:00:00 2001 From: Jonas Karlman Date: Sun, 22 Mar 2026 21:39:55 +0000 Subject: watchdog: designware: Fix probe when clk_enable return ENOSYS Rockchip SoCs typically reset with all (or most) clocks ungated. Because of this, U-Boot clock drivers for Rockchip typically do not implement the optional clk-uclass enable/disable ops. Normal driver model behavior is to return -ENOSYS when an uclass ops is not implemented. Ignore -ENOSYS to allow the designware watchdog driver to be probed on platforms that do not implement the clk-uclass enable/disable ops, e.g. Rockchip RK3308. Signed-off-by: Jonas Karlman --- drivers/watchdog/designware_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/designware_wdt.c b/drivers/watchdog/designware_wdt.c index bd9d7105366..91228de5e8e 100644 --- a/drivers/watchdog/designware_wdt.c +++ b/drivers/watchdog/designware_wdt.c @@ -122,7 +122,7 @@ static int designware_wdt_probe(struct udevice *dev) return ret; ret = clk_enable(&clk); - if (ret) + if (ret && ret != -ENOSYS) return ret; priv->clk_khz = clk_get_rate(&clk) / 1000; -- cgit v1.3.1 From 1a489a1a4375237ce1cabf7f95e2c57506350e7f Mon Sep 17 00:00:00 2001 From: Juuso Rinta Date: Mon, 4 May 2026 12:34:34 +0300 Subject: watchdog: sbsa_gwdt: clamp WOR value to hw max The WOR register is 32 bits, so any tick count exceeding U32_MAX is truncated by writel(). A large requested timeout can wrap to a small value causing the watchdog to fire sooner than requested. Clamp the calculated value to U32_MAX prior to writing the register so over-large requests will be set to the maximum timeout value. Found by code review. Signed-off-by: Juuso Rinta Reviewed-by: Stefan Roese --- drivers/watchdog/sbsa_gwdt.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c index 807884c5bc7..3a924cb2b9a 100644 --- a/drivers/watchdog/sbsa_gwdt.c +++ b/drivers/watchdog/sbsa_gwdt.c @@ -50,6 +50,7 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) { struct sbsa_gwdt_priv *priv = dev_get_priv(dev); u32 clk; + u64 tout_wdog; /* * it work in the single stage mode in u-boot, @@ -58,8 +59,13 @@ static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) * to half value of timeout. */ clk = get_tbclk(); - writel(clk / (2 * 1000) * timeout, - priv->reg_control + SBSA_GWDT_WOR); + + /* if requested timeout overflows, clamp it to u32_max */ + tout_wdog = ((u64)clk * timeout) / (2 * 1000); + if (tout_wdog > U32_MAX) + tout_wdog = U32_MAX; + + writel(tout_wdog, priv->reg_control + SBSA_GWDT_WOR); /* writing WCS will cause an explicit watchdog refresh */ writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS); -- cgit v1.3.1 From 9124bf185ba6206dd2286a78addd74a5449bd9c3 Mon Sep 17 00:00:00 2001 From: Juuso Rinta Date: Mon, 4 May 2026 12:36:58 +0300 Subject: watchdog: octeontx_wdt: fix DT matches to Marvell compatibles The OcteonTX watchdog driver currently matches arm,sbsa-gwdt. On systems with multiple watchdog devices this can be ambiguous since arm,sbsa-gwdt is a generic SBSA binding. Replace the SBSA match with SoC-specific Marvell compatibles marvell,cn10624-wdt and marvell,cn9670-wdt. These compatibles align with the upstream Linux device tree binding: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/watchdog/marvell,cn10624-wdt.yaml Reviewed-by: Aaro Koskinen Signed-off-by: Juuso Rinta Reviewed-by: Stefan Roese --- drivers/watchdog/octeontx_wdt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/octeontx_wdt.c b/drivers/watchdog/octeontx_wdt.c index c79d9539c13..7299a9f9739 100644 --- a/drivers/watchdog/octeontx_wdt.c +++ b/drivers/watchdog/octeontx_wdt.c @@ -159,7 +159,8 @@ static const struct octeontx_wdt_data octeon_data = { }; static const struct udevice_id octeontx_wdt_ids[] = { - { .compatible = "arm,sbsa-gwdt", .data = (ulong)&octeontx_data }, + { .compatible = "marvell,cn10624-wdt", .data = (ulong)&octeontx_data }, + { .compatible = "marvell,cn9670-wdt", .data = (ulong)&octeontx_data }, { .compatible = "cavium,octeon-7890-ciu3", .data = (ulong)&octeon_data }, {} }; -- cgit v1.3.1 From 3c3ba75c852e68d5f9a9b388935254a2b3e13bd3 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 25 May 2026 11:51:47 +0800 Subject: watchdog: orion_wdt: use dev_read_addr_size_index() Replace devfdt_read_addr_size_index() with dev_read_addr_size_index() when retrieving the register base address. dev_read_addr_size_index() supports both live device tree and flat DT backends, avoiding direct dependency on devfdt_* helpers. No functional changes. Signed-off-by: Peng Fan Reviewed-by: Stefan Roese --- drivers/watchdog/orion_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c index 5e89303d284..5a6cad135aa 100644 --- a/drivers/watchdog/orion_wdt.c +++ b/drivers/watchdog/orion_wdt.c @@ -193,7 +193,7 @@ static inline bool save_reg_from_ofdata(struct udevice *dev, int index, fdt_addr_t addr; fdt_size_t off; - addr = devfdt_get_addr_size_index(dev, index, &off); + addr = dev_read_addr_size_index(dev, index, &off); if (addr == FDT_ADDR_T_NONE) return false; -- cgit v1.3.1 From b9b27c875f664a42967941bc33dbbaa441f12250 Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 25 May 2026 11:51:48 +0800 Subject: watchdog: rti: Use dev_read_addr_ptr() devfdt_get_addr() returns FDT_ADDR_T_NONE(-1UL) when fail, using "!priv->regs" to check return value is wrong. Replace devfdt_read_addr() with dev_read_addr_ptr() when retrieving the register base address. dev_read_addr_ptr() supports both live device tree and flat DT backends, avoiding direct dependency on devfdt_* helpers. Also use "void __iomem *" to replace "phys_addr_t" to avoid type casting. No functional changes. Signed-off-by: Peng Fan Reviewed-by: Stefan Roese --- drivers/watchdog/rti_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index 7b387266b99..866f555789c 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -39,7 +39,7 @@ #define WDT_PRELOAD_MAX 0xfff struct rti_wdt_priv { - phys_addr_t regs; + void __iomem *regs; unsigned int clk_hz; }; @@ -177,7 +177,7 @@ static int rti_wdt_probe(struct udevice *dev) struct clk clk; int ret; - priv->regs = devfdt_get_addr(dev); + priv->regs = dev_read_addr_ptr(dev); if (!priv->regs) return -EINVAL; -- cgit v1.3.1 From 5843db9dada474aec1d29a149a681657677ed89a Mon Sep 17 00:00:00 2001 From: Peng Fan Date: Mon, 25 May 2026 11:51:49 +0800 Subject: watchdog: mpc8xxx_wdt: Use dev_remap_addr() Use dev_remap_addr() to replace devfdt_remap_addr which supports both live device tree and flat DT backends, avoiding direct dependency on devfdt_* helpers. No functional changes. Signed-off-by: Peng Fan Reviewed-by: Stefan Roese --- drivers/watchdog/mpc8xxx_wdt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers') diff --git a/drivers/watchdog/mpc8xxx_wdt.c b/drivers/watchdog/mpc8xxx_wdt.c index 7fcb866f574..068f99c5fc6 100644 --- a/drivers/watchdog/mpc8xxx_wdt.c +++ b/drivers/watchdog/mpc8xxx_wdt.c @@ -81,7 +81,7 @@ static int mpc8xxx_wdt_of_to_plat(struct udevice *dev) { struct mpc8xxx_wdt_priv *priv = dev_get_priv(dev); - priv->base = (void __iomem *)devfdt_remap_addr(dev); + priv->base = (void __iomem *)dev_remap_addr(dev); if (!priv->base) return -EINVAL; -- cgit v1.3.1 From 17f7334c952b7db35457a9e54ba273d5364e6503 Mon Sep 17 00:00:00 2001 From: Francois Berder Date: Mon, 25 May 2026 22:33:14 +0200 Subject: drivers: watchdog: Fix dev_read_addr error check dev_read_addr does not return a void* but fdt_addr_t. Replace invalid usage of dev_read_addr by dev_read_addr_ptr. v2: - Replace dev_read_addr by dev_read_addr_ptr - Change error to EINVAL Signed-off-by: Francois Berder Reviewed-by: Stefan Roese Reviewed-by: Hal Feng --- drivers/watchdog/starfive_wdt.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers') diff --git a/drivers/watchdog/starfive_wdt.c b/drivers/watchdog/starfive_wdt.c index ee9ec4cdc3a..d2c16150f4c 100644 --- a/drivers/watchdog/starfive_wdt.c +++ b/drivers/watchdog/starfive_wdt.c @@ -290,9 +290,9 @@ static int starfive_wdt_of_to_plat(struct udevice *dev) { struct starfive_wdt_priv *wdt = dev_get_priv(dev); - wdt->base = (void *)dev_read_addr(dev); + wdt->base = dev_read_addr_ptr(dev); if (!wdt->base) - return -ENODEV; + return -EINVAL; wdt->apb_clk = devm_clk_get(dev, "apb"); if (IS_ERR(wdt->apb_clk)) -- cgit v1.3.1