diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 39b25305c6..a28abf41c9 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -14,9 +14,14 @@ enum bkpdata_index { BKPDATA_INDEX_SCRATCHPAD, /* General-purpose scratchpad */ + BKPDATA_INDEX_WAKE, /* Wake reasons for hibernate */ BKPDATA_INDEX_SAVED_RESET_FLAGS,/* Saved reset flags */ }; +/* Wake reason flags for hibernate */ +#define BKPDATA_WAKE_HIBERNATE (1 << 0) /* Hibernate */ +#define BKPDATA_WAKE_HARD_RESET (1 << 1) /* Hard reset */ + /** * Read backup register at specified index. * @@ -49,11 +54,14 @@ static void check_reset_cause(void) uint32_t flags = 0; uint32_t raw_cause = STM32_RCC_CSR; uint32_t pwr_status = STM32_PWR_CSR; + uint32_t bkp_wake_flags = bkpdata_read(BKPDATA_INDEX_WAKE); /* Clear the hardware reset cause by setting the RMVF bit */ STM32_RCC_CSR |= 1 << 24; /* Clear SBF in PWR_CSR */ STM32_PWR_CR |= 1 << 3; + /* Clear hibernate wake flags */ + bkpdata_write(BKPDATA_INDEX_WAKE, 0); if (raw_cause & 0x60000000) { /* IWDG or WWDG */ @@ -69,8 +77,14 @@ static void check_reset_cause(void) if (raw_cause & 0x04000000) flags |= RESET_FLAG_RESET_PIN; - if (pwr_status & 0x00000002) - flags |= RESET_FLAG_HIBERNATE; + if (pwr_status & 0x00000002) { + /* Hibernation and waked */ + if (bkp_wake_flags & BKPDATA_WAKE_HIBERNATE) + flags |= RESET_FLAG_HIBERNATE; + /* Hibernation caused by software-triggered hard reset */ + if (bkp_wake_flags & BKPDATA_WAKE_HARD_RESET) + flags |= RESET_FLAG_HARD; + } if (!flags && (raw_cause & 0xfe000000)) flags |= RESET_FLAG_OTHER; @@ -91,8 +105,12 @@ static inline void wait_for_RTOFF(void) } -static void __enter_hibernate_stm32f100(uint32_t seconds, uint32_t milliseconds) +static void __enter_hibernate_stm32f100(uint32_t seconds, uint32_t milliseconds, + uint32_t flags) { + /* Store the hibernate flags */ + bkpdata_write(BKPDATA_INDEX_WAKE, flags); + /* Enter RTC configuration mode */ wait_for_RTOFF(); STM32_RTC_CRL |= 0x10; @@ -150,7 +168,8 @@ void system_hibernate(uint32_t seconds, uint32_t microseconds) { /* we are going to hibernate ... */ #ifdef CHIP_VARIANT_stm32f100 - __enter_hibernate_stm32f100(seconds, (microseconds + 999) / 1000); + __enter_hibernate_stm32f100(seconds, (microseconds + 999) / 1000, + BKPDATA_WAKE_HIBERNATE); #else while (1) /* NOT IMPLEMENTED */; @@ -209,8 +228,16 @@ void system_reset(int flags) else bkpdata_write(BKPDATA_INDEX_SAVED_RESET_FLAGS, 0); - /* TODO: (crosbug.com/p/7470) support hard boot; this is a soft boot. */ - CPU_NVIC_APINT = 0x05fa0004; + if (flags & SYSTEM_RESET_HARD) { +#ifdef CHIP_VARIANT_stm32f100 + /* Bounce through hibernate to trigger a hard reboot */ + __enter_hibernate_stm32f100(0, 50, BKPDATA_WAKE_HARD_RESET); +#else + /* Hard reset not supported yet. Using soft reset. */ + CPU_NVIC_APINT = 0x05fa0004; +#endif + } else + CPU_NVIC_APINT = 0x05fa0004; /* Spin and wait for reboot; should never return */ while (1)