summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCHLin <CHLin56@nuvoton.com>2020-09-28 10:19:43 +0800
committerCommit Bot <commit-bot@chromium.org>2020-10-05 10:07:41 +0000
commite6ca724f8b5e15a18bccf14c5905b3f1d8baf7c2 (patch)
treeb69ce7c30a19297c151202a977ff317f8a5c8666
parentfe6577ffb515ef35af32a109e2b0832ea6a24018 (diff)
downloadchrome-ec-e6ca724f8b5e15a18bccf14c5905b3f1d8baf7c2.tar.gz
npcx: support enhanced PSL functions in npcx9
1. In npcx7, the PSL (hibernation) wakeup source only can come from physical PSL_IN pins. In npcx9, the LCT (Long Countdown Timer) module is introduced to support wakeup from a configurable timeout. 2. support PSL wakeup from the VCC1_RST pin. This function is disabled by default and enabled (and locked) in the firmware in the npcx9 A1 chip. In the npcx9 A2 chip, this function is enabled (and locked) by booter. 3. Support pulse mode and open drain (if pulse mode is enabled) for PSL_OUT pin. 4. support one PSL general-purpose output pin which is powered by VSBY. BRANCH=none BUG=b:165777478 TEST=pass "make buildall" TEST="hibernate 10", check EC wakes up from hibernate after 10 seconds. make sure the reset cause in the console is "power-on hibernate rtc-alarm" TEST="hibernate"; check EC wakes up from hibernate after pressing VCC1_RST button on the internal test board. Test=configure the PSL_OUT to pulse mode and "hibernate"; cut off VCC1 power; check EC can wake up from hibernate with any input event. Test=configure the level of PSL_GPO before hibernation; check the level is kept after entering hibernation. Signed-off-by: Wealian Liao <whliao@nuvoton.corp-partner.google.com> Signed-off-by: CHLin <CHLin56@nuvoton.com> Change-Id: I98ad41da8557222cf3d09fef9524880731cecde1 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2435164 Tested-by: CH Lin <chlin56@nuvoton.com> Reviewed-by: caveh jalali <caveh@chromium.org> Commit-Queue: CH Lin <chlin56@nuvoton.com>
-rw-r--r--chip/npcx/build.mk4
-rw-r--r--chip/npcx/config_chip-npcx9.h7
-rw-r--r--chip/npcx/lct.c152
-rw-r--r--chip/npcx/lct_chip.h22
-rw-r--r--chip/npcx/registers-npcx9.h6
-rw-r--r--chip/npcx/system-npcx7.c83
-rw-r--r--chip/npcx/system.c127
-rw-r--r--chip/npcx/system_chip.h19
-rw-r--r--core/cortex-m/ec.lds.S2
-rw-r--r--include/config.h22
-rw-r--r--include/rtc.h5
11 files changed, 420 insertions, 29 deletions
diff --git a/chip/npcx/build.mk b/chip/npcx/build.mk
index 61137f5856..4409c33c5d 100644
--- a/chip/npcx/build.mk
+++ b/chip/npcx/build.mk
@@ -43,6 +43,10 @@ chip-$(HAS_TASK_KEYSCAN)+=keyboard_raw.o
endif
chip-$(CONFIG_PS2)+=ps2.o
+# Only npcx9 or later chip family can support LCT module
+ifneq ($(CHIP_FAMILY),$(filter $(CHIP_FAMILY),npcx5 npcx7))
+chip-y+=lct.o
+endif
# spi monitor program fw for openocd and UUT(UART Update Tool)
npcx-monitor-fw=chip/npcx/spiflashfw/npcx_monitor
diff --git a/chip/npcx/config_chip-npcx9.h b/chip/npcx/config_chip-npcx9.h
index 597d334698..0f7f9ce179 100644
--- a/chip/npcx/config_chip-npcx9.h
+++ b/chip/npcx/config_chip-npcx9.h
@@ -46,6 +46,13 @@
/* Use SHI module version 2 supported by npcx7 and latter family */
#define NPCX_SHI_V2
+/* PSL_OUT optional configuration */
+/* Set PSL_OUT mode to pulse mode */
+#define NPCX_PSL_CFG_PSL_OUT_PULSE BIT(0)
+/* set PSL_OUT to open-drain */
+#define NPCX_PSL_CFG_PSL_OUT_OD BIT(1)
+#define CONFIG_HIBERNATE_PSL_OUT_FLAGS 0
+
/*****************************************************************************/
/* Memory mapping */
diff --git a/chip/npcx/lct.c b/chip/npcx/lct.c
new file mode 100644
index 0000000000..1df2628c4f
--- /dev/null
+++ b/chip/npcx/lct.c
@@ -0,0 +1,152 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+/* LCT (Long Countdown Timer) module for Chrome EC */
+#include "lct_chip.h"
+#include "console.h"
+#include "hooks.h"
+#include "registers.h"
+#include "rtc.h"
+#include "task.h"
+#include "timer.h"
+#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)
+
+void npcx_lct_sel_power_src(enum NPCX_LCT_PWR_SRC pwr_src)
+{
+ if (IS_BIT_SET(NPCX_LCTCONT, NPCX_LCTCONT_EN)) {
+ CPRINTS("Don't set power source when LCT is enabled");
+ return;
+ }
+
+ if (pwr_src == NPCX_LCT_PWR_SRC_VSBY)
+ SET_BIT(NPCX_LCTCONT, NPCX_LCTCONT_VSBY_PWR);
+ else
+ CLEAR_BIT(NPCX_LCTCONT, NPCX_LCTCONT_VSBY_PWR);
+}
+
+void npcx_lct_enable_clk(uint8_t enable)
+{
+ if (IS_BIT_SET(NPCX_LCTCONT, NPCX_LCTCONT_EN)) {
+ CPRINTS("Don't set/unset clock when LCT is enabled");
+ return;
+ }
+
+ if (enable) {
+ SET_BIT(NPCX_LCTCONT, NPCX_LCTCONT_CLK_EN);
+ /*
+ * This bit must be set to 1 at least tLCTCKEN (150 us)
+ * before the LCT is enabled.
+ */
+ udelay(LCT_CLK_ENABLE_DELAY_USEC);
+ } else {
+ CLEAR_BIT(NPCX_LCTCONT, NPCX_LCTCONT_CLK_EN);
+ }
+}
+
+void npcx_lct_enable(uint8_t enable)
+{
+ enable = !!enable;
+ SET_FIELD(NPCX_LCTCONT, NPCX_LCTCONT_EN_FIELD, enable);
+ /* Wait until the bit value equals to what is set */
+ while (IS_BIT_SET(NPCX_LCTCONT, NPCX_LCTCONT_EN) != enable)
+ ;
+}
+
+void npcx_lct_config(int seconds, int psl_ena, int int_ena)
+{
+ if (IS_BIT_SET(NPCX_LCTCONT, NPCX_LCTCONT_EN)) {
+ CPRINTS("Don't config LCT when LCT is enabled");
+ return;
+ }
+
+ /* LCT can count max to (16 weeks - 1 second) */
+ if (seconds >= (LCT_WEEKS_MAX + 1) * SECS_PER_WEEK) {
+ CPRINTS("LCT time is out of range");
+ return;
+ }
+
+ /* Clear pending LCT event first */
+ NPCX_LCTSTAT = BIT(NPCX_LCTSTAT_EVST);
+
+ NPCX_LCTWEEK = seconds / SECS_PER_WEEK;
+ seconds %= SECS_PER_WEEK;
+ NPCX_LCTDAY = seconds / SECS_PER_DAY;
+ seconds %= SECS_PER_DAY;
+ NPCX_LCTHOUR = seconds / SECS_PER_HOUR;
+ seconds %= SECS_PER_HOUR;
+ NPCX_LCTMINUTE = seconds / SECS_PER_MINUTE;
+ NPCX_LCTSECOND = seconds % SECS_PER_MINUTE;
+
+ if (psl_ena) {
+ if (IS_BIT_SET(NPCX_LCTCONT, NPCX_LCTCONT_VSBY_PWR))
+ SET_BIT(NPCX_LCTCONT, NPCX_LCTCONT_PSL_EN);
+ else
+ CPRINTS("LCT must source VSBY to support PSL wakeup");
+ }
+
+ if (int_ena)
+ SET_BIT(NPCX_LCTCONT, NPCX_LCTCONT_EVEN);
+
+}
+
+void npcx_lct_clear_event(void)
+{
+ NPCX_LCTSTAT = BIT(NPCX_LCTSTAT_EVST);
+}
+
+int npcx_lct_is_event_set(void)
+{
+ return IS_BIT_SET(NPCX_LCTSTAT, NPCX_LCTSTAT_EVST);
+}
+
+static void npcx_lct_init(void)
+{
+ /* Disable LCT */
+ npcx_lct_enable(0);
+ /* Clear control and status registers */
+ NPCX_LCTCONT = 0x0;
+ npcx_lct_clear_event();
+ /* Clear all timer registers */
+ NPCX_LCTSECOND = 0x0;
+ NPCX_LCTMINUTE = 0x0;
+ NPCX_LCTHOUR = 0x0;
+ NPCX_LCTDAY = 0x0;
+ NPCX_LCTWEEK = 0x0;
+}
+DECLARE_HOOK(HOOK_INIT, npcx_lct_init, HOOK_PRIO_DEFAULT);
+
+#ifdef CONFIG_CMD_RTC_ALARM
+static int command_lctalarm(int argc, char **argv)
+{
+ char *e;
+ int seconds;
+
+ seconds = strtoi(argv[1], &e, 0);
+ if (*e)
+ return EC_ERROR_PARAM2;
+
+ npcx_lct_enable(0);
+ npcx_lct_sel_power_src(NPCX_LCT_PWR_SRC_VSBY);
+ npcx_lct_enable_clk(1);
+ /* Enable LCT event interrupt and MIWU */
+ npcx_lct_config(seconds, 0, 1);
+ task_disable_irq(NPCX_IRQ_LCT_WKINTF_2);
+ /* Enable wake-up input sources & clear pending bit */
+ NPCX_WKPCL(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ NPCX_WKINEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ NPCX_WKEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ task_enable_irq(NPCX_IRQ_LCT_WKINTF_2);
+ npcx_lct_enable(1);
+
+ return 0;
+}
+DECLARE_CONSOLE_COMMAND(lctalarm, command_lctalarm, "", "");
+#endif
diff --git a/chip/npcx/lct_chip.h b/chip/npcx/lct_chip.h
new file mode 100644
index 0000000000..9e612f9e53
--- /dev/null
+++ b/chip/npcx/lct_chip.h
@@ -0,0 +1,22 @@
+/* Copyright 2020 The Chromium OS Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef __CROS_EC_LCT_CHIP_H
+#define __CROS_EC_LCT_CHIP_H
+#include "registers.h"
+
+enum NPCX_LCT_PWR_SRC {
+ NPCX_LCT_PWR_SRC_VCC1,
+ NPCX_LCT_PWR_SRC_VSBY
+};
+
+void npcx_lct_config(int seconds, int psl_ena, int int_ena);
+void npcx_lct_enable(uint8_t enable);
+void npcx_lct_enable_clk(uint8_t enable);
+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);
+
+#endif /* __CROS_EC_LCT_CHIP_H */
diff --git a/chip/npcx/registers-npcx9.h b/chip/npcx/registers-npcx9.h
index bcbeed81ab..93236cb977 100644
--- a/chip/npcx/registers-npcx9.h
+++ b/chip/npcx/registers-npcx9.h
@@ -251,12 +251,6 @@ enum {
#define NPCX_DEVALTG_PSL_OUT_SL 6
#define NPCX_DEVALTG_PSL_GPO_SL 7
-/* PSL optional flags */
-/* Set PSL_OUT mode to pulse mode */
-#define NPCX_PSL_PSL_OUT_PULSE BIT(0)
-/* set PSL_OUT to open-drain */
-#define NPCX_PSL_PSL_OUT_OD BIT(1)
-
/* SMBus register fields */
#define NPCX_SMBSEL_SMB4SEL 4
#define NPCX_SMBSEL_SMB5SEL 5
diff --git a/chip/npcx/system-npcx7.c b/chip/npcx/system-npcx7.c
index ffc64bee41..abbb6755c3 100644
--- a/chip/npcx/system-npcx7.c
+++ b/chip/npcx/system-npcx7.c
@@ -11,6 +11,7 @@
#include "cpu.h"
#include "ec_commands.h"
#include "hooks.h"
+#include "lct_chip.h"
#include "registers.h"
#include "system.h"
#include "task.h"
@@ -40,16 +41,56 @@ void system_mpu_config(void)
#error "Do not enable CONFIG_HIBERNATE_PSL if npcx ec doesn't support PSL mode!"
#endif
+static enum psl_pin_t system_gpio_to_psl(enum gpio_signal signal)
+{
+ enum psl_pin_t psl_no;
+ const struct gpio_info *g = gpio_list + signal;
+
+ if (g->port == GPIO_PORT_D && g->mask == MASK_PIN2) /* GPIOD2 */
+ psl_no = PSL_IN1;
+ else if (g->port == GPIO_PORT_0 && (g->mask & 0x07)) /* GPIO00/01/02 */
+ psl_no = GPIO_MASK_TO_NUM(g->mask) + 1;
+ else
+ psl_no = PSL_NONE;
+
+ return psl_no;
+}
+
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9
+void system_set_psl_gpo(int level)
+{
+ if (level)
+ SET_BIT(NPCX_GLUE_PSL_MCTL1, NPCX_GLUE_PSL_MCTL1_PSL_GPO_CTL);
+ else
+ CLEAR_BIT(NPCX_GLUE_PSL_MCTL1, NPCX_GLUE_PSL_MCTL1_PSL_GPO_CTL);
+}
+#endif
+
void system_enter_psl_mode(void)
{
/* Configure pins from GPIOs to PSL which rely on VSBY power rail. */
gpio_config_module(MODULE_PMU, 1);
/*
- * Only PSL_IN events can pull PSL_OUT to high and reboot ec.
- * We should treat it as wake-up pin reset.
+ * In npcx7, only physical PSL_IN pins can pull PSL_OUT to high and
+ * reboot ec.
+ * In npcx9, LCT timeout event can also pull PSL_OUT.
+ * We won't decide the wake cause now but only mark we are entering
+ * hibernation via PSL.
+ * The actual wakeup cause will be checked by the PSL input event bits
+ * when ec reboots.
*/
- NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PIN;
+ NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PSL;
+
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9
+ /*
+ * If pulse mode is enabled, the VCC power is turned off by the
+ * external component (Ex: PMIC) but PSL_OUT. So we can just return
+ * here.
+ */
+ if (IS_BIT_SET(NPCX_GLUE_PSL_MCTL1, NPCX_GLUE_PSL_MCTL1_PLS_EN))
+ return;
+#endif
/*
* Pull PSL_OUT (GPIO85) to low to cut off ec's VCC power rail by
@@ -67,34 +108,32 @@ noreturn void __keep __enter_hibernate_in_psl(void)
;
}
-static void system_psl_type_sel(int psl_no, uint32_t flags)
+static void system_psl_type_sel(enum psl_pin_t psl_pin, uint32_t flags)
{
/* Set PSL input events' type as level or edge trigger */
if ((flags & GPIO_INT_F_HIGH) || (flags & GPIO_INT_F_LOW))
- CLEAR_BIT(NPCX_GLUE_PSL_CTS, psl_no + 4);
- else if ((flags & GPIO_INT_F_RISING) || (flags & GPIO_INT_F_FALLING))
- SET_BIT(NPCX_GLUE_PSL_CTS, psl_no + 4);
+ CLEAR_BIT(NPCX_GLUE_PSL_CTS, psl_pin + 4);
+ else if ((flags & GPIO_INT_F_RISING) ||
+ (flags & GPIO_INT_F_FALLING))
+ SET_BIT(NPCX_GLUE_PSL_CTS, psl_pin + 4);
/*
* Set PSL input events' polarity is low (high-to-low) active or
* high (low-to-high) active
*/
if (flags & GPIO_HIB_WAKE_HIGH)
- SET_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_no);
+ SET_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_pin);
else
- CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_no);
+ CLEAR_BIT(NPCX_DEVALT(ALT_GROUP_D), 2 * psl_pin);
}
int system_config_psl_mode(enum gpio_signal signal)
{
- int psl_no;
+ enum psl_pin_t psl_no;
const struct gpio_info *g = gpio_list + signal;
- if (g->port == GPIO_PORT_D && g->mask == MASK_PIN2) /* GPIOD2 */
- psl_no = 0;
- else if (g->port == GPIO_PORT_0 && (g->mask & 0x07)) /* GPIO00/01/02 */
- psl_no = GPIO_MASK_TO_NUM(g->mask) + 1;
- else
+ psl_no = system_gpio_to_psl(signal);
+ if (psl_no == PSL_NONE)
return 0;
system_psl_type_sel(psl_no, g->flags);
@@ -115,7 +154,11 @@ __enter_hibernate_in_last_block(void)
* for better power consumption.
*/
NPCX_RAM_PD(0) = RAM_PD_MASK & 0xFF;
+#if defined(CHIP_FAMILY_NPCX7)
NPCX_RAM_PD(1) = (RAM_PD_MASK >> 8) & 0x0F;
+#elif defined(CHIP_FAMILY_NPCX9)
+ NPCX_RAM_PD(1) = (RAM_PD_MASK >> 8) & 0x7F;
+#endif
/* Set deep idle mode */
NPCX_PMCSR = 0x6;
@@ -131,6 +174,13 @@ __enter_hibernate_in_last_block(void)
* no stack.
*/
NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_MTC;
+#ifdef NPCX_LCT_SUPPORT
+ else if (IS_BIT_SET(NPCX_LCTSTAT, NPCX_LCTSTAT_EVST)) {
+ NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_LCT;
+ /* Clear LCT event */
+ NPCX_LCTSTAT = BIT(NPCX_LCTSTAT_EVST);
+ }
+#endif
else
/* Otherwise, we treat it as GPIOs wake-up */
NPCX_BBRAM(BBRM_DATA_INDEX_WAKE) = HIBERNATE_WAKE_PIN;
@@ -173,6 +223,9 @@ static void report_psl_wake_source(void)
return;
CPRINTS("PSL_CTS: 0x%x", NPCX_GLUE_PSL_CTS & 0xf);
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9
+ CPRINTS("PSL_MCTL1 event: 0x%x", NPCX_GLUE_PSL_MCTL1 & 0x18);
+#endif
}
DECLARE_HOOK(HOOK_INIT, report_psl_wake_source, HOOK_PRIO_DEFAULT);
#endif
diff --git a/chip/npcx/system.c b/chip/npcx/system.c
index 91e7de8169..0930e8be0e 100644
--- a/chip/npcx/system.c
+++ b/chip/npcx/system.c
@@ -14,6 +14,7 @@
#include "hooks.h"
#include "host_command.h"
#include "hwtimer_chip.h"
+#include "lct_chip.h"
#include "registers.h"
#include "rom_chip.h"
#include "sib_chip.h"
@@ -326,6 +327,38 @@ uint32_t chip_read_reset_flags(void)
return bbram_data_read(BBRM_DATA_INDEX_SAVED_RESET_FLAGS);
}
+static void chip_set_hib_flag(uint32_t *flags, uint32_t hib_wake_flags)
+{
+ /* Hibernate via PSL */
+ if (hib_wake_flags & HIBERNATE_WAKE_PSL) {
+#ifdef NPCX_LCT_SUPPORT
+ if (npcx_lct_is_event_set()) {
+ *flags |= EC_RESET_FLAG_RTC_ALARM |
+ EC_RESET_FLAG_HIBERNATE;
+ npcx_lct_clear_event();
+ return;
+ }
+#endif
+ *flags |= EC_RESET_FLAG_WAKE_PIN |
+ EC_RESET_FLAG_HIBERNATE;
+ } else { /* Hibernate via non-PSL */
+#ifdef NPCX_LCT_SUPPORT
+ if (hib_wake_flags & HIBERNATE_WAKE_LCT) {
+ *flags |= EC_RESET_FLAG_RTC_ALARM |
+ EC_RESET_FLAG_HIBERNATE;
+ return;
+ }
+#endif
+ if (hib_wake_flags & HIBERNATE_WAKE_PIN) {
+ *flags |= EC_RESET_FLAG_WAKE_PIN |
+ EC_RESET_FLAG_HIBERNATE;
+ } else if (hib_wake_flags & HIBERNATE_WAKE_MTC) {
+ *flags |= EC_RESET_FLAG_RTC_ALARM |
+ EC_RESET_FLAG_HIBERNATE;
+ }
+ }
+}
+
static void check_reset_cause(void)
{
uint32_t hib_wake_flags = bbram_data_read(BBRM_DATA_INDEX_WAKE);
@@ -421,11 +454,7 @@ static void check_reset_cause(void)
SET_BIT(NPCX_RSTCTL, NPCX_RSTCTL_DBGRST_STS);
}
- /* Reset by hibernate */
- if (hib_wake_flags & HIBERNATE_WAKE_PIN)
- flags |= EC_RESET_FLAG_WAKE_PIN | EC_RESET_FLAG_HIBERNATE;
- else if (hib_wake_flags & HIBERNATE_WAKE_MTC)
- flags |= EC_RESET_FLAG_RTC_ALARM | EC_RESET_FLAG_HIBERNATE;
+ chip_set_hib_flag(&flags, hib_wake_flags);
/* Watchdog Reset */
if (IS_BIT_SET(NPCX_T0CSR, NPCX_T0CSR_WDRST_STS)) {
@@ -488,6 +517,32 @@ static void system_set_gpios_and_wakeup_inputs_hibernate(void)
}
}
+#ifdef NPCX_LCT_SUPPORT
+static void system_set_lct_alarm(uint32_t seconds, uint32_t microseconds)
+{
+ /* The min resolution of LCT is 1 seconds */
+ if ((seconds == 0) && (microseconds != 0))
+ seconds = 1;
+
+ npcx_lct_enable(0);
+ npcx_lct_sel_power_src(NPCX_LCT_PWR_SRC_VSBY);
+#ifdef CONFIG_HIBERNATE_PSL
+ /* Enable LCT event to PSL */
+ npcx_lct_config(seconds, 1, 0);
+#else
+ /* Enable LCT event interrupt and MIWU */
+ npcx_lct_config(seconds, 0, 1);
+ task_disable_irq(NPCX_IRQ_LCT_WKINTF_2);
+ /* Enable wake-up input sources & clear pending bit */
+ NPCX_WKPCL(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ NPCX_WKINEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ NPCX_WKEN(MIWU_TABLE_2, LCT_WUI_GROUP) |= LCT_WUI_MASK;
+ task_enable_irq(NPCX_IRQ_LCT_WKINTF_2);
+#endif
+ npcx_lct_enable(1);
+}
+#endif
+
/**
* hibernate function for npcx ec.
*
@@ -502,6 +557,14 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
NPCX_ADCCNF = 0;
usleep(1000);
+#ifdef NPCX_LCT_SUPPORT
+ /*
+ * This function must be called before the ITIM (system tick)
+ * is disabled because it calls udelay inside this function
+ */
+ npcx_lct_enable_clk(1);
+#endif
+
/* Set SPI pins to be in Tri-State */
SET_BIT(NPCX_DEVCNT, NPCX_DEVCNT_F_SPI_TRIS);
@@ -554,8 +617,11 @@ void __enter_hibernate(uint32_t seconds, uint32_t microseconds)
* next event.
*/
if (seconds || microseconds)
+#ifdef NPCX_LCT_SUPPORT
+ system_set_lct_alarm(seconds, microseconds);
+#else
system_set_rtc_alarm(seconds, microseconds);
-
+#endif
/* execute hibernate func depend on chip series */
__hibernate_npcx_series();
@@ -792,6 +858,55 @@ void system_pre_init(void)
#ifdef CONFIG_CHIP_PANIC_BACKUP
chip_panic_data_restore();
#endif
+
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9
+ if (IS_ENABLED(CONFIG_HIBERNATE_PSL)) {
+ uint8_t opt_flag = CONFIG_HIBERNATE_PSL_OUT_FLAGS;
+
+ /* PSL Glitch Protection */
+ SET_BIT(NPCX_GLUE_PSL_MCTL2, NPCX_GLUE_PSL_MCTL2_PSL_GP_EN);
+
+ /*
+ * TODO: Remove this when NPCX9 A2 chip is available because A2
+ * chip will enable VCC1_RST to PSL wakeup source and lock it in
+ * the booter.
+ */
+ if (IS_ENABLED(CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP)) {
+ /*
+ * Enable VCC1_RST as the wake-up source from
+ * hibernation.
+ */
+ SET_BIT(NPCX_GLUE_PSL_MCTL1,
+ NPCX_GLUE_PSL_MCTL1_VCC1_RST_PSL);
+ /* Disable VCC_RST Pull-Up */
+ SET_BIT(NPCX_DEVALT(ALT_GROUP_G),
+ NPCX_DEVALTG_VCC1_RST_PUD);
+ /*
+ * Lock this bit itself and VCC1_RST_PSL in the
+ * PSL_MCTL1 register to read-only.
+ */
+ SET_BIT(NPCX_GLUE_PSL_MCTL2,
+ NPCX_GLUE_PSL_MCTL2_VCC1_RST_PSL_LK);
+ }
+
+ /* Don't set PSL_OUT to open-drain if it is the level mode */
+ ASSERT((opt_flag & NPCX_PSL_CFG_PSL_OUT_PULSE) ||
+ !(opt_flag & NPCX_PSL_CFG_PSL_OUT_OD));
+
+ if (opt_flag & NPCX_PSL_CFG_PSL_OUT_OD)
+ SET_BIT(NPCX_GLUE_PSL_MCTL1, NPCX_GLUE_PSL_MCTL1_OD_EN);
+ else
+ CLEAR_BIT(NPCX_GLUE_PSL_MCTL1,
+ NPCX_GLUE_PSL_MCTL1_OD_EN);
+
+ if (opt_flag & NPCX_PSL_CFG_PSL_OUT_PULSE)
+ SET_BIT(NPCX_GLUE_PSL_MCTL1,
+ NPCX_GLUE_PSL_MCTL1_PLS_EN);
+ else
+ CLEAR_BIT(NPCX_GLUE_PSL_MCTL1,
+ NPCX_GLUE_PSL_MCTL1_PLS_EN);
+ }
+#endif
}
void system_reset(int flags)
diff --git a/chip/npcx/system_chip.h b/chip/npcx/system_chip.h
index da98888787..db2351cf33 100644
--- a/chip/npcx/system_chip.h
+++ b/chip/npcx/system_chip.h
@@ -11,6 +11,13 @@
/* Flags for BBRM_DATA_INDEX_WAKE */
#define HIBERNATE_WAKE_MTC BIT(0) /* MTC alarm */
#define HIBERNATE_WAKE_PIN BIT(1) /* Wake pin */
+#define HIBERNATE_WAKE_LCT BIT(2) /* LCT alarm */
+/*
+ * Indicate that EC enters hibernation via PSL. When EC wakes up from
+ * hibernation and this flag is set, it will check the related status bit to
+ * know the actual wake up source. (From LCT or physical wakeup pins)
+ */
+#define HIBERNATE_WAKE_PSL BIT(3)
/* Indices for battery-backed ram (BBRAM) data position */
enum bbram_data_index {
@@ -30,6 +37,14 @@ enum bbram_data_index {
BBRM_DATA_INDEX_PANIC_BKUP = 36, /* Panic data (index 35-63)*/
};
+enum psl_pin_t {
+ PSL_IN1,
+ PSL_IN2,
+ PSL_IN3,
+ PSL_IN4,
+ PSL_NONE,
+};
+
/* Issue a watchdog reset */
void system_watchdog_reset(void);
@@ -79,4 +94,8 @@ extern unsigned int __after_init_end;
#endif
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX9
+void system_set_psl_gpo(int level);
+#endif
+
#endif /* __CROS_EC_SYSTEM_CHIP_H */
diff --git a/core/cortex-m/ec.lds.S b/core/cortex-m/ec.lds.S
index 2314156294..fc24d181b5 100644
--- a/core/cortex-m/ec.lds.S
+++ b/core/cortex-m/ec.lds.S
@@ -161,7 +161,7 @@ SECTIONS
. = ALIGN(4);
STRINGIFY(OUTDIR/core/CORE/init.o) (.text)
-#if defined(CHIP_FAMILY_NPCX7) && !defined(CONFIG_HIBERNATE_PSL)
+#if NPCX_FAMILY_VERSION >= NPCX_FAMILY_NPCX7 && !defined(CONFIG_HIBERNATE_PSL)
/* Keep hibernate utility in last code ram block */
. = ALIGN(4);
KEEP(*(.after_init))
diff --git a/include/config.h b/include/config.h
index 057046517d..2a5f86377d 100644
--- a/include/config.h
+++ b/include/config.h
@@ -2241,6 +2241,28 @@
/* Wake up pins have non-const configuration. */
#undef CONFIG_HIBERNATE_WAKE_PINS_DYNAMIC
+/* In npcx9 and later chips, enhanced PSL features are supported including:
+ * (1) Pulse mode for PSL_OUT signal.
+ * (2) Open-drain for PSL_OUT signal (when Pulse mode is enabled.)
+ * These features can be enabled in board configuration file by adding
+ * the following bit masks to this flag:
+ * (1) NPCX_PSL_CFG_PSL_OUT_PULSE.
+ * (2) NPCX_PSL_CFG_PSL_OUT_OD.
+ * Ex: #define CONFIG_HIBERNATE_PSL_OUT_FLAGS \
+ (NPCX_PSL_CFG_PSL_OUT_PULSE | NPCX_PSL_CFG_PSL_OUT_OD)
+ */
+#undef CONFIG_HIBERNATE_PSL_OUT_FLAGS
+
+/*
+ * Enable VCC1_RST pin as the input of PSL wakeup source. When Enabling this,
+ * the VCC1_RST pin must be connected to the VSBY supply via an external pull-up
+ * resistor of maximum 100K ohm .
+ * TODO: Remove this when NPCX9 A2 chip is available because A2
+ * chip will enable VCC1_RST to PSL wakeup source and lock it in
+ * the booter.
+ */
+#undef CONFIG_HIBERNATE_PSL_VCC1_RST_WAKEUP
+
/*
* Chip supports a 64-bit hardware timer and implements
* __hw_clock_source_read64 and __hw_clock_source_set64.
diff --git a/include/rtc.h b/include/rtc.h
index c9909bbc48..cff1ee0f64 100644
--- a/include/rtc.h
+++ b/include/rtc.h
@@ -10,7 +10,10 @@
#include "common.h"
-#define SECS_PER_DAY (60 * 60 * 24)
+#define SECS_PER_MINUTE 60
+#define SECS_PER_HOUR (60 * SECS_PER_MINUTE)
+#define SECS_PER_DAY (24 * SECS_PER_HOUR)
+#define SECS_PER_WEEK (7 * SECS_PER_DAY)
#define SECS_PER_YEAR (365 * SECS_PER_DAY)
/* The seconds elapsed from 01-01-1970 to 01-01-2000 */
#define SECS_TILL_YEAR_2K (946684800)