diff options
Diffstat (limited to 'chip')
-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 { |