From 30674d8039fa833dd9c0bf7d67b06ca252086ce4 Mon Sep 17 00:00:00 2001 From: Jun Lin Date: Thu, 13 Feb 2025 16:02:19 +0800 Subject: [PATCH] drivers: watchdog: npcx: fix T0 timer reload procedure The correct procedure to reload the T0 timer is: 1. Load TWDT0 register with the new value or write 1 to RST bit in T0CSR register to load the old value. 2. Wait until RST bit in T0CSR register becomes 1. 3. Wait until RST bit in T0CSR register becomes 0. The current watchdog driver misses step 2. Fix the issue in this commit. Signed-off-by: Jun Lin --- drivers/watchdog/wdt_npcx.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/wdt_npcx.c b/drivers/watchdog/wdt_npcx.c index 24979ce88defb..c3245a50b7898 100644 --- a/drivers/watchdog/wdt_npcx.c +++ b/drivers/watchdog/wdt_npcx.c @@ -61,7 +61,8 @@ LOG_MODULE_REGISTER(wdt_npcx, CONFIG_WDT_LOG_LEVEL); #define NPCX_WDT_MIN_WND_TIME 100UL /* Timeout for reloading and restarting Timer 0. (Unit:ms) */ -#define NPCX_T0CSR_RST_TIMEOUT 2 +#define NPCX_T0CSR_RST_CLEAR_TIMEOUT 2 +#define NPCX_T0CSR_RST_SET_TIMEOUT 1 /* Timeout for stopping watchdog. (Unit:ms) */ #define NPCX_WATCHDOG_STOP_TIMEOUT 1 @@ -100,10 +101,22 @@ static inline int wdt_t0out_reload(const struct device *dev) /* Reload and restart T0 timer */ inst->T0CSR = (inst->T0CSR & ~BIT(NPCX_T0CSR_WDRST_STS)) | BIT(NPCX_T0CSR_RST); + /* + * Wait for the T0CSR_RST bit to change from 0 to 1. This transition is expected to occur + * over multiple LFCLK cycles. If a timeout occurs, we can assume that the bit has changed + * from 0 -> 1 -> 0, but the polling thread missed it because it was preempted by + * higher-priority threads. In this case, we can simply return. + */ + st = k_uptime_get(); + while (!IS_BIT_SET(inst->T0CSR, NPCX_T0CSR_RST)) { + if (k_uptime_get() - st > NPCX_T0CSR_RST_SET_TIMEOUT) { + return 0; + } + } /* Wait for timer is loaded and restart */ st = k_uptime_get(); while (IS_BIT_SET(inst->T0CSR, NPCX_T0CSR_RST)) { - if (k_uptime_get() - st > NPCX_T0CSR_RST_TIMEOUT) { + if (k_uptime_get() - st > NPCX_T0CSR_RST_CLEAR_TIMEOUT) { /* RST bit is still set? */ if (IS_BIT_SET(inst->T0CSR, NPCX_T0CSR_RST)) { LOG_ERR("Timeout: reload T0 timer!");