diff options
-rw-r--r-- | configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig | 1 | ||||
-rw-r--r-- | configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig | 1 | ||||
-rw-r--r-- | configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig | 1 | ||||
-rw-r--r-- | configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig | 1 | ||||
-rw-r--r-- | configs/stm32mp15_basic_defconfig | 1 | ||||
-rw-r--r-- | configs/stm32mp15_dhsom.config | 1 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 1 | ||||
-rw-r--r-- | drivers/watchdog/arm_smc_wdt.c | 17 | ||||
-rw-r--r-- | drivers/watchdog/stm32mp_wdt.c | 33 | ||||
-rw-r--r-- | drivers/watchdog/wdt-uclass.c | 9 | ||||
-rw-r--r-- | include/wdt.h | 9 |
11 files changed, 75 insertions, 0 deletions
diff --git a/configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig b/configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig index 2e86abac801..2c71d36dec0 100644 --- a/configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig +++ b/configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig @@ -89,6 +89,7 @@ CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SYSRESET_SYSCON=y +CONFIG_WATCHDOG_AUTOSTART=y CONFIG_WDT=y CONFIG_WDT_STM32MP=y # CONFIG_BINMAN_FDT is not set diff --git a/configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig b/configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig index b800b4c4073..69e9ea4b0c7 100644 --- a/configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig +++ b/configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig @@ -89,6 +89,7 @@ CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SYSRESET_SYSCON=y +CONFIG_WATCHDOG_AUTOSTART=y CONFIG_WDT=y CONFIG_WDT_STM32MP=y # CONFIG_BINMAN_FDT is not set diff --git a/configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig b/configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig index 870e17e451a..ea584f5f794 100644 --- a/configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig +++ b/configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig @@ -89,6 +89,7 @@ CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SYSRESET_SYSCON=y +CONFIG_WATCHDOG_AUTOSTART=y CONFIG_WDT=y CONFIG_WDT_STM32MP=y # CONFIG_BINMAN_FDT is not set diff --git a/configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig b/configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig index 88ee89aa13a..5b12980f0a4 100644 --- a/configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig +++ b/configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig @@ -89,6 +89,7 @@ CONFIG_DM_RTC=y CONFIG_RTC_STM32=y CONFIG_SERIAL_RX_BUFFER=y CONFIG_SYSRESET_SYSCON=y +CONFIG_WATCHDOG_AUTOSTART=y CONFIG_WDT=y CONFIG_WDT_STM32MP=y # CONFIG_BINMAN_FDT is not set diff --git a/configs/stm32mp15_basic_defconfig b/configs/stm32mp15_basic_defconfig index 4c8ad87e72b..79593cce9fe 100644 --- a/configs/stm32mp15_basic_defconfig +++ b/configs/stm32mp15_basic_defconfig @@ -191,6 +191,7 @@ CONFIG_SPLASH_SCREEN_ALIGN=y CONFIG_BMP_16BPP=y CONFIG_BMP_24BPP=y CONFIG_BMP_32BPP=y +CONFIG_WATCHDOG_AUTOSTART=y CONFIG_WDT=y CONFIG_WDT_STM32MP=y # CONFIG_BINMAN_FDT is not set diff --git a/configs/stm32mp15_dhsom.config b/configs/stm32mp15_dhsom.config index c84116482f6..565b49584e3 100644 --- a/configs/stm32mp15_dhsom.config +++ b/configs/stm32mp15_dhsom.config @@ -76,3 +76,4 @@ CONFIG_PREBOOT="run dh_preboot" CONFIG_SYS_SPI_U_BOOT_OFFS=0x80000 CONFIG_TARGET_DH_STM32MP1_PDK2=y CONFIG_USE_SERVERIP=y +CONFIG_WATCHDOG_AUTOSTART=y diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index e9ea874d0e3..56290b32bd9 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -15,6 +15,7 @@ config WATCHDOG_AUTOSTART bool "Automatically start watchdog timer" depends on WDT default n if ARCH_SUNXI + default n if ARCH_STM32MP default y help Automatically start watchdog timer and start servicing it during diff --git a/drivers/watchdog/arm_smc_wdt.c b/drivers/watchdog/arm_smc_wdt.c index 0ea44445700..f6854aa9ac9 100644 --- a/drivers/watchdog/arm_smc_wdt.c +++ b/drivers/watchdog/arm_smc_wdt.c @@ -46,6 +46,8 @@ static int smcwd_call(struct udevice *dev, enum smcwd_call call, return -ENODEV; if (res->a0 == PSCI_RET_INVALID_PARAMS) return -EINVAL; + if (res->a0 == PSCI_RET_DISABLED) + return -ENODATA; if (res->a0 != PSCI_RET_SUCCESS) return -EIO; @@ -99,6 +101,21 @@ static int smcwd_probe(struct udevice *dev) priv->min_timeout = res.a1; 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; } diff --git a/drivers/watchdog/stm32mp_wdt.c b/drivers/watchdog/stm32mp_wdt.c index 97ab8cfe7ab..0712524b4a8 100644 --- a/drivers/watchdog/stm32mp_wdt.c +++ b/drivers/watchdog/stm32mp_wdt.c @@ -21,11 +21,13 @@ #define IWDG_PR 0x04 /* Prescaler Register */ #define IWDG_RLR 0x08 /* ReLoad Register */ #define IWDG_SR 0x0C /* Status Register */ +#define IWDG_VERR 0x3F4 /* Version Register */ /* IWDG_KR register bit mask */ #define KR_KEY_RELOAD 0xAAAA /* Reload counter enable */ #define KR_KEY_ENABLE 0xCCCC /* Peripheral enable */ #define KR_KEY_EWA 0x5555 /* Write access enable */ +#define KR_KEY_DWA 0x0000 /* Write access disable*/ /* IWDG_PR register bit values */ #define PR_256 0x06 /* Prescaler set to 256 */ @@ -36,10 +38,17 @@ /* IWDG_SR register bit values */ #define SR_PVU BIT(0) /* Watchdog prescaler 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 { fdt_addr_t base; /* registers addr in physical memory */ unsigned long wdt_clk_rate; /* Watchdog dedicated clock rate */ + unsigned int hw_version; /* Peripheral version */ }; 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) { struct stm32mp_wdt_priv *priv = dev_get_priv(dev); + u32 rlr, sr; struct clk clk; int ret; @@ -115,6 +125,29 @@ static int stm32mp_wdt_probe(struct udevice *dev) 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"); return 0; diff --git a/drivers/watchdog/wdt-uclass.c b/drivers/watchdog/wdt-uclass.c index 10be334e9ed..b32590069d9 100644 --- a/drivers/watchdog/wdt-uclass.c +++ b/drivers/watchdog/wdt-uclass.c @@ -46,6 +46,15 @@ struct wdt_priv { 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) { struct wdt_priv *priv = container_of(c, struct wdt_priv, cyclic); diff --git a/include/wdt.h b/include/wdt.h index 5026f5a6db4..1ef656585c4 100644 --- a/include/wdt.h +++ b/include/wdt.h @@ -19,6 +19,15 @@ struct udevice; */ /* + * 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 * * @dev: WDT Device |