diff options
-rw-r--r-- | chip/stm32/clock-stm32f100.c | 27 | ||||
-rw-r--r-- | chip/stm32/system.c | 45 |
2 files changed, 58 insertions, 14 deletions
diff --git a/chip/stm32/clock-stm32f100.c b/chip/stm32/clock-stm32f100.c index 0dd63f456b..58c51e0a94 100644 --- a/chip/stm32/clock-stm32f100.c +++ b/chip/stm32/clock-stm32f100.c @@ -73,12 +73,12 @@ static void finalize_rtc_write(void) ; } -uint32_t set_rtc_alarm(unsigned delay_us) +uint32_t set_rtc_alarm(unsigned delay_s, unsigned delay_us) { unsigned rtc_t0, rtc_t1; rtc_t0 = ((uint32_t)STM32_RTC_CNTH << 16) | STM32_RTC_CNTL; - rtc_t1 = rtc_t0 + delay_us / US_PER_RTC_TICK; + rtc_t1 = rtc_t0 + delay_us / US_PER_RTC_TICK + delay_s * RTC_FREQ; prepare_rtc_write(); /* set RTC alarm timestamp (using the 40kHz counter ) */ @@ -168,6 +168,26 @@ static void config_hispeed_clock(void) ; } +void __enter_hibernate(uint32_t seconds, uint32_t microseconds) +{ + if (seconds || microseconds) + set_rtc_alarm(seconds, microseconds); + + /* interrupts off now */ + asm volatile("cpsid i"); + + /* enable the wake up pin */ + STM32_PWR_CSR |= (1<<8); + STM32_PWR_CR |= 0xe; + CPU_SCB_SYSCTRL |= 0x4; + /* go to Standby mode */ + asm("wfi"); + + /* we should never reach that point */ + while (1) + ; +} + #ifdef CONFIG_LOW_POWER_IDLE #ifdef CONFIG_FORCE_CONSOLE_RESUME @@ -217,7 +237,8 @@ void __idle(void) /* set deep sleep bit */ CPU_SCB_SYSCTRL |= 0x4; - rtc_t0 = set_rtc_alarm(next_delay - STOP_MODE_LATENCY); + rtc_t0 = set_rtc_alarm(0, + next_delay - STOP_MODE_LATENCY); asm("wfi"); CPU_SCB_SYSCTRL &= ~0x4; diff --git a/chip/stm32/system.c b/chip/stm32/system.c index 18e9edf044..0530624b06 100644 --- a/chip/stm32/system.c +++ b/chip/stm32/system.c @@ -57,6 +57,29 @@ static int bkpdata_write(enum bkpdata_index index, uint16_t value) return EC_SUCCESS; } +void __no_hibernate(uint32_t seconds, uint32_t microseconds) +{ + /* + * Hibernate not implemented on this platform. + * + * Until then, treat this as a request to hard-reboot. + */ + cprintf(CC_SYSTEM, "[%T hibernate not supported, so rebooting]\n"); + cflush(); + system_reset(SYSTEM_RESET_HARD); +} + +void __enter_hibernate(uint32_t seconds, uint32_t microseconds) + __attribute__((weak, alias("__no_hibernate"))); + +void system_hibernate(uint32_t seconds, uint32_t microseconds) +{ + /* Flush console before hibernating */ + cflush(); + /* chip specific standby mode */ + __enter_hibernate(seconds, microseconds); +} + static void check_reset_cause(void) { uint32_t flags = bkpdata_read(BKPDATA_INDEX_SAVED_RESET_FLAGS); @@ -98,19 +121,19 @@ static void check_reset_cause(void) if (!flags && (raw_cause & 0xfe000000)) flags |= RESET_FLAG_OTHER; - system_set_reset_flags(flags); -} - -void system_hibernate(uint32_t seconds, uint32_t microseconds) -{ /* - * TODO: implement hibernate. - * - * Until then, treat this as a request to hard-reboot. + * WORKAROUND: as we cannot de-activate the watchdog during + * long hibernation, we are woken-up once by the watchdog and + * go back to hibernate if we detect that condition, without + * watchdog initialized this time. + * The RTC deadline (if any) is already set. */ - cprintf(CC_SYSTEM, "[%T hibernate not supported, so rebooting]\n"); - cflush(); - system_reset(SYSTEM_RESET_HARD); + if ((flags & (RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) == + (RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) { + __enter_hibernate(0, 0); + } + + system_set_reset_flags(flags); } void system_pre_init(void) |