From 2df151a0ca79664e5fd7cae638d6aec12606f1ba Mon Sep 17 00:00:00 2001 From: Chun-Chieh Li Date: Tue, 16 Dec 2025 14:58:34 +0800 Subject: [PATCH] Nuvoton: M487: Fix reset loop with target.wdt-reset-workaround We may trap in DPD/SPD wake-up reset loop when multi-level bootloaders (e.g. LDROM and MCUBoot) and application all or partial integrate this workaround. To avoid this, the wake-up flag CLK_PMUSTS_TMRWK_Msk is used to guard from duplicate wake-up reset setups and the clear-up of this flag is delayed to hal_watchdog_init, which will be invoked via Mbed Watchdog API. This approach works based on the assumptions: 1. Only application will set up WDT. LDROM and MCUBoot won't. 2. WDT setup is done via Mbed Watchdog API, not direct WDT control. --- .../TARGET_M480/mbed_overrides.c | 71 ++++++------------- .../TARGET_NUVOTON/TARGET_M480/watchdog_api.c | 7 ++ 2 files changed, 30 insertions(+), 48 deletions(-) diff --git a/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c b/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c index ca69b8deb42..242c79d5fdc 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/mbed_overrides.c @@ -83,9 +83,6 @@ void mbed_sdk_init(void) /* User can use SystemCoreClockUpdate() to calculate SystemCoreClock. */ SystemCoreClockUpdate(); - /* Lock protected registers */ - SYS_LockReg(); - #if MBED_CONF_TARGET_WDT_RESET_WORKAROUND /* Work around H/W limit with WDT reset from PD * @@ -111,9 +108,11 @@ void mbed_sdk_init(void) * and WDT wake-up from PD will. So don't rely on SYS_IS_WDT_RST() to * determine to use or not the workaround. * - * NOTE: To avoid the workaround duplicate run by bootloader (e.g. MCUBoot) - * and application and then crash when bootloader is enabled, the workaround - * is applied only when any H/W reset flag (SYS.RSTSTS) raised. + * NOTE: We may trap in DPD/SPD wake-up reset loop when multi-level + * bootloaders (e.g. LDROM and MCUBoot) and application all integrate + * this workaround. To avoid this, the wake-up flag CLK_PMUSTS_TMRWK_Msk + * is used to guard from duplicate wake-up reset setups by delaying + * its clean-up to hal_watchdog_init (watchdog_api.c). * * NOTE: The workaround will change SYS.RSTSTS and DEVICE_RESET_REASON won't * work as expected. Don't enable MBED_CONF_TARGET_WDT_RESET_WORKAROUND and @@ -133,54 +132,30 @@ MBED_CONF_TARGET_WDT_RESET_WORKAROUND and DEVICE_RESET_REASON \ at the same time." #endif -#define ALL_RESET_FLAGS \ - (SYS_RSTSTS_PORF_Msk | \ - SYS_RSTSTS_PINRF_Msk | \ - SYS_RSTSTS_WDTRF_Msk | \ - SYS_RSTSTS_LVRF_Msk | \ - SYS_RSTSTS_BODRF_Msk | \ - SYS_RSTSTS_SYSRF_Msk | \ - SYS_RSTSTS_CPURF_Msk | \ - SYS_RSTSTS_CPULKRF_Msk) - - /* Apply the workaround only when any H/W reset flag is raised. For - * bootloader enabled application, the workaround must apply either - * by bootloader or by application, but not both. - */ - if (SYS->RSTSTS & ALL_RESET_FLAGS) { - /* Re-unlock protected clock setting */ - SYS_UnlockReg(); - - /* Without this, bootloader enabled application will trap in - * loop of wake-up timer wake-up reset armed here by bootloader - * and application alternately, if both integrate this piece - * of code. - */ - SYS_CLEAR_RST_SOURCE(ALL_RESET_FLAGS); - - /* Release I/O hold status */ - CLK->IOPDCTL = 1; - - if (!(CLK->PMUSTS & CLK_PMUSTS_TMRWK_Msk)) { - /* Set up DPD/SPD power down mode */ - CLK_SetPowerDownMode(CLK_PMUCTL_PDMSEL_SPD0); + /* Release I/O hold status */ + CLK->IOPDCTL = 1; - /* Enable wake-up timer */ - CLK_SET_WKTMR_INTERVAL(CLK_PMUCTL_WKTMRIS_256); - CLK_ENABLE_WKTMR(); + if (!(CLK->PMUSTS & CLK_PMUSTS_TMRWK_Msk)) { + /* Set up DPD/SPD power down mode */ + CLK_SetPowerDownMode(CLK_PMUCTL_PDMSEL_SPD0); - CLK_PowerDown(); + /* Enable wake-up timer */ + CLK_SET_WKTMR_INTERVAL(CLK_PMUCTL_WKTMRIS_256); + CLK_ENABLE_WKTMR(); - MBED_UNREACHABLE; - } + CLK_PowerDown(); - /* Clean previous wake-up flag */ - CLK->PMUSTS |= (CLK_PMUSTS_CLRWK_Msk | CLK_PMUSTS_TMRWK_Msk); - - /* Lock protected registers */ - SYS_LockReg(); + MBED_UNREACHABLE; } + + /* Don't clean wake-up flag here (see above) */ + #if 0 + CLK->PMUSTS |= (CLK_PMUSTS_CLRWK_Msk | CLK_PMUSTS_TMRWK_Msk); + #endif #endif + + /* Lock protected registers */ + SYS_LockReg(); } // Override mbed_mac_address of mbed_interface.c to provide ethernet devices with a semi-unique MAC address diff --git a/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c b/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c index 4157e30940e..c438d247018 100644 --- a/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c +++ b/targets/TARGET_NUVOTON/TARGET_M480/watchdog_api.c @@ -88,6 +88,13 @@ watchdog_status_t hal_watchdog_init(const watchdog_config_t *config) SYS_UnlockReg(); + /* See mbed_sdk_init (mbed_override.c) on workaround to + * H/W limit with WDT reset from PD. + */ +#if MBED_CONF_TARGET_WDT_RESET_WORKAROUND + CLK->PMUSTS |= (CLK_PMUSTS_CLRWK_Msk | CLK_PMUSTS_TMRWK_Msk); +#endif + /* Enable IP module clock */ CLK_EnableModuleClock(WDT_MODULE);