diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2013-06-07 16:36:23 -0700 |
---|---|---|
committer | ChromeBot <chrome-bot@google.com> | 2013-06-11 10:19:46 -0700 |
commit | 6fdd37c71becdad402a2368ec3b22c6dab2e6b35 (patch) | |
tree | 73ab859d42be4d79cc189eb0cae15ba7c6593ec7 | |
parent | 465b59342a026d231ffef0cfcc1efc9c8e55a4f4 (diff) | |
download | chrome-ec-6fdd37c71becdad402a2368ec3b22c6dab2e6b35.tar.gz |
stm32: add hibernate support using stm32f100 standby mode
Implement the EC hibernate mode by using the stm32f100 standby low power
mode.
As we cannot de-activate the watchdog during long hibernation, the
following workaround is implemented:
we are woken-up once by the watchdog and go back to hibernate if we
detect that condition.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=spring
BUG=chrome-os-partner:19595
TEST=on Spring with rework on the EC wake-up pin,
type "hibernate 10" and see the EC console going blank for 10s, then
booting with reset cause equals to "hibernate".
Press Alt+VolUp+H, then wake-up the system by pressing power key.
Change-Id: I28150e69817ae80314f52977ec6b62750017c2c4
Reviewed-on: https://gerrit.chromium.org/gerrit/58086
Tested-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Randall Spangler <rspangler@chromium.org>
Reviewed-by: Vic Yang <victoryang@chromium.org>
Commit-Queue: Vincent Palatin <vpalatin@chromium.org>
-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) |