diff --git a/src/board/system76/common/include/board/smfi.h b/src/board/system76/common/include/board/smfi.h index 56b4a119d..8335b1c28 100644 --- a/src/board/system76/common/include/board/smfi.h +++ b/src/board/system76/common/include/board/smfi.h @@ -6,7 +6,6 @@ #include void smfi_init(void); -void smfi_watchdog(void); void smfi_event(void); void smfi_debug(uint8_t byte); diff --git a/src/board/system76/common/main.c b/src/board/system76/common/main.c index 5c9240a18..869956210 100644 --- a/src/board/system76/common/main.c +++ b/src/board/system76/common/main.c @@ -29,6 +29,7 @@ #include #include #include +#include #if CONFIG_PLATFORM_INTEL #include @@ -105,6 +106,14 @@ void main(void) { gpio_debug(); #endif + // XXX: Currently, EC upgrade process will trigger a WDT reset after it + // finishes writing the flash. + if (ec_reset_source() == RESET_SOURCE_WDT) { + ERROR("\n<<< WDT reset occurred! >>>\n\n"); + } else { + wdt_init(); + } + INFO("System76 EC board '%s', version '%s'\n", board(), version()); systick_t last_time_1ms = 0; @@ -176,6 +185,8 @@ void main(void) { fan_update_target(); } + wdt_kick(); + // Idle until next timer interrupt //PCON |= BIT(0); } diff --git a/src/board/system76/common/scratch.c b/src/board/system76/common/scratch.c index e7e9ed023..d79fd57cb 100644 --- a/src/board/system76/common/scratch.c +++ b/src/board/system76/common/scratch.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -25,8 +26,8 @@ void scratch_trampoline(void) { //TODO: Clear keyboard presses - // Start watchdog timer - smfi_watchdog(); + // Restart WDT before entry to scratch ROM + wdt_kick(); // Disable interrupts EA = 0; diff --git a/src/board/system76/common/smfi.c b/src/board/system76/common/smfi.c index 225675aa8..55e6f2b3a 100644 --- a/src/board/system76/common/smfi.c +++ b/src/board/system76/common/smfi.c @@ -337,26 +337,17 @@ static enum Result cmd_reset(void) { #endif // !defined(__SCRATCH__) - // Attempt to trigger watchdog reset - ETWCFG |= BIT(5); - EWDKEYR = 0; + wdt_trigger(); // Failed if it got this far return RES_ERR; } -// Set a watchdog timer of 10 seconds -void smfi_watchdog(void) { - ET1CNTLLR = 0xFF; - EWDCNTLLR = 0xFF; - EWDCNTLHR = 0x04; -} - void smfi_event(void) { if (smfi_cmd[SMFI_CMD_CMD]) { #if defined(__SCRATCH__) // If in scratch ROM, restart watchdog timer when command received - smfi_watchdog(); + wdt_kick(); #endif switch (smfi_cmd[SMFI_CMD_CMD]) { diff --git a/src/ec/ite/ec.c b/src/ec/ite/ec.c index 4553e97b4..a2469207f 100644 --- a/src/ec/ite/ec.c +++ b/src/ec/ite/ec.c @@ -5,7 +5,45 @@ #include #include +static enum EcResetSource ec_lsr = RESET_SOURCE_NORMAL; + +enum EcResetSource ec_reset_source(void) { + return ec_lsr; +} + +static void ec_check_reset_source(void) { + // LSR field in RSTS only reports WDT reset. + uint8_t rsts = RSTS & 0b11; + // Only write bit 0 to clear field. + RSTS |= BIT(0); + + switch (rsts) { + case 0: + case 1: + // VSTBY or WRST# + ec_lsr = RESET_SOURCE_NORMAL; + break; + case 2: + case 3: + // Internal/External WDT + ec_lsr = RESET_SOURCE_WDT; + break; + } + + // SPCTRL4 reports more reset sources. + uint8_t lsr = SPCTRL4; + // All bits are write-clear. + SPCTRL4 = 0xFF; + + if (lsr & BIT(1)) { + // PWRSW WDT + ec_lsr = RESET_SOURCE_PWRSW_TIMEOUT; + } +} + void ec_init(void) { + ec_check_reset_source(); + #if CONFIG_EC_ITE_IT8587E RSTS = (0b10U << 6) | BIT(2); #else diff --git a/src/ec/ite/ec.mk b/src/ec/ite/ec.mk index ce6b20411..8dc50f25f 100644 --- a/src/ec/ite/ec.mk +++ b/src/ec/ite/ec.mk @@ -2,6 +2,7 @@ ec-y += ec.c ec-$(CONFIG_BUS_ESPI) += espi.c +ec-y += etwd.c ec-y += gpio.c ec-y += i2c.c ec-y += intc.c diff --git a/src/ec/ite/etwd.c b/src/ec/ite/etwd.c new file mode 100644 index 000000000..e46537e47 --- /dev/null +++ b/src/ec/ite/etwd.c @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: GPL-3.0-only + +// External Timer and External Watchdog (ETWD) + +#include +#include + +enum EwtCfg { + // Lock EWTCFG register + LETWCFG = BIT(0), + // Lock ET1PS register + LETPS1 = BIT(1), + // Lock ET1CNTLx registers + LET1CNTL = BIT(2), + // Lock EWDCNTLx registers + LEWDCNTL = BIT(3), + // External WDT clock source + EWDSRC = BIT(4), + // Enable key match function to touch the WDT + EWDKEYEN = BIT(5), + // Lock ET1 and EWDT registers + LOCK_ALL = LETWCFG | LETPS1 | LET1CNTL | LEWDCNTL, +}; + +enum EtwdPrescaler { + ETWD_PRESCALER_32768_HZ = 0, + ETWD_PRESCALER_1024_HZ = 1, + ETWD_PRESCALER_32_HZ = 2, + ETWD_PRESCALER_EC_CLK = 3, // Not available for ET1PS +}; + +void wdt_init(void) { + ET1PSR = ETWD_PRESCALER_1024_HZ; + ETWCFG = EWDKEYEN | EWDSRC; + + // Start ET1 so EWDT can be started + ET1CNTLLR = 0xFF; + + // Start EWDT with timeout of 8s + // TODO: Determine time based on system performance or requirement + EWDCNTLHR = 0x20; + EWDCNTLLR = 0; + + ETWCFG |= LOCK_ALL; +} diff --git a/src/ec/ite/include/ec/ec.h b/src/ec/ite/include/ec/ec.h index 9b95a2021..9beefb781 100644 --- a/src/ec/ite/include/ec/ec.h +++ b/src/ec/ite/include/ec/ec.h @@ -3,7 +3,15 @@ #ifndef _EC_EC_H #define _EC_EC_H +// Last reset source +enum EcResetSource { + RESET_SOURCE_NORMAL, + RESET_SOURCE_WDT, + RESET_SOURCE_PWRSW_TIMEOUT, +}; + void ec_init(void); void ec_read_post_codes(void); +enum EcResetSource ec_reset_source(void); #endif // _EC_EC_H diff --git a/src/ec/ite/include/ec/etwd.h b/src/ec/ite/include/ec/etwd.h index 12eac7ce4..467d7ac17 100644 --- a/src/ec/ite/include/ec/etwd.h +++ b/src/ec/ite/include/ec/etwd.h @@ -1,15 +1,50 @@ // SPDX-License-Identifier: GPL-3.0-only -#ifndef _EC_ECWD_H -#define _EC_ECWD_H +// External Timer and External Watchdog (ETWD) + +#ifndef _EC_ETWD_H +#define _EC_ETWD_H #include volatile uint8_t __xdata __at(0x1F01) ETWCFG; volatile uint8_t __xdata __at(0x1F02) ET1PSR; +#if CONFIG_EC_ITE_IT8587E +volatile uint8_t __xdata __at(0x1F03) ET1CNTLHR; +#endif volatile uint8_t __xdata __at(0x1F04) ET1CNTLLR; +volatile uint8_t __xdata __at(0x1F05) ETWCTRL; volatile uint8_t __xdata __at(0x1F06) EWDCNTLLR; volatile uint8_t __xdata __at(0x1F07) EWDKEYR; volatile uint8_t __xdata __at(0x1F09) EWDCNTLHR; +volatile uint8_t __xdata __at(0x1F0A) ET2PSR; +volatile uint8_t __xdata __at(0x1F0B) ET2CNTLHR; +volatile uint8_t __xdata __at(0x1F0C) ET2CNTLLR; +volatile uint8_t __xdata __at(0x1F0E) ET2CNTLH2R; +#if CONFIG_EC_ITE_IT5570E || CONFIG_EC_ITE_IT5571E +volatile uint8_t __xdata __at(0x1F10) ET3PSR; +volatile uint8_t __xdata __at(0x1F11) ET3CNTLHR; +volatile uint8_t __xdata __at(0x1F12) ET3CNTLLR; +volatile uint8_t __xdata __at(0x1F13) ET3CNTLH2R; +volatile uint8_t __xdata __at(0x1F16) ET4CNTLLR; +#endif + +// When the key match function of EWD is enabled (EWTCFG[5]), writing this +// value to EWDKEY will restart the WDT. +#define WDT_KEY 0x5C + +void wdt_init(void); + +// Restart WDT +// NOTE: Must be inlined for compiling in Scratch ROM +static inline void wdt_kick(void) { + EWDKEYR = WDT_KEY; +} + +// Trigger EC reset by WDT key mismatch +// NOTE: Must be inlined for compiling in Scratch ROM +static inline void wdt_trigger(void) { + EWDKEYR = 0; +} -#endif // _EC_ECWD_H +#endif // _EC_ETWD_H diff --git a/src/ec/ite/include/ec/gctrl.h b/src/ec/ite/include/ec/gctrl.h index ee0504a42..5cdbca7f2 100644 --- a/src/ec/ite/include/ec/gctrl.h +++ b/src/ec/ite/include/ec/gctrl.h @@ -8,7 +8,11 @@ volatile uint8_t __xdata __at(0x2006) RSTS; volatile uint8_t __xdata __at(0x200A) BADRSEL; volatile uint8_t __xdata __at(0x200D) SPCTRL1; +volatile uint8_t __xdata __at(0x2012) SPCTRL2; +volatile uint8_t __xdata __at(0x201C) SPCTRL4; #if CONFIG_EC_ITE_IT5570E || CONFIG_EC_ITE_IT5571E +volatile uint8_t __xdata __at(0x200C) SPCTRL5; +volatile uint8_t __xdata __at(0x2016) SPCTRL3; volatile uint8_t __xdata __at(0x2030) P80H81HS; volatile uint8_t __xdata __at(0x2031) P80HD; volatile uint8_t __xdata __at(0x2032) P81HD;