summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRandall Spangler <rspangler@chromium.org>2013-10-29 14:16:40 -0700
committerchrome-internal-fetch <chrome-internal-fetch@google.com>2014-02-13 21:57:46 +0000
commit31ee166e8e1c3f18cb2fb6fc491c1d0ffd7b25f6 (patch)
treed6c80a69e823799f990a224d273aa2749d813883
parenta7529e03addfb399b4d3b131e9e259daa201a1ae (diff)
downloadchrome-ec-31ee166e8e1c3f18cb2fb6fc491c1d0ffd7b25f6.tar.gz
CHERRY-PICK: lm4: fix enabling RTC alarm
All hibernate register writes must wait for the WC bit. When we're enabling the RTC alarm, it's important to wait for the WC bit afterwards, too, or else we could go into deep sleep before the write to HIBIM is committed. Also make sure that the normal hibernate() path enables the RTC alarm if it has a timeout. This bug wasn't noticed until the low-power idle code called system_reset_rtc_alarm(), since before then HIBIM was initialized to 1 and just stayed there. BUG=chrome-os-partner:25661 BRANCH=anywhere we use low power idle (wolf/leon, too) TEST=with hacked firmware, note that HIBIM=1 just before the wfi instruction in chip/lm4/clock.c Change-Id: I6fff333ca15dfca6f25c9103a73f4c8f1cbe05ac Original-Change-Id: Ie01b106ac6a6c5894811f9a333715b22ef896f82 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/175013 Reviewed-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/186269 Tested-by: Dave Parker <dparker@chromium.org> Commit-Queue: Dave Parker <dparker@chromium.org>
-rw-r--r--chip/lm4/registers.h1
-rw-r--r--chip/lm4/system.c16
2 files changed, 16 insertions, 1 deletions
diff --git a/chip/lm4/registers.h b/chip/lm4/registers.h
index ac25724197..b87a7b55ec 100644
--- a/chip/lm4/registers.h
+++ b/chip/lm4/registers.h
@@ -194,6 +194,7 @@ static inline int lm4_fan_addr(int ch, int offset)
#define LM4_HIBCTL_RTCEN (1 << 0)
#define LM4_HIBERNATE_HIBIM REG32(0x400fc014)
#define LM4_HIBERNATE_HIBRIS REG32(0x400fc018)
+#define LM4_HIBERNATE_HIBMIS REG32(0x400fc01c)
#define LM4_HIBERNATE_HIBIC REG32(0x400fc020)
#define LM4_HIBERNATE_HIBRTCT REG32(0x400fc024)
#define LM4_HIBERNATE_HIBRTCSS REG32(0x400fc028)
diff --git a/chip/lm4/system.c b/chip/lm4/system.c
index 05f6def1bd..02586bfab1 100644
--- a/chip/lm4/system.c
+++ b/chip/lm4/system.c
@@ -190,7 +190,7 @@ void __attribute__((section(".iram.text"))) __enter_hibernate(int hibctl)
*
* @return the real-time clock seconds value.
*/
-static uint32_t system_get_rtc_sec_subsec(uint32_t *ss_ptr)
+uint32_t system_get_rtc_sec_subsec(uint32_t *ss_ptr)
{
uint32_t rtc, rtc2;
uint32_t rtcss, rtcss2;
@@ -289,6 +289,14 @@ void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds)
/* Enable RTC interrupt on match */
wait_for_hibctl_wc();
LM4_HIBERNATE_HIBIM = 1;
+
+ /*
+ * Wait for the write to commit. This ensures that the RTC interrupt
+ * actually gets enabled. This is important if we're about to switch
+ * the system to the 30 kHz oscillator, which might prevent the write
+ * from comitting.
+ */
+ wait_for_hibctl_wc();
}
/**
@@ -297,9 +305,11 @@ void system_set_rtc_alarm(uint32_t seconds, uint32_t microseconds)
void system_reset_rtc_alarm(void)
{
/* Disable hibernate interrupts */
+ wait_for_hibctl_wc();
LM4_HIBERNATE_HIBIM = 0;
/* Clear interrupts */
+ wait_for_hibctl_wc();
LM4_HIBERNATE_HIBIC = LM4_HIBERNATE_HIBRIS;
}
@@ -344,6 +354,10 @@ static void hibernate(uint32_t seconds, uint32_t microseconds, uint32_t flags)
flags |= HIBDATA_WAKE_RTC;
set_hibernate_rtc_match_time(seconds, microseconds);
+
+ /* Enable RTC interrupt on match */
+ wait_for_hibctl_wc();
+ LM4_HIBERNATE_HIBIM = 1;
} else {
hibctl &= ~LM4_HIBCTL_RTCWEN;
}