diff options
author | Wealian Liao <whliao@nuvoton.corp-partner.google.com> | 2020-10-29 01:55:56 -0700 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-01-12 02:35:14 +0000 |
commit | 88b780027ddfc0afa55c4cf3c6d5606d7676cbca (patch) | |
tree | 32aac28aa0a1c737aecea4162b43a7599a035bef /chip/npcx | |
parent | 72106b0e0997ac8d0df70335471659372466133b (diff) | |
download | chrome-ec-88b780027ddfc0afa55c4cf3c6d5606d7676cbca.tar.gz |
npcx/system: LCT compensate for MTC in PSL_hibernate
NPCX chip uses the MTC module as the RTC counter. However, in PSL
hibernate, MTC will stop counting. NPCX9 supports the LCT module which
could count continuously when VCC1 power is off. The CL uses LCT to
compensate for the MTC counter value after PSL hibernate wake-up. The
LCT maximum counting value is 16 weeks.
BRANCH=none
BUG=b:165777478, b:171919875
TEST=pass "make buildall"
TEST=Check the RTC value in the following scenario:
1. "hibernate" and wake up EC by PSL input.
2. "hibernate 30" and wake up EC after timeout.
3. "hibernate 30" and wake up EC by PSL input before timeout.
Signed-off-by: Wealian Liao <whliao@nuvoton.corp-partner.google.com>
Change-Id: I39e370a437f40749acbd3a35a8b37ebec70f1bf2
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2506864
Reviewed-by: Keith Short <keithshort@chromium.org>
Diffstat (limited to 'chip/npcx')
-rw-r--r-- | chip/npcx/lct.c | 28 | ||||
-rw-r--r-- | chip/npcx/lct_chip.h | 6 | ||||
-rw-r--r-- | chip/npcx/system.c | 40 | ||||
-rw-r--r-- | chip/npcx/system_chip.h | 2 |
4 files changed, 69 insertions, 7 deletions
diff --git a/chip/npcx/lct.c b/chip/npcx/lct.c index 1df2628c4f..e23fa3bf6a 100644 --- a/chip/npcx/lct.c +++ b/chip/npcx/lct.c @@ -14,7 +14,6 @@ #include "util.h" #define LCT_CLK_ENABLE_DELAY_USEC 150 -#define LCT_WEEKS_MAX 15 #define CPRINTF(format, args...) cprintf(CC_CLOCK, format, ## args) #define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) @@ -68,7 +67,7 @@ void npcx_lct_config(int seconds, int psl_ena, int int_ena) } /* LCT can count max to (16 weeks - 1 second) */ - if (seconds >= (LCT_WEEKS_MAX + 1) * SECS_PER_WEEK) { + if (seconds > NPCX_LCT_MAX) { CPRINTS("LCT time is out of range"); return; } @@ -97,6 +96,31 @@ void npcx_lct_config(int seconds, int psl_ena, int int_ena) } +uint32_t npcx_lct_get_time(void) +{ + uint32_t second; + uint8_t week, day, hour, minute; + + do { + week = NPCX_LCTWEEK; + day = NPCX_LCTDAY; + hour = NPCX_LCTHOUR; + minute = NPCX_LCTMINUTE; + second = NPCX_LCTSECOND; + } while (week != NPCX_LCTWEEK || + day != NPCX_LCTDAY || + hour != NPCX_LCTHOUR || + minute != NPCX_LCTMINUTE || + second != NPCX_LCTSECOND); + + second += minute * SECS_PER_MINUTE + + hour * SECS_PER_HOUR + + day * SECS_PER_DAY + + week * SECS_PER_WEEK; + + return second; +} + void npcx_lct_clear_event(void) { NPCX_LCTSTAT = BIT(NPCX_LCTSTAT_EVST); diff --git a/chip/npcx/lct_chip.h b/chip/npcx/lct_chip.h index 9e612f9e53..197c189f43 100644 --- a/chip/npcx/lct_chip.h +++ b/chip/npcx/lct_chip.h @@ -6,6 +6,9 @@ #ifndef __CROS_EC_LCT_CHIP_H #define __CROS_EC_LCT_CHIP_H #include "registers.h" +#include "rtc.h" + +#define NPCX_LCT_MAX (16 * SECS_PER_WEEK - 1) enum NPCX_LCT_PWR_SRC { NPCX_LCT_PWR_SRC_VCC1, @@ -19,4 +22,7 @@ void npcx_lct_sel_power_src(enum NPCX_LCT_PWR_SRC pwr_src); void npcx_lct_clear_event(void); int npcx_lct_is_event_set(void); +/* return the current time of LCT in second */ +uint32_t npcx_lct_get_time(void); + #endif /* __CROS_EC_LCT_CHIP_H */ diff --git a/chip/npcx/system.c b/chip/npcx/system.c index a779c050bf..e2fb468414 100644 --- a/chip/npcx/system.c +++ b/chip/npcx/system.c @@ -534,6 +534,9 @@ static void system_set_lct_alarm(uint32_t seconds, uint32_t microseconds) #ifdef CONFIG_HIBERNATE_PSL /* Enable LCT event to PSL */ npcx_lct_config(seconds, 1, 0); + /* save the start time of LCT */ + if (IS_ENABLED(CONFIG_HOSTCMD_RTC) || IS_ENABLED(CONFIG_CMD_RTC)) + bbram_data_write(BBRM_DATA_INDEX_LCT_TIME, seconds); #else /* Enable LCT event interrupt and MIWU */ npcx_lct_config(seconds, 0, 1); @@ -617,21 +620,48 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds) for (i = NPCX_IRQ_0 ; i < NPCX_IRQ_COUNT ; i++) task_clear_pending_irq(i); - /* - * Set RTC interrupt in time to wake up before - * next event. - */ - if (seconds || microseconds) + /* Set the timer interrupt for wake up. */ #ifdef NPCX_LCT_SUPPORT + if (seconds || microseconds) { system_set_lct_alarm(seconds, microseconds); + } else if (IS_ENABLED(CONFIG_HIBERNATE_PSL_COMPENSATE_RTC)) { + system_set_lct_alarm(NPCX_LCT_MAX, 0); + } #else + if (seconds || microseconds) system_set_rtc_alarm(seconds, microseconds); #endif /* execute hibernate func depend on chip series */ __hibernate_npcx_series(); +} + +#ifdef CONFIG_HIBERNATE_PSL_COMPENSATE_RTC +#ifndef NPCX_LCT_SUPPORT +#error "Do not enable CONFIG_HIBERNATE_PSL_COMPENSATE_RTC if npcx ec doesn't \ +support LCT!" +#endif +/* + * The function uses the LCT counter value to compensate for RTC after hibernate + * wake-up. Because system_set_rtc() will invoke udelay(), the function should + * execute after timer_init(). The function also should execute before + * npcx_lct_init() which will clear all LCT register. + */ +void system_compensate_rtc(void) +{ + uint32_t rtc_time, ltc_start_time; + ltc_start_time = bbram_data_read(BBRM_DATA_INDEX_LCT_TIME); + if (ltc_start_time == 0) + return; + + rtc_time = system_get_rtc_sec(); + rtc_time += ltc_start_time - npcx_lct_get_time(); + system_set_rtc(rtc_time); + /* Clear BBRAM data to avoid compensating again. */ + bbram_data_write(BBRM_DATA_INDEX_LCT_TIME, 0); } +#endif #endif /* CONFIG_SUPPORT_CHIP_HIBERNATION */ static char system_to_hex(uint8_t val) diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h index c084cd04a6..5a9533e59f 100644 --- a/chip/npcx/system_chip.h +++ b/chip/npcx/system_chip.h @@ -35,6 +35,8 @@ enum bbram_data_index { * 36. */ BBRM_DATA_INDEX_PANIC_BKUP = 36, /* Panic data (index 35-63)*/ + BBRM_DATA_INDEX_LCT_TIME = 64, /* The start time of LCT(4 bytes) + */ }; enum psl_pin_t { |