summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWealian Liao <whliao@nuvoton.corp-partner.google.com>2020-10-29 01:55:56 -0700
committerCommit Bot <commit-bot@chromium.org>2021-01-12 02:35:14 +0000
commit88b780027ddfc0afa55c4cf3c6d5606d7676cbca (patch)
tree32aac28aa0a1c737aecea4162b43a7599a035bef
parent72106b0e0997ac8d0df70335471659372466133b (diff)
downloadchrome-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>
-rw-r--r--board/npcx9_evb/board.h2
-rw-r--r--chip/npcx/lct.c28
-rw-r--r--chip/npcx/lct_chip.h6
-rw-r--r--chip/npcx/system.c40
-rw-r--r--chip/npcx/system_chip.h2
-rw-r--r--common/main.c4
-rw-r--r--include/config.h7
-rw-r--r--include/system.h5
8 files changed, 87 insertions, 7 deletions
diff --git a/board/npcx9_evb/board.h b/board/npcx9_evb/board.h
index 209c25a803..3fe42da1a1 100644
--- a/board/npcx9_evb/board.h
+++ b/board/npcx9_evb/board.h
@@ -21,6 +21,7 @@
#define CONFIG_ENABLE_JTAG_SELECTION
#define CONFIG_BOARD_VERSION_GPIO
#define CONFIG_EXTPOWER_GPIO
+#define CONFIG_HIBERNATE_PSL_COMPENSATE_RTC
#define CONFIG_I2C_CONTROLLER
#define CONFIG_KEYBOARD_BOARD_CONFIG
#define CONFIG_KEYBOARD_PROTOCOL_8042
@@ -36,6 +37,7 @@
#define CONFIG_CMD_STACKOVERFLOW
#define CONFIG_CMD_JUMPTAGS
#define CONFIG_CMD_FLASH
+#define CONFIG_CMD_RTC
#define CONFIG_CMD_SCRATCHPAD
#define CONFIG_CMD_I2CWEDGE
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 {
diff --git a/common/main.c b/common/main.c
index c1228d0a7a..2e9fe5a444 100644
--- a/common/main.c
+++ b/common/main.c
@@ -124,6 +124,10 @@ test_mockable __keep int main(void)
*/
timer_init();
+ /* Compensate the elapsed time for the RTC. */
+ if (IS_ENABLED(CONFIG_HIBERNATE_PSL_COMPENSATE_RTC))
+ system_compensate_rtc();
+
/* Main initialization stage. Modules may enable interrupts here. */
cpu_init();
diff --git a/include/config.h b/include/config.h
index 4a3b832577..e83cb07191 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2284,6 +2284,13 @@
#undef CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP
/*
+ * Compensate the elapsed time for the RTC which couldn't work in hibernate PSL
+ * after hibernation wake-up. Currently, NPCX9 supports LCT to compensate the
+ * elapsed time for the RTC.
+ */
+#undef CONFIG_HIBERNATE_PSL_COMPENSATE_RTC
+
+/*
* Chip supports a 64-bit hardware timer and implements
* __hw_clock_source_read64 and __hw_clock_source_set64.
*
diff --git a/include/system.h b/include/system.h
index 10484b512d..1f74ecdc47 100644
--- a/include/system.h
+++ b/include/system.h
@@ -682,4 +682,9 @@ int system_set_active_copy(enum ec_image copy);
*/
uint32_t flash_get_rw_offset(enum ec_image copy);
+/**
+ * Compensate for the RTC after hibernation wake-up.
+ */
+void system_compensate_rtc(void);
+
#endif /* __CROS_EC_SYSTEM_H */