summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2013-06-07 16:36:23 -0700
committerChromeBot <chrome-bot@google.com>2013-06-11 10:19:46 -0700
commit6fdd37c71becdad402a2368ec3b22c6dab2e6b35 (patch)
tree73ab859d42be4d79cc189eb0cae15ba7c6593ec7
parent465b59342a026d231ffef0cfcc1efc9c8e55a4f4 (diff)
downloadchrome-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.c27
-rw-r--r--chip/stm32/system.c45
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)