From patchwork Thu Jun 11 11:52:34 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Biwen Li \(OSS\)" X-Patchwork-Id: 242133 List-Id: U-Boot discussion From: biwen.li at oss.nxp.com (Biwen Li) Date: Thu, 11 Jun 2020 19:52:34 +0800 Subject: [v2 1/3] Watchdog: introduce ARM SBSA watchdog driver Message-ID: <20200611115236.3107-1-biwen.li@oss.nxp.com> From: Zhao Qiang 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 --- Change in v2: - fix copyright MAINTAINERS | 1 + drivers/watchdog/Kconfig | 6 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sbsa_gwdt.c | 131 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 139 insertions(+) create mode 100644 drivers/watchdog/sbsa_gwdt.c diff --git a/MAINTAINERS b/MAINTAINERS index 1fd975c..09554c0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -685,6 +685,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 bf06180..191891c 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -163,6 +163,12 @@ 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. + config WDT_SP805 bool "SP805 watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 519bbd3..0f0b2eb 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 0000000..ddac668 --- /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 + +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) +{ + u32 clk; + u32 load_value; + + struct sbsa_gwdt_priv *priv = dev_get_priv(dev); + /* + * 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, +};