* [PATCH 0/3] watchdog: Add TI rti_wdg support
@ 2024-11-12 9:16 Sascha Hauer
2024-11-12 9:16 ` [PATCH 1/3] watchdog: cleanup timeout_cur parameter Sascha Hauer
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: Sascha Hauer @ 2024-11-12 9:16 UTC (permalink / raw)
To: open list:BAREBOX
This series adds support for the rti_wdg found on TI K3 SoCs. The
timeout for this watchdog cannot be reconfigured once started which
doesn't fit well into our current watchdog_set_timeout() API which
both pings the watchdog and starts it. For this reason this series
introduces an optional watchdog_ping() function which can be used
for this type of watchdog.
Sascha
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
Sascha Hauer (3):
watchdog: cleanup timeout_cur parameter
watchdog: add watchdog ping support
watchdog: add rti_wdt support
commands/wd.c | 17 ++++-
drivers/watchdog/Kconfig | 7 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/rti_wdt.c | 183 +++++++++++++++++++++++++++++++++++++++++++++
drivers/watchdog/wd_core.c | 43 ++++++++---
include/watchdog.h | 8 +-
6 files changed, 245 insertions(+), 14 deletions(-)
---
base-commit: 11e7f69879ca71f63f4b122c0438c4085281fe17
change-id: 20241112-k3-watchdog-5cee942f319a
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 1/3] watchdog: cleanup timeout_cur parameter
2024-11-12 9:16 [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
@ 2024-11-12 9:16 ` Sascha Hauer
2024-11-12 9:16 ` [PATCH 2/3] watchdog: add watchdog ping support Sascha Hauer
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2024-11-12 9:16 UTC (permalink / raw)
To: open list:BAREBOX
Currently a watchdog has a timeout_cur device parameter which has
a slightly confusing behaviour. The parameter has nothing to do with the
currently configured watchdog timeout, instead it is merely used by
the automatic watchdog feeder which configures the watchdog timeout
with that value.
Refine the semantics of the parameter by using it as the watchdog
timeout as the name suggests. When read, it returns the currently
configured timeout. When set, it configures the watchdog timeout
and starts it (unless it's set to 0 in which case the watchdog will
be disabled).
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/watchdog/wd_core.c | 23 +++++++++++------------
include/watchdog.h | 1 -
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index d4de213fa5..663a6e5c75 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -71,17 +71,18 @@ static int watchdog_set_cur(struct param_d *param, void *priv)
{
struct watchdog *wd = priv;
- if (wd->poller_timeout_cur > wd->timeout_max)
- return -EINVAL;
-
- return 0;
+ return watchdog_set_timeout(wd, wd->timeout_cur);
}
static void watchdog_poller_cb(void *priv);
static void watchdog_poller_start(struct watchdog *wd)
{
- watchdog_set_timeout(wd, wd->poller_timeout_cur);
+ unsigned int timeout_s;
+
+ timeout_s = wd->timeout_cur ?: wd->timeout_max;
+
+ watchdog_set_timeout(wd, timeout_s);
poller_call_async(&wd->poller, 500 * MSECOND,
watchdog_poller_cb, wd);
@@ -201,16 +202,14 @@ int watchdog_register(struct watchdog *wd)
dev_add_param_uint32_ro(&wd->dev, "timeout_max",
&wd->timeout_max, "%u");
- if (IS_ENABLED(CONFIG_WATCHDOG_POLLER)) {
- if (!wd->poller_timeout_cur ||
- wd->poller_timeout_cur > wd->timeout_max)
- wd->poller_timeout_cur = wd->timeout_max;
+ if (wd->timeout_cur > wd->timeout_max)
+ wd->timeout_cur = wd->timeout_max;
- dev_add_param_uint32(&wd->dev, "timeout_cur", watchdog_set_cur,
- NULL, &wd->poller_timeout_cur, "%u", wd);
+ dev_add_param_uint32(&wd->dev, "timeout_cur", watchdog_set_cur,
+ NULL, &wd->timeout_cur, "%u", wd);
+ if (IS_ENABLED(CONFIG_WATCHDOG_POLLER))
watchdog_register_poller(wd);
- }
dev_add_param_uint32(&wd->dev, "seconds_to_expire", param_set_readonly,
seconds_to_expire_get, &wd->seconds_to_expire, "%d", wd);
diff --git a/include/watchdog.h b/include/watchdog.h
index eaea07910c..8084f27596 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -23,7 +23,6 @@ struct watchdog {
unsigned int priority;
unsigned int timeout_max;
unsigned int timeout_cur;
- unsigned int poller_timeout_cur;
unsigned int poller_enable;
uint64_t last_ping;
int seconds_to_expire;
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 2/3] watchdog: add watchdog ping support
2024-11-12 9:16 [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
2024-11-12 9:16 ` [PATCH 1/3] watchdog: cleanup timeout_cur parameter Sascha Hauer
@ 2024-11-12 9:16 ` Sascha Hauer
2024-11-12 9:16 ` [PATCH 3/3] watchdog: add rti_wdt support Sascha Hauer
2024-11-13 11:33 ` [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2024-11-12 9:16 UTC (permalink / raw)
To: open list:BAREBOX
The barebox watchdog API is quite limited. the set_timeout() hook is an
all purpose function for enabling and disabling the watchdog and also to
configure the timeout.
This is not suitable for watchdogs which for example can't change the
timeout anymore once started.
This patch introduces a watchdog_ping() function which hooks into the
drivers with a struct watchdog::ping function. With this the watchdog
can be pinged without caring about the timeout. The ping hook is
optional. When not implemented watchdog_ping() falls back to call
watchdog_set_timeout() with the current watchdog timeout.
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
commands/wd.c | 17 ++++++++++++++++-
drivers/watchdog/wd_core.c | 28 ++++++++++++++++++++++++----
include/watchdog.h | 7 +++++++
3 files changed, 47 insertions(+), 5 deletions(-)
diff --git a/commands/wd.c b/commands/wd.c
index 11f888133a..18e8e03378 100644
--- a/commands/wd.c
+++ b/commands/wd.c
@@ -17,14 +17,18 @@ static int do_wd(int argc, char *argv[])
struct watchdog *wd = watchdog_get_default();
int opt;
int rc;
+ bool do_ping = false;
- while ((opt = getopt(argc, argv, "d:x")) > 0) {
+ while ((opt = getopt(argc, argv, "d:xp")) > 0) {
switch (opt) {
case 'd':
wd = watchdog_get_by_name(optarg);
break;
case 'x':
return watchdog_inhibit_all();
+ case 'p':
+ do_ping = true;
+ break;
default:
return COMMAND_ERROR_USAGE;
}
@@ -39,6 +43,16 @@ static int do_wd(int argc, char *argv[])
}
}
+ if (do_ping) {
+ rc = watchdog_ping(wd);
+ if (rc) {
+ printf("watchdog ping failed: %pe (%d)\n", ERR_PTR(rc), rc);
+ return COMMAND_ERROR;
+ }
+
+ return 0;
+ }
+
rc = watchdog_set_timeout(wd, timeout);
if (rc < 0) {
switch (rc) {
@@ -68,6 +82,7 @@ BAREBOX_CMD_HELP_TEXT("When TIME is 0, the watchdog gets disabled,")
BAREBOX_CMD_HELP_TEXT("Without a parameter the watchdog will be re-triggered.")
BAREBOX_CMD_HELP_TEXT("Options:")
BAREBOX_CMD_HELP_OPT("-d DEVICE\t", "watchdog name (default is highest priority watchdog)")
+BAREBOX_CMD_HELP_OPT("-p\t", "ping watchdog")
BAREBOX_CMD_HELP_OPT("-x\t", "inhibit all watchdogs (i.e. disable or autopoll if possible)")
BAREBOX_CMD_HELP_END
diff --git a/drivers/watchdog/wd_core.c b/drivers/watchdog/wd_core.c
index 663a6e5c75..27371672f3 100644
--- a/drivers/watchdog/wd_core.c
+++ b/drivers/watchdog/wd_core.c
@@ -57,6 +57,29 @@ int watchdog_set_timeout(struct watchdog *wd, unsigned timeout)
}
EXPORT_SYMBOL(watchdog_set_timeout);
+int watchdog_ping(struct watchdog *wd)
+{
+ int ret;
+
+ if (!wd)
+ return -ENODEV;
+
+ if (!watchdog_hw_running(wd))
+ return 0;
+
+ if (wd->ping) {
+ ret = wd->ping(wd);
+ if (!ret)
+ wd->last_ping = get_time_ns();
+ } else {
+ if (!wd->timeout_cur)
+ wd->timeout_cur = wd->timeout_max;
+ ret = watchdog_set_timeout(wd, wd->timeout_cur);
+ }
+
+ return ret;
+}
+
static int watchdog_set_priority(struct param_d *param, void *priv)
{
struct watchdog *wd = priv;
@@ -78,11 +101,8 @@ static void watchdog_poller_cb(void *priv);
static void watchdog_poller_start(struct watchdog *wd)
{
- unsigned int timeout_s;
-
- timeout_s = wd->timeout_cur ?: wd->timeout_max;
+ watchdog_ping(wd);
- watchdog_set_timeout(wd, timeout_s);
poller_call_async(&wd->poller, 500 * MSECOND,
watchdog_poller_cb, wd);
diff --git a/include/watchdog.h b/include/watchdog.h
index 8084f27596..c70883fbd0 100644
--- a/include/watchdog.h
+++ b/include/watchdog.h
@@ -17,6 +17,7 @@ struct device_node;
struct watchdog {
int (*set_timeout)(struct watchdog *, unsigned);
+ int (*ping)(struct watchdog *);
const char *name;
struct device *hwdev;
struct device dev;
@@ -49,6 +50,7 @@ struct watchdog *watchdog_get_default(void);
struct watchdog *watchdog_get_by_name(const char *name);
int watchdog_get_alias_id_from(struct watchdog *, struct device_node *);
int watchdog_set_timeout(struct watchdog*, unsigned);
+int watchdog_ping(struct watchdog *);
int watchdog_inhibit_all(void);
#else
static inline int watchdog_register(struct watchdog *w)
@@ -76,6 +78,11 @@ static inline int watchdog_set_timeout(struct watchdog*w, unsigned t)
return 0;
}
+static inline int watchdog_ping(struct watchdog *)
+{
+ return 0;
+}
+
static inline int watchdog_inhibit_all(void)
{
return -ENOSYS;
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH 3/3] watchdog: add rti_wdt support
2024-11-12 9:16 [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
2024-11-12 9:16 ` [PATCH 1/3] watchdog: cleanup timeout_cur parameter Sascha Hauer
2024-11-12 9:16 ` [PATCH 2/3] watchdog: add watchdog ping support Sascha Hauer
@ 2024-11-12 9:16 ` Sascha Hauer
2024-11-13 11:33 ` [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2024-11-12 9:16 UTC (permalink / raw)
To: open list:BAREBOX
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
drivers/watchdog/Kconfig | 7 ++
drivers/watchdog/Makefile | 1 +
drivers/watchdog/rti_wdt.c | 183 +++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 191 insertions(+)
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 762e37c9c2..62b44df7c1 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -177,4 +177,11 @@ config CADENCE_WATCHDOG
Say Y here if you want to include support for the watchdog
timer in the Xilinx Zynq.
+config K3_RTI_WDT
+ bool "Texas Instruments K3 RTI watchdog"
+ depends on ARCH_K3 || COMPILE_TEST
+ help
+ Say Y here if you want to include support for the K3 watchdog
+ timer (RTI module) available in the K3 generation of processors.
+
endif
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index 2b0da7cea9..85d8dbfa3f 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -24,3 +24,4 @@ obj-$(CONFIG_ITCO_WDT) += itco_wdt.o
obj-$(CONFIG_STARFIVE_WDT) += starfive_wdt.o
obj-$(CONFIG_WDAT_WDT) += wdat_wdt.o
obj-$(CONFIG_CADENCE_WATCHDOG) += cadence_wdt.o
+obj-$(CONFIG_K3_RTI_WDT) += rti_wdt.o
diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c
new file mode 100644
index 0000000000..9764bc5462
--- /dev/null
+++ b/drivers/watchdog/rti_wdt.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) Siemens AG, 2020
+ *
+ * Authors:
+ * Jan Kiszka <jan.kiszka@siemens.com>
+ *
+ * Derived from linux/drivers/watchdog/rti_wdt.c
+ */
+#include <init.h>
+#include <io.h>
+#include <of.h>
+#include <clock.h>
+#include <malloc.h>
+#include <watchdog.h>
+#include <driver.h>
+#include <linux/clk.h>
+#include <linux/math64.h>
+
+/* Timer register set definition */
+#define RTIDWDCTRL 0x90
+#define RTIDWDPRLD 0x94
+#define RTIWDSTATUS 0x98
+#define RTIWDKEY 0x9c
+#define RTIDWDCNTR 0xa0
+#define RTIWWDRXCTRL 0xa4
+#define RTIWWDSIZECTRL 0xa8
+
+#define RTIWWDRX_NMI 0xa
+
+#define RTIWWDSIZE_100P 0x5
+#define RTIWWDSIZE_50P 0x50
+
+#define WDENABLE_KEY 0xa98559da
+
+#define WDKEY_SEQ0 0xe51a
+#define WDKEY_SEQ1 0xa35c
+
+#define WDT_PRELOAD_SHIFT 13
+
+#define WDT_PRELOAD_MAX 0xfff
+
+#define DWDST BIT(1)
+
+struct rti_wdt_priv {
+ void __iomem *regs;
+ struct watchdog wdt;
+ unsigned int clk_hz;
+};
+
+static int rti_wdt_ping(struct watchdog *wdt)
+{
+ struct rti_wdt_priv *priv = container_of(wdt, struct rti_wdt_priv, wdt);
+ u64 halftime;
+
+ halftime = wdt->timeout_cur / 2 + 1;
+
+ if (!is_timeout(wdt->last_ping, halftime * SECOND))
+ return -EBUSY;
+
+ writel(WDKEY_SEQ0, priv->regs + RTIWDKEY);
+ writel(WDKEY_SEQ1, priv->regs + RTIWDKEY);
+
+ return 0;
+}
+
+static int rti_wdt_settimeout(struct watchdog *wdt, unsigned int timeout)
+{
+ struct rti_wdt_priv *priv = container_of(wdt, struct rti_wdt_priv, wdt);
+ u32 timer_margin;
+
+ if (!timeout)
+ return -ENOSYS;
+
+ if (wdt->running == WDOG_HW_RUNNING && timeout == wdt->timeout_cur)
+ return rti_wdt_ping(wdt);
+
+ if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY)
+ return -ENOSYS;
+
+ timer_margin = timeout * priv->clk_hz;
+ timer_margin >>= WDT_PRELOAD_SHIFT;
+ if (timer_margin > WDT_PRELOAD_MAX)
+ timer_margin = WDT_PRELOAD_MAX;
+
+ writel(timer_margin, priv->regs + RTIDWDPRLD);
+ writel(RTIWWDRX_NMI, priv->regs + RTIWWDRXCTRL);
+ writel(RTIWWDSIZE_50P, priv->regs + RTIWWDSIZECTRL);
+
+ readl(priv->regs + RTIWWDSIZECTRL);
+
+ writel(WDENABLE_KEY, priv->regs + RTIDWDCTRL);
+
+ return 0;
+}
+
+static unsigned int rti_wdt_get_timeleft_s(struct watchdog *wdt)
+{
+ struct rti_wdt_priv *priv = container_of(wdt, struct rti_wdt_priv, wdt);
+ u32 timer_counter;
+ u32 val;
+
+ /* if timeout has occurred then return 0 */
+ val = readl(priv->regs + RTIWDSTATUS);
+ if (val & DWDST)
+ return 0;
+
+ timer_counter = readl(priv->regs + RTIDWDCNTR);
+
+ return timer_counter / priv->clk_hz;
+}
+
+static int rti_wdt_probe(struct device *dev)
+{
+ struct rti_wdt_priv *priv;
+ struct clk *clk;
+ struct watchdog *wdt;
+ static bool one = false;
+
+ if (one)
+ return 0;
+ one = true;
+
+ priv = xzalloc(sizeof(*priv));
+
+ wdt = &priv->wdt;
+
+ priv->regs = dev_request_mem_region(dev, 0);
+ if (IS_ERR(priv->regs))
+ return -EINVAL;
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk))
+ return dev_err_probe(dev, PTR_ERR(clk), "No clock");
+
+ priv->clk_hz = clk_get_rate(clk);
+
+ /*
+ * If watchdog is running at 32k clock, it is not accurate.
+ * Adjust frequency down in this case so that it does not expire
+ * earlier than expected.
+ */
+ if (priv->clk_hz < 32768)
+ priv->clk_hz = priv->clk_hz * 9 / 10;
+
+ wdt = &priv->wdt;
+ wdt->name = "rti_wdt";
+ wdt->hwdev = dev;
+ wdt->set_timeout = rti_wdt_settimeout;
+ wdt->ping = rti_wdt_ping;
+ wdt->timeout_max = WDT_PRELOAD_MAX / (priv->clk_hz >> WDT_PRELOAD_SHIFT);
+
+ if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY) {
+ u64 heartbeat_s;
+ u32 last_ping_s;
+
+ wdt->running = WDOG_HW_RUNNING;
+
+ heartbeat_s = readl(priv->regs + RTIDWDPRLD);
+ heartbeat_s <<= WDT_PRELOAD_SHIFT;
+ do_div(heartbeat_s, priv->clk_hz);
+ wdt->timeout_cur = heartbeat_s;
+ last_ping_s = heartbeat_s - rti_wdt_get_timeleft_s(wdt) + 1;
+
+ wdt->last_ping = get_time_ns() - last_ping_s * SECOND;
+ } else {
+ wdt->running = WDOG_HW_NOT_RUNNING;
+ }
+
+ return watchdog_register(wdt);
+}
+
+static const struct of_device_id rti_wdt_of_match[] = {
+ { .compatible = "ti,j7-rti-wdt", },
+ { /* sentinel */ }
+};
+
+static struct driver rti_wdt_driver = {
+ .name = "rti-wdt",
+ .probe = rti_wdt_probe,
+ .of_match_table = rti_wdt_of_match,
+};
+device_platform_driver(rti_wdt_driver);
--
2.39.5
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: [PATCH 0/3] watchdog: Add TI rti_wdg support
2024-11-12 9:16 [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
` (2 preceding siblings ...)
2024-11-12 9:16 ` [PATCH 3/3] watchdog: add rti_wdt support Sascha Hauer
@ 2024-11-13 11:33 ` Sascha Hauer
3 siblings, 0 replies; 5+ messages in thread
From: Sascha Hauer @ 2024-11-13 11:33 UTC (permalink / raw)
To: open list:BAREBOX, Sascha Hauer
On Tue, 12 Nov 2024 10:16:03 +0100, Sascha Hauer wrote:
> This series adds support for the rti_wdg found on TI K3 SoCs. The
> timeout for this watchdog cannot be reconfigured once started which
> doesn't fit well into our current watchdog_set_timeout() API which
> both pings the watchdog and starts it. For this reason this series
> introduces an optional watchdog_ping() function which can be used
> for this type of watchdog.
>
> [...]
Applied, thanks!
[1/3] watchdog: cleanup timeout_cur parameter
https://git.pengutronix.de/cgit/barebox/commit/?id=d80f51ba7e68 (link may not be stable)
[2/3] watchdog: add watchdog ping support
https://git.pengutronix.de/cgit/barebox/commit/?id=77547d6b7772 (link may not be stable)
[3/3] watchdog: add rti_wdt support
https://git.pengutronix.de/cgit/barebox/commit/?id=adad2dfd6659 (link may not be stable)
Best regards,
--
Sascha Hauer <s.hauer@pengutronix.de>
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2024-11-13 11:34 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-11-12 9:16 [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
2024-11-12 9:16 ` [PATCH 1/3] watchdog: cleanup timeout_cur parameter Sascha Hauer
2024-11-12 9:16 ` [PATCH 2/3] watchdog: add watchdog ping support Sascha Hauer
2024-11-12 9:16 ` [PATCH 3/3] watchdog: add rti_wdt support Sascha Hauer
2024-11-13 11:33 ` [PATCH 0/3] watchdog: Add TI rti_wdg support Sascha Hauer
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox