CI: https://dev.azure.com/sr0718/u-boot/_build/results?buildId=395&view=results

- watchdog for STM32MP family updates (Antonio, Clément and Patrice)
This commit is contained in:
Tom Rini 2025-07-30 07:53:46 -06:00
commit bb708e8249
11 changed files with 75 additions and 0 deletions

View File

@ -89,6 +89,7 @@ CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_SYSRESET_SYSCON=y CONFIG_SYSRESET_SYSCON=y
CONFIG_WATCHDOG_AUTOSTART=y
CONFIG_WDT=y CONFIG_WDT=y
CONFIG_WDT_STM32MP=y CONFIG_WDT_STM32MP=y
# CONFIG_BINMAN_FDT is not set # CONFIG_BINMAN_FDT is not set

View File

@ -89,6 +89,7 @@ CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_SYSRESET_SYSCON=y CONFIG_SYSRESET_SYSCON=y
CONFIG_WATCHDOG_AUTOSTART=y
CONFIG_WDT=y CONFIG_WDT=y
CONFIG_WDT_STM32MP=y CONFIG_WDT_STM32MP=y
# CONFIG_BINMAN_FDT is not set # CONFIG_BINMAN_FDT is not set

View File

@ -89,6 +89,7 @@ CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_SYSRESET_SYSCON=y CONFIG_SYSRESET_SYSCON=y
CONFIG_WATCHDOG_AUTOSTART=y
CONFIG_WDT=y CONFIG_WDT=y
CONFIG_WDT_STM32MP=y CONFIG_WDT_STM32MP=y
# CONFIG_BINMAN_FDT is not set # CONFIG_BINMAN_FDT is not set

View File

@ -89,6 +89,7 @@ CONFIG_DM_RTC=y
CONFIG_RTC_STM32=y CONFIG_RTC_STM32=y
CONFIG_SERIAL_RX_BUFFER=y CONFIG_SERIAL_RX_BUFFER=y
CONFIG_SYSRESET_SYSCON=y CONFIG_SYSRESET_SYSCON=y
CONFIG_WATCHDOG_AUTOSTART=y
CONFIG_WDT=y CONFIG_WDT=y
CONFIG_WDT_STM32MP=y CONFIG_WDT_STM32MP=y
# CONFIG_BINMAN_FDT is not set # CONFIG_BINMAN_FDT is not set

View File

@ -191,6 +191,7 @@ CONFIG_SPLASH_SCREEN_ALIGN=y
CONFIG_BMP_16BPP=y CONFIG_BMP_16BPP=y
CONFIG_BMP_24BPP=y CONFIG_BMP_24BPP=y
CONFIG_BMP_32BPP=y CONFIG_BMP_32BPP=y
CONFIG_WATCHDOG_AUTOSTART=y
CONFIG_WDT=y CONFIG_WDT=y
CONFIG_WDT_STM32MP=y CONFIG_WDT_STM32MP=y
# CONFIG_BINMAN_FDT is not set # CONFIG_BINMAN_FDT is not set

View File

@ -76,3 +76,4 @@ CONFIG_PREBOOT="run dh_preboot"
CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000
CONFIG_TARGET_DH_STM32MP1_PDK2=y CONFIG_TARGET_DH_STM32MP1_PDK2=y
CONFIG_USE_SERVERIP=y CONFIG_USE_SERVERIP=y
CONFIG_WATCHDOG_AUTOSTART=y

View File

@ -15,6 +15,7 @@ config WATCHDOG_AUTOSTART
bool "Automatically start watchdog timer" bool "Automatically start watchdog timer"
depends on WDT depends on WDT
default n if ARCH_SUNXI default n if ARCH_SUNXI
default n if ARCH_STM32MP
default y default y
help help
Automatically start watchdog timer and start servicing it during Automatically start watchdog timer and start servicing it during

View File

@ -46,6 +46,8 @@ static int smcwd_call(struct udevice *dev, enum smcwd_call call,
return -ENODEV; return -ENODEV;
if (res->a0 == PSCI_RET_INVALID_PARAMS) if (res->a0 == PSCI_RET_INVALID_PARAMS)
return -EINVAL; return -EINVAL;
if (res->a0 == PSCI_RET_DISABLED)
return -ENODATA;
if (res->a0 != PSCI_RET_SUCCESS) if (res->a0 != PSCI_RET_SUCCESS)
return -EIO; return -EIO;
@ -99,6 +101,21 @@ static int smcwd_probe(struct udevice *dev)
priv->min_timeout = res.a1; priv->min_timeout = res.a1;
priv->max_timeout = res.a2; priv->max_timeout = res.a2;
/* If already started, then force u-boot to use it */
err = smcwd_call(dev, SMCWD_GET_TIMELEFT, 0, NULL);
switch (err) {
case 0:
dev_dbg(dev, "Already started\n");
wdt_set_force_autostart(dev);
break;
case -ENODATA:
dev_dbg(dev, "Not already started\n");
break;
default:
/* Optional SMCWD_GET_TIMELEFT not implemented */
break;
}
return 0; return 0;
} }

View File

@ -21,11 +21,13 @@
#define IWDG_PR 0x04 /* Prescaler Register */ #define IWDG_PR 0x04 /* Prescaler Register */
#define IWDG_RLR 0x08 /* ReLoad Register */ #define IWDG_RLR 0x08 /* ReLoad Register */
#define IWDG_SR 0x0C /* Status Register */ #define IWDG_SR 0x0C /* Status Register */
#define IWDG_VERR 0x3F4 /* Version Register */
/* IWDG_KR register bit mask */ /* IWDG_KR register bit mask */
#define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */ #define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */
#define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */ #define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */
#define KR_KEY_EWA 0x5555 /* Write access enable */ #define KR_KEY_EWA 0x5555 /* Write access enable */
#define KR_KEY_DWA 0x0000 /* Write access disable*/
/* IWDG_PR register bit values */ /* IWDG_PR register bit values */
#define PR_256 0x06 /* Prescaler set to 256 */ #define PR_256 0x06 /* Prescaler set to 256 */
@ -36,10 +38,17 @@
/* IWDG_SR register bit values */ /* IWDG_SR register bit values */
#define SR_PVU BIT(0) /* Watchdog prescaler value update */ #define SR_PVU BIT(0) /* Watchdog prescaler value update */
#define SR_RVU BIT(1) /* Watchdog counter reload value update */ #define SR_RVU BIT(1) /* Watchdog counter reload value update */
#define SR_ONF BIT(8) /* Watchdog enable status bit */
/* IWDG Compatibility */
#define ONF_MIN_VER 0x31
#define TIMEOUT_US 10000
struct stm32mp_wdt_priv { struct stm32mp_wdt_priv {
fdt_addr_t base; /* registers addr in physical memory */ fdt_addr_t base; /* registers addr in physical memory */
unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */
unsigned int hw_version; /* Peripheral version */
}; };
static int stm32mp_wdt_reset(struct udevice *dev) static int stm32mp_wdt_reset(struct udevice *dev)
@ -90,6 +99,7 @@ static int stm32mp_wdt_start(struct udevice *dev, u64 timeout_ms, ulong flags)
static int stm32mp_wdt_probe(struct udevice *dev) static int stm32mp_wdt_probe(struct udevice *dev)
{ {
struct stm32mp_wdt_priv *priv = dev_get_priv(dev); struct stm32mp_wdt_priv *priv = dev_get_priv(dev);
u32 rlr, sr;
struct clk clk; struct clk clk;
int ret; int ret;
@ -115,6 +125,29 @@ static int stm32mp_wdt_probe(struct udevice *dev)
priv->wdt_clk_rate = clk_get_rate(&clk); priv->wdt_clk_rate = clk_get_rate(&clk);
priv->hw_version = readl(priv->base + IWDG_VERR);
if (priv->hw_version >= ONF_MIN_VER) {
if (readl(priv->base + IWDG_SR) & SR_ONF)
wdt_set_force_autostart(dev);
} else {
/*
* Workaround for old versions without IWDG_SR_ONF bit:
* - write in IWDG_RLR_OFFSET
* - wait for sync
* - if sync succeeds, then iwdg is running
*/
writel(KR_KEY_EWA, priv->base + IWDG_KR);
rlr = readl(priv->base + IWDG_RLR);
writel(rlr, priv->base + IWDG_RLR);
ret = readl_poll_timeout(priv->base + IWDG_SR, sr, sr & SR_RVU,
TIMEOUT_US);
if (!ret)
wdt_set_force_autostart(dev);
writel(KR_KEY_DWA, priv->base + IWDG_KR);
}
dev_dbg(dev, "IWDG init done\n"); dev_dbg(dev, "IWDG init done\n");
return 0; return 0;

View File

@ -46,6 +46,15 @@ struct wdt_priv {
struct cyclic_info cyclic; struct cyclic_info cyclic;
}; };
int wdt_set_force_autostart(struct udevice *dev)
{
struct wdt_priv *priv = dev_get_uclass_priv(dev);
priv->autostart = true;
return 0;
}
static void wdt_cyclic(struct cyclic_info *c) static void wdt_cyclic(struct cyclic_info *c)
{ {
struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic); struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic);

View File

@ -18,6 +18,15 @@ struct udevice;
* which typically include placing the system in a safe, known state. * which typically include placing the system in a safe, known state.
*/ */
/*
* Force watchdog start during init. Called by driver's probe when the watchdog
* is detected as already started.
*
* @dev: WDT Device
* @return: 0 if OK, -ve on error
*/
int wdt_set_force_autostart(struct udevice *dev);
/* /*
* Start the timer * Start the timer
* *