On Thu, 11 May 2023 at 09:39, Patrice CHOTARD <patrice.chot...@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 <ma...@denx.de> > > --- > > Cc: Ilias Apalodimas <ilias.apalodi...@linaro.org> > > Cc: Marek Vasut <ma...@denx.de> > > Cc: Patrice Chotard <patrice.chot...@foss.st.com> > > Cc: Patrick Delaunay <patrick.delau...@foss.st.com> > > Cc: Sughosh Ganu <sughosh.g...@linaro.org> > > Cc: u-boot@lists.denx.de > > Cc: uboot-st...@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.chot...@foss.st.com> > > Thanks > Patrice
Acked-by: Ilias Apalodimas <ilias.apalodi...@linaro.org>