Commit df12804da9664932179d3322c085b1d10fadce33

Authored by Zhao Qiang
Committed by Priyanka Jain
1 parent a2c60b6733

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 <qiang.zhao@nxp.com>
Signed-off-by: Biwen Li <biwen.li@nxp.com>
Reviewed-by: Stefan Roese <sr@denx.de>

Showing 4 changed files with 142 additions and 0 deletions Side-by-side Diff

... ... @@ -642,6 +642,7 @@
642 642 S: Maintained
643 643 T: git https://gitlab.denx.de/u-boot/custodians/u-boot-fsl-qoriq.git
644 644 F: drivers/watchdog/sp805_wdt.c
  645 +F: drivers/watchdog/sbsa_gwdt.c
645 646  
646 647 I2C
647 648 M: Heiko Schocher <hs@denx.de>
drivers/watchdog/Kconfig
... ... @@ -162,6 +162,15 @@
162 162 can be probed and supports all of the methods of WDT, but does not
163 163 really do anything.
164 164  
  165 +config WDT_SBSA
  166 + bool "SBSA watchdog timer support"
  167 + depends on WDT
  168 + help
  169 + Select this to enable SBSA watchdog timer.
  170 + This driver can operate ARM SBSA Generic Watchdog as a single stage.
  171 + In the single stage mode, when the timeout is reached, your system
  172 + will be reset by WS1. The first signal (WS0) is ignored.
  173 +
165 174 config WDT_SP805
166 175 bool "SP805 watchdog timer support"
167 176 depends on WDT
drivers/watchdog/Makefile
... ... @@ -27,6 +27,7 @@
27 27 obj-$(CONFIG_WDT_MT7621) += mt7621_wdt.o
28 28 obj-$(CONFIG_WDT_MTK) += mtk_wdt.o
29 29 obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
  30 +obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
30 31 obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
31 32 obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
32 33 obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o
drivers/watchdog/sbsa_gwdt.c
  1 +// SPDX-License-Identifier: GPL-2.0+
  2 +/*
  3 + * Watchdog driver for SBSA
  4 + *
  5 + * Copyright 2020 NXP
  6 + */
  7 +
  8 +#include <asm/io.h>
  9 +#include <common.h>
  10 +#include <dm/device.h>
  11 +#include <dm/fdtaddr.h>
  12 +#include <dm/read.h>
  13 +#include <linux/bitops.h>
  14 +#include <linux/err.h>
  15 +#include <watchdog.h>
  16 +#include <wdt.h>
  17 +
  18 +DECLARE_GLOBAL_DATA_PTR;
  19 +
  20 +/* SBSA Generic Watchdog register definitions */
  21 +/* refresh frame */
  22 +#define SBSA_GWDT_WRR 0x000
  23 +
  24 +/* control frame */
  25 +#define SBSA_GWDT_WCS 0x000
  26 +#define SBSA_GWDT_WOR 0x008
  27 +#define SBSA_GWDT_WCV 0x010
  28 +
  29 +/* refresh/control frame */
  30 +#define SBSA_GWDT_W_IIDR 0xfcc
  31 +#define SBSA_GWDT_IDR 0xfd0
  32 +
  33 +/* Watchdog Control and Status Register */
  34 +#define SBSA_GWDT_WCS_EN BIT(0)
  35 +#define SBSA_GWDT_WCS_WS0 BIT(1)
  36 +#define SBSA_GWDT_WCS_WS1 BIT(2)
  37 +
  38 +struct sbsa_gwdt_priv {
  39 + void __iomem *reg_refresh;
  40 + void __iomem *reg_control;
  41 +};
  42 +
  43 +static int sbsa_gwdt_reset(struct udevice *dev)
  44 +{
  45 + struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  46 +
  47 + writel(0, priv->reg_refresh + SBSA_GWDT_WRR);
  48 +
  49 + return 0;
  50 +}
  51 +
  52 +static int sbsa_gwdt_start(struct udevice *dev, u64 timeout, ulong flags)
  53 +{
  54 + struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  55 + u32 clk;
  56 +
  57 + /*
  58 + * it work in the single stage mode in u-boot,
  59 + * The first signal (WS0) is ignored,
  60 + * the timeout is (WOR * 2), so the WOR should be configured
  61 + * to half value of timeout.
  62 + */
  63 + clk = get_tbclk();
  64 + writel(clk / 2 * timeout,
  65 + priv->reg_control + SBSA_GWDT_WOR);
  66 +
  67 + /* writing WCS will cause an explicit watchdog refresh */
  68 + writel(SBSA_GWDT_WCS_EN, priv->reg_control + SBSA_GWDT_WCS);
  69 +
  70 + return 0;
  71 +}
  72 +
  73 +static int sbsa_gwdt_stop(struct udevice *dev)
  74 +{
  75 + struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  76 +
  77 + writel(0, priv->reg_control + SBSA_GWDT_WCS);
  78 +
  79 + return 0;
  80 +}
  81 +
  82 +static int sbsa_gwdt_expire_now(struct udevice *dev, ulong flags)
  83 +{
  84 + sbsa_gwdt_start(dev, 0, flags);
  85 +
  86 + return 0;
  87 +}
  88 +
  89 +static int sbsa_gwdt_probe(struct udevice *dev)
  90 +{
  91 + debug("%s: Probing wdt%u (sbsa-gwdt)\n", __func__, dev->seq);
  92 +
  93 + return 0;
  94 +}
  95 +
  96 +static int sbsa_gwdt_ofdata_to_platdata(struct udevice *dev)
  97 +{
  98 + struct sbsa_gwdt_priv *priv = dev_get_priv(dev);
  99 +
  100 + priv->reg_control = (void __iomem *)dev_read_addr_index(dev, 0);
  101 + if (IS_ERR(priv->reg_control))
  102 + return PTR_ERR(priv->reg_control);
  103 +
  104 + priv->reg_refresh = (void __iomem *)dev_read_addr_index(dev, 1);
  105 + if (IS_ERR(priv->reg_refresh))
  106 + return PTR_ERR(priv->reg_refresh);
  107 +
  108 + return 0;
  109 +}
  110 +
  111 +static const struct wdt_ops sbsa_gwdt_ops = {
  112 + .start = sbsa_gwdt_start,
  113 + .reset = sbsa_gwdt_reset,
  114 + .stop = sbsa_gwdt_stop,
  115 + .expire_now = sbsa_gwdt_expire_now,
  116 +};
  117 +
  118 +static const struct udevice_id sbsa_gwdt_ids[] = {
  119 + { .compatible = "arm,sbsa-gwdt" },
  120 + {}
  121 +};
  122 +
  123 +U_BOOT_DRIVER(sbsa_gwdt) = {
  124 + .name = "sbsa_gwdt",
  125 + .id = UCLASS_WDT,
  126 + .of_match = sbsa_gwdt_ids,
  127 + .probe = sbsa_gwdt_probe,
  128 + .priv_auto_alloc_size = sizeof(struct sbsa_gwdt_priv),
  129 + .ofdata_to_platdata = sbsa_gwdt_ofdata_to_platdata,
  130 + .ops = &sbsa_gwdt_ops,
  131 +};