From 521e97fd135cfaeb199e1de0f87aa2e45b4aa804 Mon Sep 17 00:00:00 2001 From: Randall Spangler Date: Fri, 10 Aug 2012 13:15:15 -0700 Subject: [PATCH] Clean up EC hibernate logic system_hibernate(0, 0) now hibernates until a wake pin assert, with no RTC wake. BUG=none TEST=manual command -> expected reset flags from 'sysinfo' 1. reboot -> soft 2. reboot hard -> power-on hard 3. hibernate (and press power button) -> power-on wake-pin 4. hibernate 3 (and wait for timeout) -> power-on rtc-alarm 5. hibernate 10 (and press power button before 10 sec) -> power-on wake-pin hibdelay 10 then shut system down and run on battery 10 sec later, system should hibernate. Change-Id: I399413d265f6fcf808adf9ed1db7b812a1b12fc2 Signed-off-by: Randall Spangler Reviewed-on: https://gerrit.chromium.org/gerrit/29923 Reviewed-by: Vic Yang --- chip/lm4/system.c | 29 ++++++++++++++++++----------- common/system_common.c | 15 ++++++++------- common/x86_power.c | 7 ++++--- include/system.h | 20 +++++++++++++++----- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/chip/lm4/system.c b/chip/lm4/system.c index 83e6cbaefe..6046f15d4c 100644 --- a/chip/lm4/system.c +++ b/chip/lm4/system.c @@ -210,13 +210,26 @@ void system_set_rtc(uint32_t seconds) * * @param seconds Number of seconds to sleep before RTC alarm * @param microseconds Number of microseconds to sleep before RTC alarm - * @param flags Hibernate wake flags + * @param flags Additional hibernate wake flags */ static void hibernate(uint32_t seconds, uint32_t microseconds, uint32_t flags) { uint32_t rtc, rtcss; uint32_t hibctl; + /* Set up wake reasons and hibernate flags */ + hibctl = LM4_HIBERNATE_HIBCTL | LM4_HIBCTL_PINWEN; + flags |= HIBDATA_WAKE_PIN; + + if (seconds || microseconds) { + hibctl |= LM4_HIBCTL_RTCWEN; + flags |= HIBDATA_WAKE_RTC; + } else { + hibctl &= ~LM4_HIBCTL_RTCWEN; + } + wait_for_hibctl_wc(); + LM4_HIBERNATE_HIBCTL = hibctl; + /* Store hibernate flags */ hibdata_write(HIBDATA_INDEX_WAKE, flags); @@ -224,10 +237,6 @@ static void hibernate(uint32_t seconds, uint32_t microseconds, uint32_t flags) wait_for_hibctl_wc(); LM4_HIBERNATE_HIBIC = LM4_HIBERNATE_HIBRIS; - /* TODO: PRESERVE RESET FLAGS */ - - /* TODO: If sleeping forever, only wake on wake pin. */ - /* Add expected overhead for hibernate register writes */ microseconds += HIB_WAIT_USEC * 4; @@ -254,17 +263,15 @@ static void hibernate(uint32_t seconds, uint32_t microseconds, uint32_t flags) wait_for_hibctl_wc(); LM4_HIBERNATE_HIBRTCSS = rtcss << 16; - /* Go to hibernation and wake on RTC match or WAKE pin */ - hibctl = (LM4_HIBERNATE_HIBCTL | LM4_HIBCTL_RTCWEN | - LM4_HIBCTL_PINWEN | LM4_HIBCTL_HIBREQ); wait_for_hibctl_wc(); - __enter_hibernate(hibctl); + __enter_hibernate(hibctl | LM4_HIBCTL_HIBREQ); } - void system_hibernate(uint32_t seconds, uint32_t microseconds) { - hibernate(seconds, microseconds, HIBDATA_WAKE_RTC | HIBDATA_WAKE_PIN); + /* Flush console before hibernating */ + cflush(); + hibernate(seconds, microseconds, 0); } int system_pre_init(void) diff --git a/common/system_common.c b/common/system_common.c index 9f62e39f64..00b754c037 100644 --- a/common/system_common.c +++ b/common/system_common.c @@ -607,24 +607,25 @@ DECLARE_CONSOLE_COMMAND(scratchpad, command_scratchpad, static int command_hibernate(int argc, char **argv) { - int seconds; + int seconds = 0; int microseconds = 0; - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - seconds = strtoi(argv[1], NULL, 0); + if (argc >= 2) + seconds = strtoi(argv[1], NULL, 0); if (argc >= 3) microseconds = strtoi(argv[2], NULL, 0); - ccprintf("Hibernating for %d.%06d s\n", seconds, microseconds); - cflush(); + if (seconds || microseconds) + ccprintf("Hibernating for %d.%06d s\n", seconds, microseconds); + else + ccprintf("Hibernating until wake pin asserted.\n"); system_hibernate(seconds, microseconds); return EC_SUCCESS; } DECLARE_CONSOLE_COMMAND(hibernate, command_hibernate, - "sec [usec]", + "[sec] [usec]", "Hibernate the EC", NULL); diff --git a/common/x86_power.c b/common/x86_power.c index 655826418b..567af54f77 100644 --- a/common/x86_power.c +++ b/common/x86_power.c @@ -444,9 +444,10 @@ void x86_power_task(void) hibernate_delay * 1000000ull; time_now = get_time().val; if (time_now > target_time) { - /* Time's up. Hibernate as long as - * possible. */ - system_hibernate(0xffffffff, 0); + /* Time's up. Hibernate until wake pin + * asserted. */ + CPRINTF("[%T x86 hibernating]\n"); + system_hibernate(0, 0); } else { /* Wait for a message */ diff --git a/include/system.h b/include/system.h index d1975c9fed..c11e89814d 100644 --- a/include/system.h +++ b/include/system.h @@ -169,11 +169,21 @@ const char *system_get_chip_vendor(void); const char *system_get_chip_name(void); const char *system_get_chip_revision(void); -/* TODO: request sleep. How do we want to handle transitioning - * to/from low-power states? */ - -/* Put the EC in hibernate (lowest EC power state) for the specified - * duration. Note that this is NOT the same as chipset S4/hibernate. */ +/** + * Put the EC in hibernate (lowest EC power state). + * + * @param seconds Number of seconds to hibernate. + * @param microseconds Number of microseconds to hibernate. + * + * The EC will hibernate until the wake pin is asserted. If seconds and/or + * microseconds is non-zero, the EC will also automatically wake after that + * period. If both are zero, the EC will only wake on a wake pin assert. Very + * short hibernation delays do not work well; if non-zero, the delays must be + * at least SYSTEM_HIB_MINIMUM_DURATION. + * + * Note although the name is similar, EC hibernate is NOT the same as chipset + * S4/hibernate. + */ void system_hibernate(uint32_t seconds, uint32_t microseconds); /* Minimum duration to get proper hibernation */