diff options
author | Mulin Chao <mlchao@nuvoton.com> | 2016-02-16 14:17:42 +0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2016-05-11 21:24:32 -0700 |
commit | 3ccb91fe10271f8af6f097483efac9a177d11a31 (patch) | |
tree | fa3e6ecf1d4bf8dd53c8a12dce4ff0389ff02367 /chip/npcx/hwtimer.c | |
parent | b6b6430daa81e44519e92e37fe57ccd8312cfcf1 (diff) | |
download | chrome-ec-3ccb91fe10271f8af6f097483efac9a177d11a31.tar.gz |
npcx: Fixed bug that unexpected value of timer which source clock is 32K
In rare case, FW read the unexpected counter value of timer which source
clock is 32K (Watchdog timer and ITIM16/32 which use 32K source clock).
The root cause is the clocks between reading registers and timer's are
asynchronous. It has a chance to get invalid counter value when timer is
under transaction edge. The solution is using two consecutive equal
readings to make sure the counter value is valid.
Beside different source clocks of timer, we also found there's chip's bug
which causes unexpected value of timer. If an interrupt that occurs very
shortly before entering deep idle with instant wakeup, it might result in
disruptive execution (such as skipping some instructions or hard fault)
after "wfi". The workaround is adding the same bypass for idle in deep
idle section.
Modified sources:
1. clock.c: Add bypass for instant wakeup from deep sleep.
2. hwtimer.c: Add consecutive reading function for event timer.
3. watchdog.c: Add consecutive reading function for watchdog timer.
BUG=chrome-os-partner:34346
TEST=make buildall -j; test nuvoton IC specific drivers
BRANCH=none
Change-Id: I7c9f1fb9618a3c29826d8f4599864a8dac4203bf
Signed-off-by: Mulin Chao <mlchao@nuvoton.com>
Reviewed-on: https://chromium-review.googlesource.com/327356
Reviewed-by: Shawn N <shawnn@chromium.org>
Diffstat (limited to 'chip/npcx/hwtimer.c')
-rw-r--r-- | chip/npcx/hwtimer.c | 10 |
1 files changed, 8 insertions, 2 deletions
diff --git a/chip/npcx/hwtimer.c b/chip/npcx/hwtimer.c index 5a7fa8b38c..196fcf985c 100644 --- a/chip/npcx/hwtimer.c +++ b/chip/npcx/hwtimer.c @@ -117,7 +117,13 @@ uint32_t __hw_clock_event_get(void) /* Get current counter value of event timer */ uint16_t __hw_clock_event_count(void) { - return NPCX_ITCNT16(ITIM_EVENT_NO); + uint16_t cnt; + /* Wait for two consecutive equal values are read */ + do { + cnt = NPCX_ITCNT16(ITIM_EVENT_NO); + } while (cnt != NPCX_ITCNT16(ITIM_EVENT_NO)); + + return cnt; } /* Returns time delay cause of deep idle */ @@ -125,7 +131,7 @@ uint32_t __hw_clock_get_sleep_time(uint16_t pre_evt_cnt) { fp_t evt_tick = FLOAT_TO_FP(SECOND/(float)INT_32K_CLOCK); uint32_t sleep_time; - uint16_t cnt = NPCX_ITCNT16(ITIM_EVENT_NO); + uint16_t cnt = __hw_clock_event_count(); /* Event has been triggered but timer ISR dosen't handle it */ if (IS_BIT_SET(NPCX_ITCTS(ITIM_EVENT_NO), NPCX_ITCTS_TO_STS)) |