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 00:17:08 -0700
commitb7200f19af0108c72ec6288221c9a58e7c114b41 (patch)
tree6334a2b14c3260676fb3ca6b0101f76c28bc8e70
parentab5f333b494865d4672a7e153ca4d2dc4f8bc6ef (diff)
downloadchrome-ec-b7200f19af0108c72ec6288221c9a58e7c114b41.tar.gz
stm32: add hibernate support using stm32f100 standby mode
Implement the EC hibernate mode by using the stm32f100 standby low power mode. Also add the special key combination Alt+VolUp+H to force hibernation. 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: If0fa8a38df3c75b380d1e5c0092d3396b27567c7 Reviewed-on: https://gerrit.chromium.org/gerrit/58004 Reviewed-by: Todd Broch <tbroch@chromium.org> Reviewed-by: Vic Yang <victoryang@chromium.org> Commit-Queue: Vincent Palatin <vpalatin@chromium.org> Tested-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r--chip/stm32/clock-stm32f100.c27
-rw-r--r--chip/stm32/keyboard_scan.c43
-rw-r--r--chip/stm32/system.c36
3 files changed, 85 insertions, 21 deletions
diff --git a/chip/stm32/clock-stm32f100.c b/chip/stm32/clock-stm32f100.c
index 1e99e78248..6e56c4c317 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 ) */
@@ -152,6 +152,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
@@ -201,7 +221,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/keyboard_scan.c b/chip/stm32/keyboard_scan.c
index d719bfe43b..b11b7b2ccd 100644
--- a/chip/stm32/keyboard_scan.c
+++ b/chip/stm32/keyboard_scan.c
@@ -59,14 +59,16 @@ static uint8_t scan_edge_index[KB_OUTPUTS][KB_INPUTS];
#define MASK_VALUE_REFRESH 0x04
/* Key masks and values for warm reboot combination */
-#define MASK_INDEX_KEYR 3
-#define MASK_VALUE_KEYR 0x80
#define MASK_INDEX_VOL_UP 4
#define MASK_VALUE_VOL_UP 0x01
#define MASK_INDEX_RIGHT_ALT 10
#define MASK_VALUE_RIGHT_ALT 0x01
#define MASK_INDEX_LEFT_ALT 10
#define MASK_VALUE_LEFT_ALT 0x40
+#define MASK_INDEX_KEY_R 3
+#define MASK_VALUE_KEY_R 0x80
+#define MASK_INDEX_KEY_H 6
+#define MASK_VALUE_KEY_H 0x02
struct kbc_gpio {
int num; /* logical row or column number */
@@ -249,25 +251,42 @@ void enter_polling_mode(void)
*/
static int check_runtime_keys(const uint8_t *state)
{
- int num_press;
+ int num_press = 0;
int c;
- /* Count number of key pressed */
- for (c = num_press = 0; c < KB_OUTPUTS; c++) {
+ /*
+ * All runtime key combos are (right or left ) alt + volume up + (some
+ * key NOT on the same col as alt or volume up )
+ */
+ if (state[MASK_INDEX_VOL_UP] != MASK_VALUE_VOL_UP)
+ return 0;
+ if (state[MASK_INDEX_RIGHT_ALT] != MASK_VALUE_RIGHT_ALT &&
+ state[MASK_INDEX_LEFT_ALT] != MASK_VALUE_LEFT_ALT)
+ return 0;
+
+ /*
+ * Count number of columns with keys pressed. We know two columns are
+ * pressed for volume up and alt, so if only one more key is pressed
+ * there will be exactly 3 non-zero columns.
+ */
+ for (c = 0; c < KB_OUTPUTS; c++) {
if (state[c])
- ++num_press;
+ num_press++;
}
-
- if (num_press < 3)
+ if (num_press != 3)
return 0;
- if (state[MASK_INDEX_KEYR] == MASK_VALUE_KEYR &&
- state[MASK_INDEX_VOL_UP] == MASK_VALUE_VOL_UP &&
- (state[MASK_INDEX_RIGHT_ALT] == MASK_VALUE_RIGHT_ALT ||
- state[MASK_INDEX_LEFT_ALT] == MASK_VALUE_LEFT_ALT)) {
+ /* Check individual keys */
+ if (state[MASK_INDEX_KEY_R] == MASK_VALUE_KEY_R) {
+ /* R = reboot */
+ CPRINTF("[%T KB warm reboot]\n");
keyboard_clear_state();
system_warm_reboot();
return 1;
+ } else if (state[MASK_INDEX_KEY_H] == MASK_VALUE_KEY_H) {
+ /* H = hibernate */
+ CPRINTF("[%T KB hibernate]\n");
+ system_hibernate(0, 0);
}
return 0;
diff --git a/chip/stm32/system.c b/chip/stm32/system.c
index b973a9592f..7e0c0acb0c 100644
--- a/chip/stm32/system.c
+++ b/chip/stm32/system.c
@@ -5,6 +5,7 @@
/* System module for Chrome EC : hardware specific implementation */
+#include "console.h"
#include "cpu.h"
#include "registers.h"
#include "system.h"
@@ -55,6 +56,23 @@ static int bkpdata_write(enum bkpdata_index index, uint16_t value)
return EC_SUCCESS;
}
+void __no_hibernate(uint32_t seconds, uint32_t microseconds)
+{
+ while (1)
+ /* NOT IMPLEMENTED */;
+}
+
+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);
@@ -96,13 +114,19 @@ static void check_reset_cause(void)
if (!flags && (raw_cause & 0xfe000000))
flags |= RESET_FLAG_OTHER;
- system_set_reset_flags(flags);
-}
+ /*
+ * 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.
+ */
+ if ((flags & (RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) ==
+ (RESET_FLAG_HIBERNATE | RESET_FLAG_WATCHDOG)) {
+ __enter_hibernate(0, 0);
+ }
-void system_hibernate(uint32_t seconds, uint32_t microseconds)
-{
- while (1)
- /* NOT IMPLEMENTED */;
+ system_set_reset_flags(flags);
}
void system_pre_init(void)