[PATCH] ARM: stm32: Add IWDG handling into PSCI suspend code

In case the IWDG is enabled by either U-Boot or Linux, the IWDG can never be disabled again. That includes low power states, which means that if the IWDG is enabled, the SoC would reset itself after a while in suspend via the IWDG. This is not desired behavior.
It is possible to enable IWDG pre-timeout IRQ which is routed into the EXTI, and use that IRQ to wake the CPU up before the IWDG timeout is reached and reset is triggered. This pre-timeout IRQ can be used to reload the WDT and then suspend the CPU again every once in a while.
Implement this functionality for both IWDG1 and IWDG2 by reading out all the unmasked IRQs, comparing the list with currently pending IRQs in GICv3: - If any IRQ is pending and it is NOT IWDG1 or IWDG2 pre-timeout IRQ, wake up and let OS handle the IRQs - If IWDG1 or IWDG2 IRQ is pending and no other IRQ is pending, ping the respective IWDG and suspend again
This does not seem to have any adverse impact on power consumption in suspend.
Signed-off-by: Marek Vasut marex@denx.de --- Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Marek Vasut marex@denx.de Cc: Patrice Chotard patrice.chotard@foss.st.com Cc: Patrick Delaunay patrick.delaunay@foss.st.com Cc: Sughosh Ganu sughosh.ganu@linaro.org Cc: u-boot@lists.denx.de Cc: uboot-stm32@st-md-mailman.stormreply.com --- arch/arm/mach-stm32mp/include/mach/stm32.h | 2 + arch/arm/mach-stm32mp/psci.c | 66 ++++++++++++++++++++-- 2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index c85ae6a34ee..1cdc5e3b186 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -21,8 +21,10 @@ #define STM32_DBGMCU_BASE 0x50081000 #endif #define STM32_FMC2_BASE 0x58002000 +#define STM32_IWDG2_BASE 0x5A002000 #define STM32_DDRCTRL_BASE 0x5A003000 #define STM32_DDRPHYC_BASE 0x5A004000 +#define STM32_IWDG1_BASE 0x5C003000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_STGEN_BASE 0x5C008000 diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 1e69673e88b..89b093d6d89 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -161,6 +161,12 @@ #define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) #define RCC_MP_GRSTCSETR_MPUP1RST BIT(5)
+/* IWDG */ +#define IWDG_KR 0x00 +#define IWDG_KR_RELOAD_KEY 0xaaaa +#define IWDG_EWCR 0x14 +#define IWDG_EWCR_EWIC BIT(14) + #define STM32MP1_PSCI_NR_CPUS 2 #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" @@ -696,7 +702,18 @@ void __secure psci_system_suspend(u32 __always_unused function_id, u32 ep, u32 context_id) { u32 saved_mcudivr, saved_pll3cr, saved_pll4cr, saved_mssckselr; + u32 gicd_addr = stm32mp_get_gicd_base_address(); + bool iwdg1_wake = false; + bool iwdg2_wake = false; + bool other_wake = false; u32 saved_pwrctl, reg; + u32 gic_enabled[8]; + u32 irqs; + int i; + + /* Cache enable mask of all 256 SPI */ + for (i = 0; i < ARRAY_SIZE(gic_enabled); i++) + gic_enabled[i] = readl(gicd_addr + GICD_ISENABLERn + 0x4 + 4 * i);
/* Disable IO compensation */
@@ -725,11 +742,50 @@ void __secure psci_system_suspend(u32 __always_unused function_id, setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN); writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR);
- /* Zzz, enter stop mode */ - asm volatile( - "isb\n" - "dsb\n" - "wfi\n"); + for (;;) { + /* Zzz, enter stop mode */ + asm volatile( + "isb\n" + "dsb\n" + "wfi\n"); + + /* Determine the wake up source */ + for (i = 0; i < ARRAY_SIZE(gic_enabled); i++) { + irqs = readl(gicd_addr + GICR_IGROUPMODRn + 0x4 + 4 * i); + irqs &= gic_enabled[i]; + if (!irqs) + continue; + + /* Test whether IWDG pretimeout triggered the wake up. */ + if (i == 4) { /* SPI Num 128..159 */ + iwdg1_wake = !!(irqs & BIT(22)); /* SPI 150 */ + iwdg2_wake = !!(irqs & BIT(23)); /* SPI 151 */ + irqs &= ~(BIT(22) | BIT(23)); + } + + /* Test whether there is any other wake up trigger. */ + if (irqs) { + other_wake = true; + break; + } + } + + /* Other wake up triggers pending, let OS deal with all of it. */ + if (other_wake) + break; + + /* Ping IWDG1 and ACK pretimer IRQ */ + if (iwdg1_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG1_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG1_BASE + IWDG_EWCR); + } + + /* Ping IWDG2 and ACK pretimer IRQ */ + if (iwdg2_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR); + } + }
writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();

On 5/11/23 02:22, Marek Vasut wrote:
In case the IWDG is enabled by either U-Boot or Linux, the IWDG can never be disabled again. That includes low power states, which means that if the IWDG is enabled, the SoC would reset itself after a while in suspend via the IWDG. This is not desired behavior.
It is possible to enable IWDG pre-timeout IRQ which is routed into the EXTI, and use that IRQ to wake the CPU up before the IWDG timeout is reached and reset is triggered. This pre-timeout IRQ can be used to reload the WDT and then suspend the CPU again every once in a while.
Implement this functionality for both IWDG1 and IWDG2 by reading out all the unmasked IRQs, comparing the list with currently pending IRQs in GICv3:
- If any IRQ is pending and it is NOT IWDG1 or IWDG2 pre-timeout IRQ, wake up and let OS handle the IRQs
- If IWDG1 or IWDG2 IRQ is pending and no other IRQ is pending, ping the respective IWDG and suspend again
This does not seem to have any adverse impact on power consumption in suspend.
Signed-off-by: Marek Vasut marex@denx.de
Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Marek Vasut marex@denx.de Cc: Patrice Chotard patrice.chotard@foss.st.com Cc: Patrick Delaunay patrick.delaunay@foss.st.com Cc: Sughosh Ganu sughosh.ganu@linaro.org Cc: u-boot@lists.denx.de Cc: uboot-stm32@st-md-mailman.stormreply.com
arch/arm/mach-stm32mp/include/mach/stm32.h | 2 + arch/arm/mach-stm32mp/psci.c | 66 ++++++++++++++++++++-- 2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index c85ae6a34ee..1cdc5e3b186 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -21,8 +21,10 @@ #define STM32_DBGMCU_BASE 0x50081000 #endif #define STM32_FMC2_BASE 0x58002000 +#define STM32_IWDG2_BASE 0x5A002000 #define STM32_DDRCTRL_BASE 0x5A003000 #define STM32_DDRPHYC_BASE 0x5A004000 +#define STM32_IWDG1_BASE 0x5C003000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_STGEN_BASE 0x5C008000 diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 1e69673e88b..89b093d6d89 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -161,6 +161,12 @@ #define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) #define RCC_MP_GRSTCSETR_MPUP1RST BIT(5)
+/* IWDG */ +#define IWDG_KR 0x00 +#define IWDG_KR_RELOAD_KEY 0xaaaa +#define IWDG_EWCR 0x14 +#define IWDG_EWCR_EWIC BIT(14)
#define STM32MP1_PSCI_NR_CPUS 2 #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" @@ -696,7 +702,18 @@ void __secure psci_system_suspend(u32 __always_unused function_id, u32 ep, u32 context_id) { u32 saved_mcudivr, saved_pll3cr, saved_pll4cr, saved_mssckselr;
u32 gicd_addr = stm32mp_get_gicd_base_address();
bool iwdg1_wake = false;
bool iwdg2_wake = false;
bool other_wake = false; u32 saved_pwrctl, reg;
u32 gic_enabled[8];
u32 irqs;
int i;
/* Cache enable mask of all 256 SPI */
for (i = 0; i < ARRAY_SIZE(gic_enabled); i++)
gic_enabled[i] = readl(gicd_addr + GICD_ISENABLERn + 0x4 + 4 * i);
/* Disable IO compensation */
@@ -725,11 +742,50 @@ void __secure psci_system_suspend(u32 __always_unused function_id, setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN); writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR);
- /* Zzz, enter stop mode */
- asm volatile(
"isb\n"
"dsb\n"
"wfi\n");
for (;;) {
/* Zzz, enter stop mode */
asm volatile(
"isb\n"
"dsb\n"
"wfi\n");
/* Determine the wake up source */
for (i = 0; i < ARRAY_SIZE(gic_enabled); i++) {
irqs = readl(gicd_addr + GICR_IGROUPMODRn + 0x4 + 4 * i);
irqs &= gic_enabled[i];
if (!irqs)
continue;
/* Test whether IWDG pretimeout triggered the wake up. */
if (i == 4) { /* SPI Num 128..159 */
iwdg1_wake = !!(irqs & BIT(22)); /* SPI 150 */
iwdg2_wake = !!(irqs & BIT(23)); /* SPI 151 */
irqs &= ~(BIT(22) | BIT(23));
}
/* Test whether there is any other wake up trigger. */
if (irqs) {
other_wake = true;
break;
}
}
/* Other wake up triggers pending, let OS deal with all of it. */
if (other_wake)
break;
/* Ping IWDG1 and ACK pretimer IRQ */
if (iwdg1_wake) {
writel(IWDG_KR_RELOAD_KEY, STM32_IWDG1_BASE + IWDG_KR);
writel(IWDG_EWCR_EWIC, STM32_IWDG1_BASE + IWDG_EWCR);
}
/* Ping IWDG2 and ACK pretimer IRQ */
if (iwdg2_wake) {
writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR);
writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR);
}
}
writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Thanks Patrice

On Thu, 11 May 2023 at 09:39, Patrice CHOTARD patrice.chotard@foss.st.com wrote:
On 5/11/23 02:22, Marek Vasut wrote:
In case the IWDG is enabled by either U-Boot or Linux, the IWDG can never be disabled again. That includes low power states, which means that if the IWDG is enabled, the SoC would reset itself after a while in suspend via the IWDG. This is not desired behavior.
It is possible to enable IWDG pre-timeout IRQ which is routed into the EXTI, and use that IRQ to wake the CPU up before the IWDG timeout is reached and reset is triggered. This pre-timeout IRQ can be used to reload the WDT and then suspend the CPU again every once in a while.
Implement this functionality for both IWDG1 and IWDG2 by reading out all the unmasked IRQs, comparing the list with currently pending IRQs in GICv3:
- If any IRQ is pending and it is NOT IWDG1 or IWDG2 pre-timeout IRQ, wake up and let OS handle the IRQs
- If IWDG1 or IWDG2 IRQ is pending and no other IRQ is pending, ping the respective IWDG and suspend again
This does not seem to have any adverse impact on power consumption in suspend.
Signed-off-by: Marek Vasut marex@denx.de
Cc: Ilias Apalodimas ilias.apalodimas@linaro.org Cc: Marek Vasut marex@denx.de Cc: Patrice Chotard patrice.chotard@foss.st.com Cc: Patrick Delaunay patrick.delaunay@foss.st.com Cc: Sughosh Ganu sughosh.ganu@linaro.org Cc: u-boot@lists.denx.de Cc: uboot-stm32@st-md-mailman.stormreply.com
arch/arm/mach-stm32mp/include/mach/stm32.h | 2 + arch/arm/mach-stm32mp/psci.c | 66 ++++++++++++++++++++-- 2 files changed, 63 insertions(+), 5 deletions(-)
diff --git a/arch/arm/mach-stm32mp/include/mach/stm32.h b/arch/arm/mach-stm32mp/include/mach/stm32.h index c85ae6a34ee..1cdc5e3b186 100644 --- a/arch/arm/mach-stm32mp/include/mach/stm32.h +++ b/arch/arm/mach-stm32mp/include/mach/stm32.h @@ -21,8 +21,10 @@ #define STM32_DBGMCU_BASE 0x50081000 #endif #define STM32_FMC2_BASE 0x58002000 +#define STM32_IWDG2_BASE 0x5A002000 #define STM32_DDRCTRL_BASE 0x5A003000 #define STM32_DDRPHYC_BASE 0x5A004000 +#define STM32_IWDG1_BASE 0x5C003000 #define STM32_TZC_BASE 0x5C006000 #define STM32_ETZPC_BASE 0x5C007000 #define STM32_STGEN_BASE 0x5C008000 diff --git a/arch/arm/mach-stm32mp/psci.c b/arch/arm/mach-stm32mp/psci.c index 1e69673e88b..89b093d6d89 100644 --- a/arch/arm/mach-stm32mp/psci.c +++ b/arch/arm/mach-stm32mp/psci.c @@ -161,6 +161,12 @@ #define RCC_MP_GRSTCSETR_MPUP0RST BIT(4) #define RCC_MP_GRSTCSETR_MPUP1RST BIT(5)
+/* IWDG */ +#define IWDG_KR 0x00 +#define IWDG_KR_RELOAD_KEY 0xaaaa +#define IWDG_EWCR 0x14 +#define IWDG_EWCR_EWIC BIT(14)
#define STM32MP1_PSCI_NR_CPUS 2 #if STM32MP1_PSCI_NR_CPUS > CONFIG_ARMV7_PSCI_NR_CPUS #error "invalid value for CONFIG_ARMV7_PSCI_NR_CPUS" @@ -696,7 +702,18 @@ void __secure psci_system_suspend(u32 __always_unused function_id, u32 ep, u32 context_id) { u32 saved_mcudivr, saved_pll3cr, saved_pll4cr, saved_mssckselr;
u32 gicd_addr = stm32mp_get_gicd_base_address();
bool iwdg1_wake = false;
bool iwdg2_wake = false;
bool other_wake = false; u32 saved_pwrctl, reg;
u32 gic_enabled[8];
u32 irqs;
int i;
/* Cache enable mask of all 256 SPI */
for (i = 0; i < ARRAY_SIZE(gic_enabled); i++)
gic_enabled[i] = readl(gicd_addr + GICD_ISENABLERn + 0x4 + 4 * i); /* Disable IO compensation */
@@ -725,11 +742,50 @@ void __secure psci_system_suspend(u32 __always_unused function_id, setbits_le32(STM32_PWR_BASE + PWR_CR3, PWR_CR3_DDRSREN); writel(0x3, STM32_RCC_BASE + RCC_MP_SREQSETR);
/* Zzz, enter stop mode */
asm volatile(
"isb\n"
"dsb\n"
"wfi\n");
for (;;) {
/* Zzz, enter stop mode */
asm volatile(
"isb\n"
"dsb\n"
"wfi\n");
/* Determine the wake up source */
for (i = 0; i < ARRAY_SIZE(gic_enabled); i++) {
irqs = readl(gicd_addr + GICR_IGROUPMODRn + 0x4 + 4 * i);
irqs &= gic_enabled[i];
if (!irqs)
continue;
/* Test whether IWDG pretimeout triggered the wake up. */
if (i == 4) { /* SPI Num 128..159 */
iwdg1_wake = !!(irqs & BIT(22)); /* SPI 150 */
iwdg2_wake = !!(irqs & BIT(23)); /* SPI 151 */
irqs &= ~(BIT(22) | BIT(23));
}
/* Test whether there is any other wake up trigger. */
if (irqs) {
other_wake = true;
break;
}
}
/* Other wake up triggers pending, let OS deal with all of it. */
if (other_wake)
break;
/* Ping IWDG1 and ACK pretimer IRQ */
if (iwdg1_wake) {
writel(IWDG_KR_RELOAD_KEY, STM32_IWDG1_BASE + IWDG_KR);
writel(IWDG_EWCR_EWIC, STM32_IWDG1_BASE + IWDG_EWCR);
}
/* Ping IWDG2 and ACK pretimer IRQ */
if (iwdg2_wake) {
writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR);
writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR);
}
} writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
Thanks Patrice
Acked-by: Ilias Apalodimas ilias.apalodimas@linaro.org

On 5/11/23 08:39, Patrice CHOTARD wrote:
Hi,
On 5/11/23 02:22, Marek Vasut wrote:
In case the IWDG is enabled by either U-Boot or Linux, the IWDG can never be disabled again. That includes low power states, which means that if the IWDG is enabled, the SoC would reset itself after a while in suspend via the IWDG. This is not desired behavior.
It is possible to enable IWDG pre-timeout IRQ which is routed into the EXTI, and use that IRQ to wake the CPU up before the IWDG timeout is reached and reset is triggered. This pre-timeout IRQ can be used to reload the WDT and then suspend the CPU again every once in a while.
Implement this functionality for both IWDG1 and IWDG2 by reading out all the unmasked IRQs, comparing the list with currently pending IRQs in GICv3:
- If any IRQ is pending and it is NOT IWDG1 or IWDG2 pre-timeout IRQ, wake up and let OS handle the IRQs
- If IWDG1 or IWDG2 IRQ is pending and no other IRQ is pending, ping the respective IWDG and suspend again
This does not seem to have any adverse impact on power consumption in suspend.
[...]
/* Ping IWDG2 and ACK pretimer IRQ */
if (iwdg2_wake) {
writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR);
writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR);
}
}
writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
I feel like maybe I need to whack the IWDG also BEFORE entering suspend, expect a V2 shortly.
Do you think this IWDG approach is fine to keep the system from rebooting in suspend ? Or do you see any better option for the MP1 ?

Hi,
On 5/11/23 13:54, Marek Vasut wrote:
On 5/11/23 08:39, Patrice CHOTARD wrote:
Hi,
On 5/11/23 02:22, Marek Vasut wrote:
In case the IWDG is enabled by either U-Boot or Linux, the IWDG can never be disabled again. That includes low power states, which means that if the IWDG is enabled, the SoC would reset itself after a while in suspend via the IWDG. This is not desired behavior.
It is possible to enable IWDG pre-timeout IRQ which is routed into the EXTI, and use that IRQ to wake the CPU up before the IWDG timeout is reached and reset is triggered. This pre-timeout IRQ can be used to reload the WDT and then suspend the CPU again every once in a while.
Implement this functionality for both IWDG1 and IWDG2 by reading out all the unmasked IRQs, comparing the list with currently pending IRQs in GICv3:
- If any IRQ is pending and it is NOT IWDG1 or IWDG2 pre-timeout IRQ,
wake up and let OS handle the IRQs
- If IWDG1 or IWDG2 IRQ is pending and no other IRQ is pending,
ping the respective IWDG and suspend again
This does not seem to have any adverse impact on power consumption in suspend.
[...]
+ /* Ping IWDG2 and ACK pretimer IRQ */ + if (iwdg2_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR); + } + } writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
I feel like maybe I need to whack the IWDG also BEFORE entering suspend, expect a V2 shortly.
Do you think this IWDG approach is fine to keep the system from rebooting in suspend ? Or do you see any better option for the MP1 ?
I think it is fine if you want to have watchdog running in STANDBY even this patch force a wakeup.
but if IWDG 1 or 2 should be not running in STANDBY (but also for STOP) for your product,
it can be managed directly by the hardware with OTP, to freeze watchdog.
=> it is a decision for each product of the desired behavior of the IWDG in low power mode.
See Ref Manual: 48.3 IWDG implementation
Table 332. STM32MP157x IWDG features
Option bytes to control the activity in Standby mode (6)
6. Controlled via option bytes OTP_IWDG1_FZ_STANDBY and OTP_IWDG2_FZ_STANDBY, respectively, for IWDG1 and IWDG2.
and in Table17 => OTP 18 = HW2 bit 5 to 8
Regards
Patrick

On 5/12/23 15:43, Patrick DELAUNAY wrote:
Hi,
Hi,
+ /* Ping IWDG2 and ACK pretimer IRQ */ + if (iwdg2_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR); + } + } writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
I feel like maybe I need to whack the IWDG also BEFORE entering suspend, expect a V2 shortly.
Do you think this IWDG approach is fine to keep the system from rebooting in suspend ? Or do you see any better option for the MP1 ?
I think it is fine if you want to have watchdog running in STANDBY even this patch force a wakeup.
but if IWDG 1 or 2 should be not running in STANDBY (but also for STOP) for your product,
Why ?
I want the watchdog to monitor that the platform is still OK, even in suspend. Also, as far as I can tell, once the IWDG is started, it cannot be stopped, right ?
it can be managed directly by the hardware with OTP, to freeze watchdog.
=> it is a decision for each product of the desired behavior of the IWDG in low power mode.
See Ref Manual: 48.3 IWDG implementation
Table 332. STM32MP157x IWDG features
Option bytes to control the activity in Standby mode (6)
- Controlled via option bytes OTP_IWDG1_FZ_STANDBY and
OTP_IWDG2_FZ_STANDBY, respectively, for IWDG1 and IWDG2.
and in Table17 => OTP 18 = HW2 bit 5 to 8
I saw the OTP fuses, but I don't want to blow them. Or is that really the suggestion ST would provide for suspend/resume, blow the fuses ?
(I wonder, why isn't the logic of those fuses inverted then, i.e. by default stop the watchdog in suspend AND blow fuses to keep it running in suspend?)

Hi
On 5/12/23 15:55, Marek Vasut wrote:
On 5/12/23 15:43, Patrick DELAUNAY wrote:
Hi,
Hi,
+ /* Ping IWDG2 and ACK pretimer IRQ */ + if (iwdg2_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR); + } + } writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
I feel like maybe I need to whack the IWDG also BEFORE entering suspend, expect a V2 shortly.
Do you think this IWDG approach is fine to keep the system from rebooting in suspend ? Or do you see any better option for the MP1 ?
I think it is fine if you want to have watchdog running in STANDBY even this patch force a wakeup.
but if IWDG 1 or 2 should be not running in STANDBY (but also for STOP) for your product,
Why ?
I want the watchdog to monitor that the platform is still OK, even in suspend. Also, as far as I can tell, once the IWDG is started, it cannot be stopped, right ?
without change OTP (so with the default behavior)
=> yes the watchdog IWDG is running without way to stop it.
it can be managed directly by the hardware with OTP, to freeze watchdog.
=> it is a decision for each product of the desired behavior of the IWDG in low power mode.
See Ref Manual: 48.3 IWDG implementation
Table 332. STM32MP157x IWDG features
Option bytes to control the activity in Standby mode (6)
- Controlled via option bytes OTP_IWDG1_FZ_STANDBY and
OTP_IWDG2_FZ_STANDBY, respectively, for IWDG1 and IWDG2.
and in Table17 => OTP 18 = HW2 bit 5 to 8
I saw the OTP fuses, but I don't want to blow them. Or is that really the suggestion ST would provide for suspend/resume, blow the fuses ?
(I wonder, why isn't the logic of those fuses inverted then, i.e. by default stop the watchdog in suspend AND blow fuses to keep it running in suspend?)
it is a SoC design choice => the default behavior is watchdog is running in standby and stop, so you need to reload it
That imply the limit of the duration of max duration of standby to avoid reset....
and the usage of IWDG pre-timeout in this case it a good place to wakeup the SoC
and add sanity checks (check the system is still running) before to reload it.
Patrick

On 5/25/23 13:57, Patrick DELAUNAY wrote:
Hi
Hello Patrick,
+ /* Ping IWDG2 and ACK pretimer IRQ */ + if (iwdg2_wake) { + writel(IWDG_KR_RELOAD_KEY, STM32_IWDG2_BASE + IWDG_KR); + writel(IWDG_EWCR_EWIC, STM32_IWDG2_BASE + IWDG_EWCR); + } + } writel(0x3, STM32_RCC_BASE + RCC_MP_SREQCLRR); ddr_sw_self_refresh_exit();
Reviewed-by: Patrice Chotard patrice.chotard@foss.st.com
I feel like maybe I need to whack the IWDG also BEFORE entering suspend, expect a V2 shortly.
Do you think this IWDG approach is fine to keep the system from rebooting in suspend ? Or do you see any better option for the MP1 ?
I think it is fine if you want to have watchdog running in STANDBY even this patch force a wakeup.
but if IWDG 1 or 2 should be not running in STANDBY (but also for STOP) for your product,
Why ?
I want the watchdog to monitor that the platform is still OK, even in suspend. Also, as far as I can tell, once the IWDG is started, it cannot be stopped, right ?
without change OTP (so with the default behavior)
=> yes the watchdog IWDG is running without way to stop it.
ACK
it can be managed directly by the hardware with OTP, to freeze watchdog.
=> it is a decision for each product of the desired behavior of the IWDG in low power mode.
See Ref Manual: 48.3 IWDG implementation
Table 332. STM32MP157x IWDG features
Option bytes to control the activity in Standby mode (6)
- Controlled via option bytes OTP_IWDG1_FZ_STANDBY and
OTP_IWDG2_FZ_STANDBY, respectively, for IWDG1 and IWDG2.
and in Table17 => OTP 18 = HW2 bit 5 to 8
I saw the OTP fuses, but I don't want to blow them. Or is that really the suggestion ST would provide for suspend/resume, blow the fuses ?
(I wonder, why isn't the logic of those fuses inverted then, i.e. by default stop the watchdog in suspend AND blow fuses to keep it running in suspend?)
it is a SoC design choice => the default behavior is watchdog is running in standby and stop, so you need to reload it
That imply the limit of the duration of max duration of standby to avoid reset....
and the usage of IWDG pre-timeout in this case it a good place to wakeup the SoC
and add sanity checks (check the system is still running) before to reload it.
OK
participants (4)
-
Ilias Apalodimas
-
Marek Vasut
-
Patrice CHOTARD
-
Patrick DELAUNAY