summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configs/stm32mp15-icore-stm32mp1-ctouch2_defconfig1
-rw-r--r--configs/stm32mp15-icore-stm32mp1-edimm2.2_defconfig1
-rw-r--r--configs/stm32mp15-microgea-stm32mp1-microdev2-of7_defconfig1
-rw-r--r--configs/stm32mp15-microgea-stm32mp1-microdev2_defconfig1
-rw-r--r--configs/stm32mp15_basic_defconfig1
-rw-r--r--configs/stm32mp15_dhsom.config1
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/arm_smc_wdt.c17
-rw-r--r--drivers/watchdog/stm32mp_wdt.c33
-rw-r--r--drivers/watchdog/wdt-uclass.c9
-rw-r--r--include/wdt.h9
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