summaryrefslogtreecommitdiff
path: root/chip/npcx/system-npcx7.c
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 /chip/npcx/system-npcx7.c
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>
Diffstat (limited to 'chip/npcx/system-npcx7.c')
-rw-r--r--chip/npcx/system-npcx7.c83
1 files changed, 68 insertions, 15 deletions
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