summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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)