[PATCH 4/9] watchdog: Add HPE GSC watchdog driver

Jorge Cisneros jorge.cisneros at hpe.com
Wed Apr 8 21:24:16 CEST 2026


Add watchdog driver for the HPE GSC SoC. The GSC watchdog uses two
separate register regions: a counter register and a control register.
Writing the counter value resets the watchdog timer, while writing to
the control register enables or disables the watchdog.

Supported operations: start, stop, reset, and expire_now.

Signed-off-by: Jorge Cisneros <jorge.cisneros at hpe.com>
---
 drivers/watchdog/Kconfig   |   7 +++
 drivers/watchdog/Makefile  |   1 +
 drivers/watchdog/gsc_wdt.c | 110 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 118 insertions(+)

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 35ae7d106b1..692a7eb4304 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -195,6 +195,13 @@ config WDT_DAVINCI
 	  Select this to enable the watchdog timer for DaVinci SoCs such as the
 	  OMAP-L138.
 
+config WDT_GSC
+	bool "HPE GSC watchdog support"
+	depends on WDT
+	help
+	  Enable support for the watchdog timer in HPE GSC BMC SoC
+	  used in HPE Gen12 servers.
+
 config WDT_GPIO
 	bool "External gpio watchdog support"
 	depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 02e2674f8af..f7397e03527 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o
 obj-$(CONFIG_WDT_DA9063) += da9063-wdt.o
 obj-$(CONFIG_WDT_DAVINCI) += davinci_wdt.o
 obj-$(CONFIG_WDT_FTWDT010) += ftwdt010_wdt.o
+obj-$(CONFIG_WDT_GSC) += gsc_wdt.o
 obj-$(CONFIG_$(SPL_TPL_)WDT_GPIO) += gpio_wdt.o
 obj-$(CONFIG_WDT_MAX6370) += max6370_wdt.o
 obj-$(CONFIG_WDT_MCF) += mcf_wdt.o
diff --git a/drivers/watchdog/gsc_wdt.c b/drivers/watchdog/gsc_wdt.c
new file mode 100644
index 00000000000..b535f47e052
--- /dev/null
+++ b/drivers/watchdog/gsc_wdt.c
@@ -0,0 +1,110 @@
+// SPDX-License-Identifier: GPL-2.0+
+/* Copyright (C) 2022-2025 Hewlett Packard Enterprise Development LP */
+
+#include <dm.h>
+#include <errno.h>
+#include <log.h>
+#include <wdt.h>
+#include <asm/io.h>
+#include <linux/err.h>
+
+#define MASK_WDGCS_ENABLE	BIT(0)
+#define MASK_WDGCS_RELOAD	BIT(2)
+#define MASK_WDGCS_NMIEN	BIT(3)
+#define MASK_WDGCS_WARN		BIT(7)
+
+#define WDT_MAX_TIMEOUT_MS	655350
+#define SECS_TO_WDOG_TICKS(x)	((x) * 100)
+
+struct gsc_wdt_priv {
+	void __iomem *counter;
+	void __iomem *control;
+};
+
+static int gsc_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
+{
+	struct gsc_wdt_priv *priv = dev_get_priv(dev);
+	u8 val;
+	u16 timeout_secs;
+
+	if (timeout_ms > WDT_MAX_TIMEOUT_MS)
+		timeout_ms = WDT_MAX_TIMEOUT_MS;
+	else if (timeout_ms == 0)
+		timeout_ms = CONFIG_WATCHDOG_TIMEOUT_MSECS;
+
+	timeout_secs = timeout_ms / 1000;
+	writew(SECS_TO_WDOG_TICKS(timeout_secs), priv->counter);
+
+	val = readb(priv->control);
+	val |= MASK_WDGCS_ENABLE;
+	writeb(val, priv->control);
+
+	return 0;
+}
+
+static int gsc_wdt_stop(struct udevice *dev)
+{
+	struct gsc_wdt_priv *priv = dev_get_priv(dev);
+	u8 val;
+
+	val = readb(priv->control);
+	val &= ~MASK_WDGCS_ENABLE;
+	writeb(val, priv->control);
+
+	return 0;
+}
+
+static int gsc_wdt_reset(struct udevice *dev)
+{
+	struct gsc_wdt_priv *priv = dev_get_priv(dev);
+	u8 val;
+
+	val = readb(priv->control);
+	val |= MASK_WDGCS_RELOAD;
+	writeb(val, priv->control);
+
+	return 0;
+}
+
+static int gsc_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	return gsc_wdt_start(dev, 1, flags);
+}
+
+static const struct wdt_ops gsc_wdt_ops = {
+	.start = gsc_wdt_start,
+	.reset = gsc_wdt_reset,
+	.stop = gsc_wdt_stop,
+	.expire_now = gsc_wdt_expire_now,
+};
+
+static const struct udevice_id gsc_wdt_ids[] = {
+	{ .compatible = "hpe,gsc-wdt" },
+	{ }
+};
+
+static int gsc_wdt_probe(struct udevice *dev)
+{
+	struct gsc_wdt_priv *priv = dev_get_priv(dev);
+
+	priv->counter = dev_remap_addr_index(dev, 0);
+	if (!priv->counter)
+		return -EINVAL;
+
+	priv->control = dev_remap_addr_index(dev, 1);
+	if (!priv->control)
+		return -EINVAL;
+
+	gsc_wdt_stop(dev);
+
+	return 0;
+}
+
+U_BOOT_DRIVER(gsc_wdt) = {
+	.name = "gsc_wdt",
+	.id = UCLASS_WDT,
+	.of_match = gsc_wdt_ids,
+	.probe = gsc_wdt_probe,
+	.priv_auto = sizeof(struct gsc_wdt_priv),
+	.ops = &gsc_wdt_ops,
+};

-- 
2.43.0



More information about the U-Boot mailing list