diff options
author | Randall Spangler <rspangler@chromium.org> | 2013-10-29 14:16:40 -0700 |
---|---|---|
committer | chrome-internal-fetch <chrome-internal-fetch@google.com> | 2013-10-30 19:45:00 +0000 |
commit | 1d0102ae2cccdb4e798c196b0e6445c167efe4b6 (patch) | |
tree | 363162ba6894b4235f68495c050938d5381d434a | |
parent | 52ce907d40074d92c5044ac2fbe5c267b166a4ee (diff) | |
download | chrome-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.h | 1 | ||||
-rw-r--r-- | chip/lm4/system.c | 16 |
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; } |