[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