diff options
-rw-r--r-- | chip/it83xx/clock.c | 8 | ||||
-rw-r--r-- | chip/it83xx/system.c | 47 |
2 files changed, 52 insertions, 3 deletions
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c index c3fc6ffbf4..7c3bf25844 100644 --- a/chip/it83xx/clock.c +++ b/chip/it83xx/clock.c @@ -488,8 +488,14 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds) * may not return at all. On those boards, power to the EC is likely * being turn off entirely. */ - if (board_hibernate_late) + if (board_hibernate_late) { + /* + * Set reset flag in case board_hibernate_late() doesn't + * return. + */ + chip_save_reset_flags(EC_RESET_FLAG_HIBERNATE); board_hibernate_late(); + } if (seconds || microseconds) { /* At least 1 ms for hibernate. */ diff --git a/chip/it83xx/system.c b/chip/it83xx/system.c index a42134e0d4..615f89de9d 100644 --- a/chip/it83xx/system.c +++ b/chip/it83xx/system.c @@ -38,6 +38,17 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds) __enter_hibernate(seconds, microseconds); } +/* Clear reset flags if it's not cleared in check_reset_cause() */ +static int delayed_clear_reset_flags; +static void clear_reset_flags(void) +{ + if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON) && + delayed_clear_reset_flags) { + chip_save_reset_flags(0); + } +} +DECLARE_HOOK(HOOK_INIT, clear_reset_flags, HOOK_PRIO_LAST); + static void check_reset_cause(void) { uint32_t flags; @@ -68,8 +79,40 @@ static void check_reset_cause(void) if (flags & (EC_RESET_FLAG_HARD | EC_RESET_FLAG_SOFT)) flags &= ~EC_RESET_FLAG_WATCHDOG; - /* Clear saved reset flags. */ - chip_save_reset_flags(0); + /* + * On power-on of some boards, H1 releases the EC from reset but then + * quickly asserts and releases the reset a second time. This means the + * EC sees 2 resets. In order to carry over some important flags (e.g. + * HIBERNATE) to the second resets, the reset flag will not be wiped if + * we know this is the first reset. + */ + if (IS_ENABLED(CONFIG_BOARD_RESET_AFTER_POWER_ON) && + (flags & EC_RESET_FLAG_POWER_ON)) { + if (flags & EC_RESET_FLAG_INITIAL_PWR) { + /* Second boot, clear the flag immediately */ + chip_save_reset_flags(0); + } else { + /* + * First boot, Keep current flags and set INITIAL_PWR + * flag. EC reset should happen soon. + * + * It's possible that H1 never trigger EC reset, or + * reset happens before this line. Both cases should be + * fine because we will have the correct flag anyway. + */ + chip_save_reset_flags(chip_read_reset_flags() | + EC_RESET_FLAG_INITIAL_PWR); + + /* + * Schedule chip_save_reset_flags(0) later. + * Wait until end of HOOK_INIT should be long enough. + */ + delayed_clear_reset_flags = 1; + } + } else { + /* Clear saved reset flags. */ + chip_save_reset_flags(0); + } system_set_reset_flags(flags); |