watchdog: rti_wdt: Add support for loading firmware

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.

The board is responsible for providing the firmware as additional
loadable via the U-Boot fit image. The driver will pick up its location
from /fit-images/k3-rti-wdt-firmware then.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
This commit is contained in:
Jan Kiszka 2021-09-18 08:17:55 +02:00 committed by Tom Rini
parent a2db09e269
commit f3efb1d106
2 changed files with 108 additions and 0 deletions

View File

@ -218,6 +218,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

View File

@ -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,88 @@ struct rti_wdt_priv {
unsigned int clk_khz;
};
#ifdef CONFIG_WDT_K3_RTI_LOAD_FW
#define RTI_WDT_FIT_PATH "/fit-images/k3-rti-wdt-firmware"
static int rti_wdt_load_fw(struct udevice *dev)
{
struct udevice *rproc_dev;
int primary_core, ret;
u32 cluster_mode;
ofnode node;
u64 rti_wdt_fw;
u32 rti_wdt_fw_size;
node = ofnode_path(RTI_WDT_FIT_PATH);
if (!ofnode_valid(node))
goto fit_error;
ret = ofnode_read_u64(node, "load", &rti_wdt_fw);
if (ret)
goto fit_error;
ret = ofnode_read_u32(node, "size", &rti_wdt_fw_size);
if (ret)
goto fit_error;
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;
fit_error:
dev_err(dev, "No loadable firmware found under %s\n", RTI_WDT_FIT_PATH);
return -ENOENT;
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 +135,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)