[PATCH 02/10] watchdog: add sl28cpld watchdog driver

Michael Walle michael at walle.cc
Mon Nov 15 23:45:43 CET 2021


The watchdog timer is part of the sl28cpld management controller. The
watchdog timer usually supervises the bootloader boot-up and if it bites
the failsafe bootloader will be activated. Apart from that it supports
the usual board level reset and one SMARC speciality: driving the
WDT_TIMEOUT# signal.

Signed-off-by: Michael Walle <michael at walle.cc>
---
 MAINTAINERS                     |   1 +
 doc/board/kontron/sl28.rst      |  53 +++++++++++-----
 drivers/watchdog/Kconfig        |   7 ++
 drivers/watchdog/Makefile       |   1 +
 drivers/watchdog/sl28cpld-wdt.c | 109 ++++++++++++++++++++++++++++++++
 5 files changed, 154 insertions(+), 17 deletions(-)
 create mode 100644 drivers/watchdog/sl28cpld-wdt.c

diff --git a/MAINTAINERS b/MAINTAINERS
index e9d0bd0818..d7f09e1c81 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1104,6 +1104,7 @@ SL28CLPD
 M:	Michael Walle <michael at walle.cc>
 S:	Maintained
 F:	drivers/misc/sl28cpld.c
+F:	drivers/watchdog/sl28cpld-wdt.c
 
 SPI
 M:	Jagan Teki <jagan at amarulasolutions.com>
diff --git a/doc/board/kontron/sl28.rst b/doc/board/kontron/sl28.rst
index c7b18bed10..c2cdc5e424 100644
--- a/doc/board/kontron/sl28.rst
+++ b/doc/board/kontron/sl28.rst
@@ -35,23 +35,6 @@ The board is fully failsafe, you can't break anything. But because you've
 disabled the builtin watchdog you might have to manually enter failsafe
 mode by asserting the ``FORCE_RECOV#`` line during board reset.
 
-Disable the builtin watchdog
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-- boot into the failsafe bootloader, either by asserting the
-  ``FORCE_RECOV#`` line or if you still have the original bootloader
-  installed you can use the command::
-
-  > wdt dev cpld_watchdog at 4a; wdt expire 1
-
-- in the failsafe bootloader use the "sl28 nvm" command to disable
-  the automatic start of the builtin watchdog::
-
-  > sl28 nvm 0008
-
-- power-cycle the board
-
-
 Update image
 ------------
 
@@ -82,6 +65,42 @@ u-boot (yet). But you can use the i2c command to access it.
   > i2c md 4a 3.1 1
 
 
+Builtin watchdog
+----------------
+
+The builtin watchdog will supervise the bootloader startup. If anything
+goes wrong it will reset the board and boot into the failsafe bootloader.
+
+Once the bootloader is started successfully, it will disable the watchdog
+timer.
+
+wdt command flags
+^^^^^^^^^^^^^^^^^
+
+The `wdt start` as well as the `wdt expire` command take a flags argument.
+The supported bitmask is as follows.
+
+| Bit | Description                   |
+| --- | ----------------------------- |
+|   0 | Enable failsafe mode          |
+|   1 | Lock the control register     |
+|   2 | Disable board reset           |
+|   3 | Enable WDT_TIME_OUT# line     |
+
+For example, you can use `wdt expire 1` to issue a reset and boot into the
+failsafe bootloader.
+
+Disable the builtin watchdog
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+If for some reason, this isn't a desired behavior, the watchdog can also
+be configured to not be enabled on board reset. It's configuration is saved
+in the non-volatile board configuration bits. To change these you can use
+the `sl28 nvm` command.
+
+For more information on the non-volatile board configuration bits, see the
+following section.
+
 Non-volatile Board Configuration Bits
 -------------------------------------
 
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 1177f17fd8..a232b595ba 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -257,6 +257,13 @@ config WDT_SBSA
 	   In the single stage mode, when the timeout is reached, your system
 	   will be reset by WS1. The first signal (WS0) is ignored.
 
+config WDT_SL28CPLD
+	bool "sl28cpld watchdog timer support"
+	depends on WDT && SL28CPLD
+	help
+	  Enable support for the watchdog timer in the Kontron sl28cpld
+	  management controller.
+
 config WDT_SP805
 	bool "SP805 watchdog timer support"
 	depends on WDT
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index fa7ce583ce..8c6e5326c0 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -34,6 +34,7 @@ obj-$(CONFIG_WDT_OCTEONTX) += octeontx_wdt.o
 obj-$(CONFIG_WDT_OMAP3) += omap_wdt.o
 obj-$(CONFIG_WDT_SBSA) += sbsa_gwdt.o
 obj-$(CONFIG_WDT_K3_RTI) += rti_wdt.o
+obj-$(CONFIG_WDT_SL28CPLD) += sl28cpld-wdt.o
 obj-$(CONFIG_WDT_SP805) += sp805_wdt.o
 obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o
 obj-$(CONFIG_WDT_SUNXI) += sunxi_wdt.o
diff --git a/drivers/watchdog/sl28cpld-wdt.c b/drivers/watchdog/sl28cpld-wdt.c
new file mode 100644
index 0000000000..af5a6b1a28
--- /dev/null
+++ b/drivers/watchdog/sl28cpld-wdt.c
@@ -0,0 +1,109 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Watchdog driver for the sl28cpld
+ *
+ * Copyright (c) 2021 Michael Walle <michael at walle.cc>
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <wdt.h>
+#include <sl28cpld.h>
+#include <div64.h>
+
+#define SL28CPLD_WDT_CTRL		0x00
+#define  WDT_CTRL_EN0			BIT(0)
+#define  WDT_CTRL_EN1			BIT(1)
+#define  WDT_CTRL_EN_MASK		GENMASK(1, 0)
+#define  WDT_CTRL_LOCK			BIT(2)
+#define  WDT_CTRL_ASSERT_SYS_RESET	BIT(6)
+#define  WDT_CTRL_ASSERT_WDT_TIMEOUT	BIT(7)
+#define SL28CPLD_WDT_TIMEOUT		0x01
+#define SL28CPLD_WDT_KICK		0x02
+#define  WDT_KICK_VALUE			0x6b
+
+static int sl28cpld_wdt_reset(struct udevice *dev)
+{
+	return sl28cpld_write(dev, SL28CPLD_WDT_KICK, WDT_KICK_VALUE);
+}
+
+static int sl28cpld_wdt_start(struct udevice *dev, u64 timeout, ulong flags)
+{
+	int ret, val;
+
+	val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
+	if (val < 0)
+		return val;
+
+	/* (1) disable watchdog */
+	val &= ~WDT_CTRL_EN_MASK;
+	ret = sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
+	if (ret)
+		return ret;
+
+	/* (2) set timeout */
+	ret = sl28cpld_write(dev, SL28CPLD_WDT_TIMEOUT, lldiv(timeout, 1000));
+	if (ret)
+		return ret;
+
+	/* (3) kick it, will reset timer to the timeout value */
+	ret = sl28cpld_wdt_reset(dev);
+	if (ret)
+		return ret;
+
+	/* (4) enable either recovery or normal one */
+	if (flags & BIT(0))
+		val |= WDT_CTRL_EN1;
+	else
+		val |= WDT_CTRL_EN0;
+
+	if (flags & BIT(1))
+		val |= WDT_CTRL_LOCK;
+
+	if (flags & BIT(2))
+		val &= ~WDT_CTRL_ASSERT_SYS_RESET;
+	else
+		val |= WDT_CTRL_ASSERT_SYS_RESET;
+
+	if (flags & BIT(3))
+		val |= WDT_CTRL_ASSERT_WDT_TIMEOUT;
+	else
+		val &= ~WDT_CTRL_ASSERT_WDT_TIMEOUT;
+
+	return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val);
+}
+
+static int sl28cpld_wdt_stop(struct udevice *dev)
+{
+	int val;
+
+	val = sl28cpld_read(dev, SL28CPLD_WDT_CTRL);
+	if (val < 0)
+		return val;
+
+	return sl28cpld_write(dev, SL28CPLD_WDT_CTRL, val & ~WDT_CTRL_EN_MASK);
+}
+
+static int sl28cpld_wdt_expire_now(struct udevice *dev, ulong flags)
+{
+	return sl28cpld_wdt_start(dev, 0, flags);
+}
+
+static const struct wdt_ops sl28cpld_wdt_ops = {
+	.start = sl28cpld_wdt_start,
+	.reset = sl28cpld_wdt_reset,
+	.stop = sl28cpld_wdt_stop,
+	.expire_now = sl28cpld_wdt_expire_now,
+};
+
+static const struct udevice_id sl28cpld_wdt_ids[] = {
+	{ .compatible = "kontron,sl28cpld-wdt", },
+	{}
+};
+
+U_BOOT_DRIVER(sl28cpld_wdt) = {
+	.name = "sl28cpld-wdt",
+	.id = UCLASS_WDT,
+	.of_match = sl28cpld_wdt_ids,
+	.ops = &sl28cpld_wdt_ops,
+};
-- 
2.30.2



More information about the U-Boot mailing list