summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2013-11-04 12:00:24 -0800
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-02-13 16:44:08 +0000
commita7529e03addfb399b4d3b131e9e259daa201a1ae (patch)
tree1155a5a082d7d7811fabba6ebad63d0115376bfe
parent8e8102cc8993c2bec312451093da31dcc6eeb86f (diff)
downloadchrome-ec-a7529e03addfb399b4d3b131e9e259daa201a1ae.tar.gz
CHERRY-PICK: lm4: Fixed low power idle doesn't always wake up.
Temporary fix to the bug in which we miss wake events when in deep sleep with the LFIOSC (32kHz) clock and the EC is cold. This fix involves simply using a faster clock, 250kHz, when in low speed deep sleep. This fix consumes more power but solves the bug. Renamed EC console command dsleepmask to dsleep. BUG=chrome-os-partner:25661 BRANCH=none TEST=Go in to low speed deep sleep by going into either S3 or G3 and letting the EC console timeout. Then freeze-spray the EC chip. Wake up the EC via the console and make sure that the idlestats show that we have not missed a deadline. Change-Id: Ida96cd04c1af9b114270f9a2eff002e419984e7c Original-Change-Id: I4f9844f1937bc8c95cf1540502f7d8fb4cbc097e Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/175614 Reviewed-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/186268 Commit-Queue: Dave Parker <dparker@chromium.org> Tested-by: Dave Parker <dparker@chromium.org>
-rw-r--r--chip/lm4/clock.c38
-rw-r--r--include/config.h6
2 files changed, 32 insertions, 12 deletions
diff --git a/chip/lm4/clock.c b/chip/lm4/clock.c
index bbd2e503d1..1d58e59e3d 100644
--- a/chip/lm4/clock.c
+++ b/chip/lm4/clock.c
@@ -235,7 +235,7 @@ void __idle(void)
timestamp_t t0, t1, rtc_t0, rtc_t1;
int next_delay = 0;
int time_for_dsleep, margin_us;
- int use_lfiosc;
+ int use_low_speed_clock;
/* Enable the hibernate IRQ used to wake up from deep sleep */
system_enable_hib_interrupt();
@@ -300,25 +300,37 @@ void __idle(void)
}
/*
- * Determine if we should use the LFIOSC (30kHz) or the
- * PIOSC (16MHz) for the clock in deep sleep. Use the
- * LFIOSC only if the sleep mask specifies that low
+ * Determine if we should use a lower clock speed or
+ * keep the same (16MHz) clock in deep sleep. Use the
+ * lower speed only if the sleep mask specifies that low
* speed sleep is allowed, the console UART TX is not
* busy, and the console UART buffer is empty.
*/
- use_lfiosc = LOW_SPEED_DEEP_SLEEP_ALLOWED &&
+ use_low_speed_clock = LOW_SPEED_DEEP_SLEEP_ALLOWED &&
!uart_tx_in_progress() && uart_buffer_empty();
- /* Set the deep sleep clock register. */
- LM4_SYSTEM_DSLPCLKCFG = use_lfiosc ? 0x32 : 0x10;
+#ifdef CONFIG_LOW_POWER_USE_LFIOSC
+ /* Set the deep sleep clock register. Use either the
+ * normal PIOSC (16MHz) or the LFIOSC (32kHz). */
+ LM4_SYSTEM_DSLPCLKCFG = use_low_speed_clock ?
+ 0x32 : 0x10;
+#else
+ /*
+ * Set the deep sleep clock register. Use either the
+ * PIOSC with no divider (16MHz) or the PIOSC with
+ * a /64 divider (250kHz).
+ */
+ LM4_SYSTEM_DSLPCLKCFG = use_low_speed_clock ?
+ 0x1f800010 : 0x10;
+#endif
/*
- * If using low speed (LFIOSC) clock, disable console.
+ * If using low speed clock, disable console.
* This will also convert the console RX pin to a GPIO
* and set an edge interrupt to wake us from deep sleep
* if any action occurs on console.
*/
- if (use_lfiosc)
+ if (use_low_speed_clock)
uart_enter_dsleep();
/* Set deep sleep bit. */
@@ -349,7 +361,7 @@ void __idle(void)
force_time(t1);
/* If using low speed clock, re-enable the console. */
- if (use_lfiosc)
+ if (use_low_speed_clock)
uart_exit_dsleep();
/* Record time spent in deep sleep. */
@@ -357,6 +369,8 @@ void __idle(void)
/* Calculate how close we were to missing deadline */
margin_us = next_delay - (int)(rtc_t1.val - rtc_t0.val);
+ if (margin_us < 0)
+ CPRINTF("[%T overslept by %dus]\n", -margin_us);
/* Record the closest to missing a deadline. */
if (margin_us < dsleep_recovery_margin_us)
@@ -697,7 +711,7 @@ DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats,
/**
* Configure deep sleep clock settings.
*/
-static int command_dsleepmask(int argc, char **argv)
+static int command_dsleep(int argc, char **argv)
{
int v;
@@ -732,7 +746,7 @@ static int command_dsleepmask(int argc, char **argv)
return EC_SUCCESS;
}
-DECLARE_CONSOLE_COMMAND(dsleepmask, command_dsleepmask,
+DECLARE_CONSOLE_COMMAND(dsleep, command_dsleep,
"[ on | off | <timeout> sec]",
"Deep sleep clock settings:\nUse 'on' to force deep "
"sleep not to use low speed clock.\nUse 'off' to "
diff --git a/include/config.h b/include/config.h
index abe0fe5836..9d3559e9a7 100644
--- a/include/config.h
+++ b/include/config.h
@@ -407,7 +407,13 @@
*/
#define CONFIG_LID_SWITCH
+/*
+ * Low power idle options. These are disabled by default and all boards that
+ * want to use low power idle must define it. When using the LFIOSC, the low
+ * frequency clock will be used to conserve even more power when possible.
+ */
#undef CONFIG_LOW_POWER_IDLE
+#undef CONFIG_LOW_POWER_USE_LFIOSC
/* Compile support for LPC interface */
#undef CONFIG_LPC