summaryrefslogtreecommitdiff
path: root/chip
diff options
context:
space:
mode:
Diffstat (limited to 'chip')
-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
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 {