From 9a22d8465107ee1a0b526e4caf70ca9b689b7f57 Mon Sep 17 00:00:00 2001 From: Jett Rink Date: Fri, 6 Sep 2019 11:33:48 -0600 Subject: npcx: Ensure the watchdog isn't stopped while it is invalid to do so We cannot unlock the watchdog timer within 3 watch dog ticks of touching it per the datasheet. This is actually around 100ms so we should protect against this. Note: To avoid bringing in other dependencies into the npcx_monitor_fw, the "old" method of stopping the watchdog is used (no waiting first). BRANCH=none BUG=b:140207603 TEST=eliminates cold reset issue. Change-Id: I440d36fb9aecdd6d78bae6fc4002208198a3357f Signed-off-by: Jett Rink Signed-off-by: Tim Wawrzynczak Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1842592 Reviewed-by: ML Chao --- chip/npcx/system.c | 8 ++------ chip/npcx/system_chip.h | 5 ++++- chip/npcx/watchdog.c | 28 +++++++++++++++++++++++++--- 3 files changed, 31 insertions(+), 10 deletions(-) (limited to 'chip') diff --git a/chip/npcx/system.c b/chip/npcx/system.c index e247989693..bac303afa0 100644 --- a/chip/npcx/system.c +++ b/chip/npcx/system.c @@ -44,9 +44,7 @@ void system_watchdog_reset(void) { /* Unlock & stop watchdog registers */ - NPCX_WDSDM = 0x87; - NPCX_WDSDM = 0x61; - NPCX_WDSDM = 0x63; + watchdog_stop_and_unlock(); /* Reset TWCFG */ NPCX_TWCFG = 0; @@ -493,9 +491,7 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds) CLEAR_BIT(NPCX_ITCTS(ITIM_WDG_NO), NPCX_ITCTS_ITEN); /* Unlock & stop watchdog */ - NPCX_WDSDM = 0x87; - NPCX_WDSDM = 0x61; - NPCX_WDSDM = 0x63; + watchdog_stop_and_unlock(); /* Initialize watchdog */ NPCX_TWCFG = 0; /* Select T0IN clock as watchdog prescaler clock */ diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h index 5ca686a86f..2836a1e4f7 100644 --- a/chip/npcx/system_chip.h +++ b/chip/npcx/system_chip.h @@ -30,9 +30,12 @@ enum bbram_data_index { BBRM_DATA_INDEX_PANIC_BKUP = 36, /* Panic data (index 35-63)*/ }; -/* Issue a watchdog reset*/ +/* Issue a watchdog reset */ void system_watchdog_reset(void); +/* Stops the watchdog timer and unlocks configuration. */ +void watchdog_stop_and_unlock(void); + /* * Configure the specific memory addresses in the the MPU * (Memory Protection Unit) for Nuvoton different chip series. diff --git a/chip/npcx/watchdog.c b/chip/npcx/watchdog.c index 44a980326b..233c875643 100644 --- a/chip/npcx/watchdog.c +++ b/chip/npcx/watchdog.c @@ -58,6 +58,27 @@ static uint8_t watchdog_count(void) return cnt; } +static timestamp_t last_watchdog_touch; +void watchdog_stop_and_unlock(void) +{ + /* + * Ensure we have waited at least 3 watchdog ticks since touching WD + * timer. 3 / (32768 / 1024) HZ = 93.75ms + */ + while (time_since32(last_watchdog_touch) < (100 * MSEC)) + continue; + + NPCX_WDSDM = 0x87; + NPCX_WDSDM = 0x61; + NPCX_WDSDM = 0x63; +} + +static void touch_watchdog_count(void) +{ + NPCX_WDSDM = 0x5C; + last_watchdog_touch = get_time(); +} + void __keep watchdog_check(uint32_t excep_lr, uint32_t excep_sp) { int wd_cnt; @@ -75,7 +96,8 @@ void __keep watchdog_check(uint32_t excep_lr, uint32_t excep_sp) * Touch watchdog to let UART have enough time * to print panic info */ - NPCX_WDSDM = 0x5C; + touch_watchdog_count(); + /* Print panic info */ watchdog_trace(excep_lr, excep_sp); cflush(); @@ -112,7 +134,7 @@ void watchdog_reload(void) #if 1 /* mark this for testing watchdog */ /* Touch watchdog & reset software counter */ - NPCX_WDSDM = 0x5C; + touch_watchdog_count(); #endif /* Enable watchdog interrupt */ @@ -125,7 +147,7 @@ int watchdog_init(void) #if SUPPORT_WDG /* Touch watchdog before init if it is already running */ if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WD_RUN)) - NPCX_WDSDM = 0x5C; + touch_watchdog_count(); /* Keep prescaler ratio timer0 clock to 1:1024 */ NPCX_TWCP = 0x0A; -- cgit v1.2.1