From f27d73e941525cab15682f2aea1673f5f943a128 Mon Sep 17 00:00:00 2001 From: Zhao Qiang Date: Fri, 10 Jul 2020 16:55:18 +0800 Subject: [PATCH] Watchdog: introduce ARM SBSA watchdog driver According to Server Base System Architecture (SBSA) specification, the SBSA Generic Watchdog has two stage timeouts: the first signal (WS0) is for alerting the system by interrupt, the second one (WS1) is a real hardware reset. More details about the hardware specification of this device: ARM DEN0029B - Server Base System Architecture (SBSA) This driver can operate ARM SBSA Generic Watchdog as a single stage In the single stage mode, when the timeout is reached, your system will be reset by WS1. The first signal (WS0) is ignored. Signed-off-by: Zhao Qiang Signed-off-by: Biwen Li Reviewed-by: Stefan Roese Reviewed-by: Priyanka Jain --- MAINTAINERS | 1 + drivers/watchdog/Kconfig | 9 +++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sbsa_gwdt.c | 131 +++++++++++++++++++++++++++++++++++ 4 files changed, 142 insertions(+) create mode 100644 drivers/watchdog/sbsa_gwdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 6316c6ca00..4c84c4da54 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -689,6 +689,7 @@ M: Priyanka Jain S: Maintained T: git https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq.git F: drivers/watchdog/sp805_wdt.c +F: drivers/watchdog/sbsa_gwdt.c I2C M: Heiko Schocher diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index bf06180cdd..6d5c4fcfeb 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -163,6 +163,15 @@ config WDT_SANDBOX can be probed and supports all of the methods of WDT, but does not really do anything. +config WDT_SBSA + bool "SBSA watchdog timer support" + depends on WDT + help + Select this to enable SBSA watchdog timer. + This driver can operate ARM SBSA Generic Watchdog as a single stage. + In the single stage mode, when the timeout is reached, your system + will be reset by WS1. The first signal (WS0) is ignored. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 519bbd3a40..0f0b2eb5bc 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -27,6 +27,7 @@ obj-$(CONFIG_WDT_MPC8xx) += mpc8xx_wdt.o obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o obj-$(CONFIG_WDT_MTK) += mtk_wdt.o obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o +obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o diff --git a/drivers/watchdog/sbsa_gwdt.c b/drivers/watchdog/sbsa_gwdt.c new file mode 100644 index 0000000000..2eae431ba6 --- /dev/null +++ b/drivers/watchdog/sbsa_gwdt.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for SBSA + * + * Copyright 2020 NXP + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +DECLARE_GLOBAL_DATA_PTR; + +/* SBSA Generic Watchdog register definitions */ +/* refresh frame */ +#define SBSA_GWDT_WRR 0x000 + +/* control frame */ +#define SBSA_GWDT_WCS 0x000 +#define SBSA_GWDT_WOR 0x008 +#define SBSA_GWDT_WCV 0x010 + +/* refresh/control frame */ +#define SBSA_GWDT_W_IIDR 0xfcc +#define SBSA_GWDT_IDR 0xfd0 + +/* Watchdog Control and Status Register */ +#define SBSA_GWDT_WCS_EN BIT(0) +#define SBSA_GWDT_WCS_WS0 BIT(1) +#define SBSA_GWDT_WCS_WS1 BIT(2) + +struct sbsa_gwdt_priv { + void __iomem *reg_refresh; + void __iomem *reg_control; +}; + +static int sbsa_gwdt_reset(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_refresh + SBSA_GWDT_WRR); + + return 0; +} + +static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + u32 clk; + + /* + * it work in the single stage mode in u-boot, + * The first signal (WS0) is ignored, + * the timeout is (WOR * 2), so the WOR should be configured + * to half value of timeout. + */ + clk = get_tbclk(); + writel(clk / 2 * timeout, + 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); + + return 0; +} + +static int sbsa_gwdt_stop(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + writel(0, priv->reg_control + SBSA_GWDT_WCS); + + return 0; +} + +static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags) +{ + sbsa_gwdt_start(dev, 0, flags); + + return 0; +} + +static int sbsa_gwdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev->seq); + + return 0; +} + +static int sbsa_gwdt_ofdata_to_platdata(struct udevice *dev) +{ + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + + priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0); + if (IS_ERR(priv->reg_control)) + return PTR_ERR(priv->reg_control); + + priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1); + if (IS_ERR(priv->reg_refresh)) + return PTR_ERR(priv->reg_refresh); + + return 0; +} + +static const struct wdt_ops sbsa_gwdt_ops = { + .start = sbsa_gwdt_start, + .reset = sbsa_gwdt_reset, + .stop = sbsa_gwdt_stop, + .expire_now = sbsa_gwdt_expire_now, +}; + +static const struct udevice_id sbsa_gwdt_ids[] = { + { .compatible = "arm,sbsa-gwdt" }, + {} +}; + +U_BOOT_DRIVER(sbsa_gwdt) = { + .name = "sbsa_gwdt", + .id = UCLASS_WDT, + .of_match = sbsa_gwdt_ids, + .probe = sbsa_gwdt_probe, + .priv_auto_alloc_size = sizeof(struct sbsa_gwdt_priv), + .ofdata_to_platdata = sbsa_gwdt_ofdata_to_platdata, + .ops = &sbsa_gwdt_ops, +}; -- 2.39.5