
From: Jan Kiszka jan.kiszka@siemens.com
To avoid the need of extra boot scripting on AM65x for loading a watchdog firmware, add the required rproc init and loading logic for the first R5F core to the watchdog start handler. In case the R5F cluster is in lock-step mode, also initialize the second core. The firmware itself is embedded into U-Boot binary to ease access to it and ensure it is properly hashed in case of secure boot.
One possible firmware source is https://github.com/siemens/k3-rti-wdt.
Signed-off-by: Jan Kiszka jan.kiszka@siemens.com --- drivers/watchdog/Kconfig | 20 ++++++++++ drivers/watchdog/Makefile | 5 +++ drivers/watchdog/rti_wdt.c | 72 +++++++++++++++++++++++++++++++++++ drivers/watchdog/rti_wdt_fw.S | 20 ++++++++++ 4 files changed, 117 insertions(+) create mode 100644 drivers/watchdog/rti_wdt_fw.S
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index f0ff2612a6..1a1fddfe9f 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -209,6 +209,26 @@ config WDT_K3_RTI Say Y here if you want to include support for the K3 watchdog timer (RTI module) available in the K3 generation of processors.
+if WDT_K3_RTI + +config WDT_K3_RTI_LOAD_FW + bool "Load watchdog firmware" + depends on REMOTEPROC + help + Automatically load the specified firmware image into the MCU R5F + core 0. On the AM65x, this firmware is supposed to handle the expiry + of the watchdog timer, typically by resetting the system. + +config WDT_K3_RTI_FW_FILE + string "Watchdog firmware image file" + default "k3-rti-wdt.fw" + depends on WDT_K3_RTI_LOAD_FW + help + Firmware image to be embedded into U-Boot and loaded on watchdog + start. + +endif + config WDT_SANDBOX bool "Enable Watchdog Timer support for Sandbox" depends on SANDBOX && WDT diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile index 5c7ef593fe..5016ee4708 100644 --- a/drivers/watchdog/Makefile +++ b/drivers/watchdog/Makefile @@ -33,7 +33,12 @@ 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_K3_RTI_LOAD_FW) += rti_wdt_fw.o obj-$(CONFIG_WDT_SP805) += sp805_wdt.o obj-$(CONFIG_WDT_STM32MP) += stm32mp_wdt.o obj-$(CONFIG_WDT_TANGIER) += tangier_wdt.o obj-$(CONFIG_WDT_XILINX) += xilinx_wwdt.o + +ifeq ($(CONFIG_WDT_K3_RTI_LOAD_FW),y) +$(obj)/rti_wdt_fw.o: $(shell readlink -f $(CONFIG_WDT_K3_RTI_FW_FILE)) FORCE +endif diff --git a/drivers/watchdog/rti_wdt.c b/drivers/watchdog/rti_wdt.c index 8335b20ae8..fca743fc6c 100644 --- a/drivers/watchdog/rti_wdt.c +++ b/drivers/watchdog/rti_wdt.c @@ -11,9 +11,11 @@ #include <common.h> #include <clk.h> #include <dm.h> +#include <dm/device_compat.h> #include <power-domain.h> #include <wdt.h> #include <asm/io.h> +#include <remoteproc.h>
/* Timer register set definition */ #define RTIDWDCTRL 0x90 @@ -42,6 +44,72 @@ struct rti_wdt_priv { unsigned int clk_khz; };
+#ifdef CONFIG_WDT_K3_RTI_LOAD_FW +extern const u32 rti_wdt_fw[]; +extern const int rti_wdt_fw_size; + +static int rti_wdt_load_fw(struct udevice *dev) +{ + struct udevice *rproc_dev; + int primary_core, ret; + u32 cluster_mode; + ofnode node; + + node = ofnode_by_compatible(ofnode_null(), "ti,am654-r5fss"); + if (!ofnode_valid(node)) + goto dt_error; + + ret = ofnode_read_u32(node, "ti,cluster-mode", &cluster_mode); + if (ret) + cluster_mode = 1; + + node = ofnode_by_compatible(node, "ti,am654-r5f"); + if (!ofnode_valid(node)) + goto dt_error; + + ret = uclass_get_device_by_ofnode(UCLASS_REMOTEPROC, node, &rproc_dev); + if (ret) + return ret; + + primary_core = dev_seq(rproc_dev); + + ret = rproc_dev_init(primary_core); + if (ret) + goto fw_error; + + if (cluster_mode == 1) { + ret = rproc_dev_init(primary_core + 1); + if (ret) + goto fw_error; + } + + ret = rproc_load(primary_core, (ulong)rti_wdt_fw, + rti_wdt_fw_size); + if (ret) + goto fw_error; + + ret = rproc_start(primary_core); + if (ret) + goto fw_error; + + return 0; + +dt_error: + dev_err(dev, "No compatible firmware target processor found\n"); + return -ENODEV; + +fw_error: + dev_err(dev, "Failed to load watchdog firmware into remote processor %d\n", + primary_core); + return ret; +} +#else +static inline int rti_wdt_load_fw(struct udevice *dev) +{ + return 0; +} +#endif + static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) { struct rti_wdt_priv *priv = dev_get_priv(dev); @@ -51,6 +119,10 @@ static int rti_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags) if (readl(priv->regs + RTIDWDCTRL) == WDENABLE_KEY) return -EBUSY;
+ ret = rti_wdt_load_fw(dev); + if (ret < 0) + return ret; + timer_margin = timeout_ms * priv->clk_khz / 1000; timer_margin >>= WDT_PRELOAD_SHIFT; if (timer_margin > WDT_PRELOAD_MAX) diff --git a/drivers/watchdog/rti_wdt_fw.S b/drivers/watchdog/rti_wdt_fw.S new file mode 100644 index 0000000000..335c0b63f5 --- /dev/null +++ b/drivers/watchdog/rti_wdt_fw.S @@ -0,0 +1,20 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (c) Siemens AG, 2020 + * + * Authors: + * Jan Kiszka jan.kiszka@siemens.com + */ + +.section .rodata + +.global rti_wdt_fw +.global rti_wdt_fw_size + +rti_wdt_fw: +.align 4 +.incbin CONFIG_WDT_K3_RTI_FW_FILE +rti_wdt_fw_end: + +rti_wdt_fw_size: +.int rti_wdt_fw_end - rti_wdt_fw