From: Pramod Kumar <[email protected]>

Add sp805 watchdog driver for Broadcom iproc socs (DM).

Signed-off-by: Pramod Kumar <[email protected]>
Signed-off-by: Vladimir Olovyannikov <[email protected]>
---
 drivers/watchdog/Kconfig        |  10 ++
 drivers/watchdog/Makefile       |   1 +
 drivers/watchdog/sp805_wdt_dm.c | 181 ++++++++++++++++++++++++++++++++
 3 files changed, 192 insertions(+)
 create mode 100644 drivers/watchdog/sp805_wdt_dm.c

diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8c16d69d33..74a5319467 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -40,6 +40,16 @@ config OMAP_WATCHDOG
        help
          Say Y here to enable the OMAP3+ watchdog driver.
 
+config SP805_WATCHDOG
+       bool "Enable ARM SP805 watchdog driver (DM)"
+       depends on WDT
+       imply WATCHDOG
+       help
+         Say Y here to enable the sp805 watchdog (DM)
+
+         This provides basic infrastructure to support sp805 watchdog
+         hardware; driver model.
+
 config ULP_WATCHDOG
        bool "i.MX7ULP watchdog"
        help
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 955caef815..aacabf1f2e 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_S5P)               += s5p_wdt.o
 obj-$(CONFIG_XILINX_TB_WATCHDOG) += xilinx_tb_wdt.o
 obj-$(CONFIG_OMAP_WATCHDOG) += omap_wdt.o
 obj-$(CONFIG_DESIGNWARE_WATCHDOG) += designware_wdt.o
+obj-$(CONFIG_SP805_WATCHDOG) += sp805_iproc_dm.o
 obj-$(CONFIG_ULP_WATCHDOG) += ulp_wdog.o
 obj-$(CONFIG_$(SPL_TPL_)WDT) += wdt-uclass.o
 obj-$(CONFIG_WDT_SANDBOX) += sandbox_wdt.o
diff --git a/drivers/watchdog/sp805_wdt_dm.c b/drivers/watchdog/sp805_wdt_dm.c
new file mode 100644
index 0000000000..56d0e77080
--- /dev/null
+++ b/drivers/watchdog/sp805_wdt_dm.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Broadcom.
+ */
+
+#include <common.h>
+#include <command.h>
+#include <dm/device.h>
+#include <dm/read.h>
+#include <log.h>
+#include <wdt.h>
+#include <asm/io.h>
+#include <linux/bitops.h>
+
+/* SP805 register offset */
+#define SP805_WDOG_LOAD_OFF            0x000
+#define SP805_WDOG_CTR_OFF             0x008
+#define SP805_WDOG_CLR_OFF             0x00c
+#define SP805_WDOG_LOCK_OFF            0xc00
+
+/* Magic word to unlock the wd registers */
+#define WDOG_UNLOCK_KEY                        0x1ACCE551
+
+/* Register field definitions */
+#define SP805_CTR_RESEN                        BIT(1)
+#define SP805_CTR_INTEN                        BIT(0)
+
+struct sp805_wdt_platdata {
+       void __iomem *regs;
+       u32 timeout_msec;
+       u32 clk_mhz;
+};
+
+/* Inline register access functions */
+
+static inline void sp805_write_wdog_load(void __iomem *base, u32 value)
+{
+       writel(value, base + SP805_WDOG_LOAD_OFF);
+}
+
+static inline void sp805_write_wdog_ctrl(void __iomem *base, u32 value)
+{
+       writel(value, base + SP805_WDOG_CTR_OFF);
+}
+
+static inline void sp805_write_wdog_lock(void __iomem *base, u32 value)
+{
+       writel(value, base + SP805_WDOG_LOCK_OFF);
+}
+
+static inline void sp805_write_wdog_kick(void __iomem *base, u32 value)
+{
+       writel(value, base + SP805_WDOG_CLR_OFF);
+}
+
+static u32 msec_to_ticks(struct udevice *dev)
+{
+       u32 timeout_msec;
+       u32 msec;
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+
+       timeout_msec = env_get_ulong("wdt_timeout_msec", 16, 0);
+       if (timeout_msec) {
+               dev_dbg(dev, "Overriding timeout :%u\n", timeout_msec);
+               msec = timeout_msec;
+       } else {
+               msec = pd->timeout_msec;
+       }
+
+       timeout_msec = (msec / 2) * (pd->clk_mhz / 1000);
+
+       dev_dbg(dev, "ticks :%u\n", timeout_msec);
+
+       return timeout_msec;
+}
+
+static int sp805_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+
+       sp805_write_wdog_lock(pd->regs, WDOG_UNLOCK_KEY);
+       sp805_write_wdog_load(pd->regs, 0);
+       sp805_write_wdog_lock(pd->regs, 0);
+
+       return 0;
+}
+
+static int sp805_wdt_reset(struct udevice *dev)
+{
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+       u32 ticks;
+
+       ticks = msec_to_ticks(dev);
+
+       sp805_write_wdog_lock(pd->regs, WDOG_UNLOCK_KEY);
+       sp805_write_wdog_load(pd->regs, ticks);
+       sp805_write_wdog_lock(pd->regs, 0);
+
+       dev_dbg(dev, "%s ", __func__);
+
+       return 0;
+}
+
+static int sp805_wdt_stop(struct udevice *dev)
+{
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+
+       sp805_write_wdog_lock(pd->regs, WDOG_UNLOCK_KEY);
+       sp805_write_wdog_ctrl(pd->regs, 0);
+
+       dev_dbg(dev, "Watchdog disabled!\n");
+
+       return 0;
+}
+
+static int sp805_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+       u32 ticks;
+
+       ticks = msec_to_ticks(dev);
+
+       dev_dbg(dev, "%s:\n", __func__);
+
+       sp805_write_wdog_load(pd->regs, ticks);
+       sp805_write_wdog_ctrl(pd->regs, SP805_CTR_RESEN | SP805_CTR_INTEN);
+       /* Lock registers access */
+       sp805_write_wdog_lock(pd->regs, 0);
+
+       return 0;
+}
+
+static int sp805_wdt_probe(struct udevice *dev)
+{
+       dev_dbg(dev, "%s: Probing wdt%u\n", __func__, dev->seq);
+
+       return 0;
+}
+
+static int sp805_wdt_ofdata_to_platdata(struct udevice *dev)
+{
+       struct sp805_wdt_platdata *pd = dev_get_platdata(dev);
+
+       dev_dbg(dev, "%s->\n", __func__);
+       pd->regs = dev_read_addr_ptr(dev);
+       if (!pd->regs)
+               return -ENODEV;
+
+       if (dev_read_u32(dev, "timeout-msec", &pd->timeout_msec))
+               return -ENODATA;
+
+       if (dev_read_u32(dev, "clk-mhz", &pd->clk_mhz))
+               return -ENODATA;
+
+       dev_dbg(dev, "%s: regs:%p, msec :%u, clk %u\n", __func__,
+               pd->regs, pd->timeout_msec, pd->clk_mhz);
+
+       return 0;
+}
+
+static const struct wdt_ops sp805_wdt_ops = {
+       .start = sp805_wdt_start,
+       .reset = sp805_wdt_reset,
+       .stop = sp805_wdt_stop,
+       .expire_now = sp805_wdt_expire_now,
+};
+
+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,
+       .platdata_auto_alloc_size = sizeof(struct sp805_wdt_platdata),
+       .ofdata_to_platdata = sp805_wdt_ofdata_to_platdata,
+       .ops = &sp805_wdt_ops,
+};
-- 
2.17.1

_______________________________________________
U-Boot mailing list
[email protected]
https://lists.denx.de/listinfo/u-boot

Reply via email to