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>2013-10-30 19:45:00 +0000
commit1d0102ae2cccdb4e798c196b0e6445c167efe4b6 (patch)
tree363162ba6894b4235f68495c050938d5381d434a
parent52ce907d40074d92c5044ac2fbe5c267b166a4ee (diff)
downloadchrome-ec-1d0102ae2cccdb4e798c196b0e6445c167efe4b6.tar.gz
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:23678 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: Ie01b106ac6a6c5894811f9a333715b22ef896f82 Signed-off-by: Randall Spangler <rspangler@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/175013 Reviewed-by: Alec Berg <alecaberg@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 589a10c99e..0741d0c7f3 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;
}