Message ID | 20200611115236.3107-1-biwen.li@oss.nxp.com |
---|---|
State | Superseded |
Headers | show |
Series | [v2,1/3] Watchdog: introduce ARM SBSA watchdog driver | expand |
On 11.06.20 13:52, Biwen Li wrote: > From: Zhao Qiang <qiang.zhao at nxp.com> > > 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 at nxp.com> > Signed-off-by: Biwen Li <biwen.li at nxp.com> > --- > 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 <priyanka.jain at nxp.com> > 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 <hs at denx.de> > 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. Please extend this help text a bit (add something from the commit text) to make it more descriptive. > + > 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 <asm/io.h> > +#include <common.h> > +#include <dm/device.h> > +#include <dm/fdtaddr.h> > +#include <dm/read.h> > +#include <linux/bitops.h> > +#include <watchdog.h> > +#include <wdt.h> > + > +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); Nitpicking: Remove empty line above and add sone below the variable declarations (reverse x-max tree is preferred): struct sbsa_gwdt_priv *priv = dev_get_priv(dev); u32 load_value; u32 clk; Other than that: Reviewed-by: Stefan Roese <sr at denx.de> Thanks, Stefan > + /* > + * 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, > +}; > Viele Gr??e, Stefan
> > 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 at nxp.com> > > Signed-off-by: Biwen Li <biwen.li at nxp.com> > > --- > > 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 <priyanka.jain at nxp.com> > > 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 <hs at denx.de> > > 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. > > Please extend this help text a bit (add something from the commit text) to > make it more descriptive. Okay, it will be updated in v3. > > > + > > 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 <asm/io.h> > > +#include <common.h> > > +#include <dm/device.h> > > +#include <dm/fdtaddr.h> > > +#include <dm/read.h> > > +#include <linux/bitops.h> > > +#include <watchdog.h> > > +#include <wdt.h> > > + > > +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); > > Nitpicking: > > Remove empty line above and add sone below the variable declarations > (reverse x-max tree is preferred): > > struct sbsa_gwdt_priv *priv = dev_get_priv(dev); > u32 load_value; > u32 clk; Okay, it will be updated in v3. > > Other than that: > > Reviewed-by: Stefan Roese <sr at denx.de> > Okay, got it. > Thanks, > Stefan > > > + /* > > + * 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, > > +}; > > > > > Viele Gr??e, > Stefan > > -- > DENX Software Engineering GmbH, Managing Director: Wolfgang Denk > HRB 165235 Munich, Office: Kirchenstr.5, D-82194 Groebenzell, Germany > Phone: (+49)-8142-66989-51 Fax: (+49)-8142-66989-80 Email: sr at denx.de
diff --git a/MAINTAINERS b/MAINTAINERS index 1fd975c..09554c0 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -685,6 +685,7 @@ M: Priyanka Jain <priyanka.jain at nxp.com> 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 <hs at denx.de> 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 <asm/io.h> +#include <common.h> +#include <dm/device.h> +#include <dm/fdtaddr.h> +#include <dm/read.h> +#include <linux/bitops.h> +#include <watchdog.h> +#include <wdt.h> + +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, +};