Message ID | 20190429082611.21614-2-qiang.zhao@nxp.com |
---|---|
State | Superseded |
Delegated to: | Prabhakar Kushwaha |
Headers | show |
Series | add new wdt driver for sp805 | expand |
On 29.04.19 10:24, Qiang Zhao wrote: > sp805 is watchdog on some NXP layerscape SoCs, Now add its driver in uboot. > To add > CONFIG_WDT_SP805=y > CONFIG_WDT=y > CONFIG_CMD_WDT=y > in defconfig to use it. > > Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com> > --- > MAINTAINERS | 1 + > drivers/watchdog/Kconfig | 7 ++ > drivers/watchdog/Makefile | 1 + > drivers/watchdog/sp805_wdt.c | 126 +++++++++++++++++++++++++++++++++++ > 4 files changed, 135 insertions(+) > create mode 100644 drivers/watchdog/sp805_wdt.c > > diff --git a/MAINTAINERS b/MAINTAINERS > index 8f237128b2..e8e7a92802 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -410,6 +410,7 @@ FREESCALE QORIQ > M: York Sun <york.sun@nxp.com> > S: Maintained > T: git git://git.denx.de/u-boot-fsl-qoriq.git > +F: drivers/watchdog/sp805_wdt.c > > I2C > M: Heiko Schocher <hs@denx.de> > diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig > index b06c5447f6..29e04630d2 100644 > --- a/drivers/watchdog/Kconfig > +++ b/drivers/watchdog/Kconfig > @@ -95,6 +95,13 @@ config WDT_ORION > Select this to enable Orion watchdog timer, which can be found on some > Marvell Armada chips. > > +config WDT_SP805 > + bool "SP805 watchdog timer support" > + depends on WDT > + help > + Select this to enable SP805 watchdog timer, which can be found on some > + nxp layerscape chips. > + > config WDT_CDNS > bool "Cadence watchdog timer support" > depends on WDT > diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile > index 19c631bb58..eb285bde24 100644 > --- a/drivers/watchdog/Makefile > +++ b/drivers/watchdog/Makefile > @@ -25,3 +25,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o > obj-$(CONFIG_WDT_ORION) += orion_wdt.o > obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o > obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o > +obj-$(CONFIG_WDT_SP805) += sp805_wdt.o > diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c > new file mode 100644 > index 0000000000..e4d81c995d > --- /dev/null > +++ b/drivers/watchdog/sp805_wdt.c > @@ -0,0 +1,126 @@ > +// SPDX-License-Identifier: GPL-2.0+ > +/* > + * Watchdog driver for SP805 on some Layerscape SoC > + * > + * Copyright 2019 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> > + > +#define WDTLOAD 0x000 > +#define WDTCONTROL 0x008 > +#define WDTINTCLR 0x00C > +#define WDTLOCK 0xC00 > + > +#define TIME_OUT_DEFAULT_MSECS 15000 > +#define TIME_OUT_MIN_MSECS 1 > +#define TIME_OUT_MAX_MSECS 120000 > +#define SYS_FSL_WDT_CLK_DIV 16 > +#define INT_ENABLE BIT(0) > +#define RESET_ENABLE BIT(1) > +#define DISABLE 0 > +#define UNLOCK 0x1ACCE551 > +#define LOCK 0x00000001 > +#define INT_MASK BIT(0) > + > +DECLARE_GLOBAL_DATA_PTR; > + > +struct sp805_wdt_priv { > + void __iomem *reg; > + u32 timeout; You can drop this "timeout" variable here. > +}; > + > +static int sp805_wdt_reset(struct udevice *dev) > +{ > + struct sp805_wdt_priv *priv = dev_get_priv(dev); > + > + writel(UNLOCK, priv->reg + WDTLOCK); > + writel(INT_MASK, priv->reg + WDTINTCLR); > + writel(LOCK, priv->reg + WDTLOCK); > + readl(priv->reg + WDTLOCK); > + > + return 0; > +} > + > +static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags) > +{ > + u32 load_value; > + struct sp805_wdt_priv *priv = dev_get_priv(dev); > + > + priv->timeout = (u32)timeout; Again, the copy of timeout in "priv" is not needed. Or am I missing something? > + if (timeout < TIME_OUT_MIN_MSECS || timeout > TIME_OUT_MAX_MSECS) > + priv->timeout = TIME_OUT_DEFAULT_MSECS; Why not better clip the value to the min or max value instead of using a default value here? Please note that you can specify a timeout value via the "timeout-sec" DT property now with the new generic approach. Thanks, Stefan > + /* sp805 runs counter with given value twice, so when the timeout is > + * set 15s, the gd->bus_clk is less than 9162MHz, the load_value will > + * not overflow. > + */ > + load_value = (gd->bus_clk) / > + (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * priv->timeout; > + > + writel(UNLOCK, priv->reg + WDTLOCK); > + writel(load_value, priv->reg + WDTLOAD); > + writel(INT_MASK, priv->reg + WDTINTCLR); > + writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL); > + writel(LOCK, priv->reg + WDTLOCK); > + readl(priv->reg + WDTLOCK); > + > + return 0; > +} > + > +static int sp805_wdt_stop(struct udevice *dev) > +{ > + struct sp805_wdt_priv *priv = dev_get_priv(dev); > + > + writel(UNLOCK, priv->reg + WDTLOCK); > + writel(DISABLE, priv->reg + WDTCONTROL); > + writel(LOCK, priv->reg + WDTLOCK); > + readl(priv->reg + WDTLOCK); > + > + return 0; > +} > + > +static int sp805_wdt_probe(struct udevice *dev) > +{ > + debug("%s: Probing wdt%u\n", __func__, dev->seq); > + > + return 0; > +} > + > +static int sp805_wdt_ofdata_to_platdata(struct udevice *dev) > +{ > + struct sp805_wdt_priv *priv = dev_get_priv(dev); > + > + priv->reg = (void __iomem *)dev_read_addr(dev); > + if (IS_ERR(priv->reg)) > + return PTR_ERR(priv->reg); > + > + return 0; > +} > + > +static const struct wdt_ops sp805_wdt_ops = { > + .start = sp805_wdt_start, > + .reset = sp805_wdt_reset, > + .stop = sp805_wdt_stop, > +}; > + > +static const struct udevice_id sp805_wdt_ids[] = { > + { .compatible = "arm,sp805-wdt" }, > + {} > +}; > + > +U_BOOT_DRIVER(sp805_wdt) = { > + .name = "sp805_wdt", > + .id = UCLASS_WDT, > + .of_match = sp805_wdt_ids, > + .probe = sp805_wdt_probe, > + .priv_auto_alloc_size = sizeof(struct sp805_wdt_priv), > + .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata, > + .ops = &sp805_wdt_ops, > +}; >
diff --git a/MAINTAINERS b/MAINTAINERS index 8f237128b2..e8e7a92802 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -410,6 +410,7 @@ FREESCALE QORIQ M: York Sun <york.sun@nxp.com> S: Maintained T: git git://git.denx.de/u-boot-fsl-qoriq.git +F: drivers/watchdog/sp805_wdt.c I2C M: Heiko Schocher <hs@denx.de> diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index b06c5447f6..29e04630d2 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -95,6 +95,13 @@ config WDT_ORION Select this to enable Orion watchdog timer, which can be found on some Marvell Armada chips. +config WDT_SP805 + bool "SP805 watchdog timer support" + depends on WDT + help + Select this to enable SP805 watchdog timer, which can be found on some + nxp layerscape chips. + config WDT_CDNS bool "Cadence watchdog timer support" depends on WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 19c631bb58..eb285bde24 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o obj-$(CONFIG_WDT_ORION) += orion_wdt.o obj-$(CONFIG_WDT_CDNS) += cdns_wdt.o obj-$(CONFIG_MPC8xx_WATCHDOG) += mpc8xx_wdt.o +obj-$(CONFIG_WDT_SP805) += sp805_wdt.o diff --git a/drivers/watchdog/sp805_wdt.c b/drivers/watchdog/sp805_wdt.c new file mode 100644 index 0000000000..e4d81c995d --- /dev/null +++ b/drivers/watchdog/sp805_wdt.c @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Watchdog driver for SP805 on some Layerscape SoC + * + * Copyright 2019 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> + +#define WDTLOAD 0x000 +#define WDTCONTROL 0x008 +#define WDTINTCLR 0x00C +#define WDTLOCK 0xC00 + +#define TIME_OUT_DEFAULT_MSECS 15000 +#define TIME_OUT_MIN_MSECS 1 +#define TIME_OUT_MAX_MSECS 120000 +#define SYS_FSL_WDT_CLK_DIV 16 +#define INT_ENABLE BIT(0) +#define RESET_ENABLE BIT(1) +#define DISABLE 0 +#define UNLOCK 0x1ACCE551 +#define LOCK 0x00000001 +#define INT_MASK BIT(0) + +DECLARE_GLOBAL_DATA_PTR; + +struct sp805_wdt_priv { + void __iomem *reg; + u32 timeout; +}; + +static int sp805_wdt_reset(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(INT_MASK, priv->reg + WDTINTCLR); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags) +{ + u32 load_value; + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + priv->timeout = (u32)timeout; + if (timeout < TIME_OUT_MIN_MSECS || timeout > TIME_OUT_MAX_MSECS) + priv->timeout = TIME_OUT_DEFAULT_MSECS; + /* sp805 runs counter with given value twice, so when the timeout is + * set 15s, the gd->bus_clk is less than 9162MHz, the load_value will + * not overflow. + */ + load_value = (gd->bus_clk) / + (2 * 1000 * SYS_FSL_WDT_CLK_DIV) * priv->timeout; + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(load_value, priv->reg + WDTLOAD); + writel(INT_MASK, priv->reg + WDTINTCLR); + writel(INT_ENABLE | RESET_ENABLE, priv->reg + WDTCONTROL); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_stop(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + writel(UNLOCK, priv->reg + WDTLOCK); + writel(DISABLE, priv->reg + WDTCONTROL); + writel(LOCK, priv->reg + WDTLOCK); + readl(priv->reg + WDTLOCK); + + return 0; +} + +static int sp805_wdt_probe(struct udevice *dev) +{ + debug("%s: Probing wdt%u\n", __func__, dev->seq); + + return 0; +} + +static int sp805_wdt_ofdata_to_platdata(struct udevice *dev) +{ + struct sp805_wdt_priv *priv = dev_get_priv(dev); + + priv->reg = (void __iomem *)dev_read_addr(dev); + if (IS_ERR(priv->reg)) + return PTR_ERR(priv->reg); + + return 0; +} + +static const struct wdt_ops sp805_wdt_ops = { + .start = sp805_wdt_start, + .reset = sp805_wdt_reset, + .stop = sp805_wdt_stop, +}; + +static const struct udevice_id sp805_wdt_ids[] = { + { .compatible = "arm,sp805-wdt" }, + {} +}; + +U_BOOT_DRIVER(sp805_wdt) = { + .name = "sp805_wdt", + .id = UCLASS_WDT, + .of_match = sp805_wdt_ids, + .probe = sp805_wdt_probe, + .priv_auto_alloc_size = sizeof(struct sp805_wdt_priv), + .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata, + .ops = &sp805_wdt_ops, +};
sp805 is watchdog on some NXP layerscape SoCs, Now add its driver in uboot. To add CONFIG_WDT_SP805=y CONFIG_WDT=y CONFIG_CMD_WDT=y in defconfig to use it. Signed-off-by: Zhao Qiang <qiang.zhao@nxp.com> --- MAINTAINERS | 1 + drivers/watchdog/Kconfig | 7 ++ drivers/watchdog/Makefile | 1 + drivers/watchdog/sp805_wdt.c | 126 +++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+) create mode 100644 drivers/watchdog/sp805_wdt.c