summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDino Li <Dino.Li@ite.com.tw>2021-09-08 12:01:31 +0800
committerCommit Bot <commit-bot@chromium.org>2021-09-27 06:44:09 +0000
commit4e2d1981915533a3f214b4075babd49c8ca6c0ef (patch)
tree5626aeec1fb410c9c540892de1323e2519cfae5a
parent8e132f7c5b61466bcca6d7ab7403f44611cbd032 (diff)
downloadchrome-ec-4e2d1981915533a3f214b4075babd49c8ca6c0ef.tar.gz
it83xx: clock: fix sequence to set PLL control register
We change event timer's clock to 32.768kHz before entering low power mode. And will restore the clock to 8MHz (by checking PLL control register's setting in ISR) when chip wake up from the low power mode. So we need to ensure the setting is taken into PLL control register before wfi instruction. The original implementation can't ensure event timer’s clock is restored to 8MHz when chip wake up. So we fix it. This also fix wfi (wait for interrupt) instruction fail issue on RISV-V core chips when a timer count down to zero (MTIP@mip is set to 1 until HW reload timer counter). Once CPU executed wfi instruction, CPU should stay there until interrupt is fired or MEIP@mip is non-zero. But currently, HW checks entire mip value (should check MEIP@mip only) to decide whether or not to ignore wfi instruction. The issue will cause EC premature wake from idle task even there is no interrupt fired. BRANCH=asurada, icarus BUG=none TEST=-On asurada, increase CPU clock to 96mhz. Plug out/in type-c adapter to wake chip up from low power mode, no pre-watchdog warning fired. (x100) -buildall Signed-off-by: Dino Li <Dino.Li@ite.com.tw> Change-Id: I72bb2566c5b22bc132ab304a38a5a1b5b968e463 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3168672 Reviewed-by: Eric Yilun Lin <yllin@google.com> Commit-Queue: Eric Yilun Lin <yllin@google.com>
-rw-r--r--chip/it83xx/clock.c46
1 files changed, 40 insertions, 6 deletions
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c
index 49f99a167b..41f800721a 100644
--- a/chip/it83xx/clock.c
+++ b/chip/it83xx/clock.c
@@ -134,9 +134,15 @@ static uint8_t pll_setting;
void __ram_code clock_ec_pll_ctrl(enum ec_pll_ctrl mode)
{
+ volatile uint8_t _pll_ctrl __unused;
+
IT83XX_ECPM_PLLCTRL = mode;
- /* for deep doze / sleep mode */
- IT83XX_ECPM_PLLCTRL = mode;
+ /*
+ * for deep doze / sleep mode
+ * This load operation will ensure PLL setting is taken into
+ * control register before wait for interrupt instruction.
+ */
+ _pll_ctrl = IT83XX_ECPM_PLLCTRL;
#ifdef IT83XX_CHIP_FLASH_NO_DEEP_POWER_DOWN
/*
@@ -546,10 +552,16 @@ defined(CONFIG_HOSTCMD_ESPI)
__builtin_unreachable();
}
+/* use data type int here not bool to get better instruction number. */
+static volatile int wait_interrupt_fired;
void clock_sleep_mode_wakeup_isr(void)
{
uint32_t st_us, c;
+ /* Clear flag on each interrupt. */
+ if (IS_ENABLED(CHIP_CORE_RISCV))
+ wait_interrupt_fired = 0;
+
/* trigger a reboot if wake up EC from sleep mode (system hibernate) */
if (clock_ec_wake_from_sleep()) {
#if defined(IT83XX_ESPI_INHIBIT_CS_BY_PAD_DISABLED) && \
@@ -595,10 +607,7 @@ defined(CONFIG_HOSTCMD_ESPI)
}
}
-/**
- * Low power idle task. Executed when no tasks are ready to be scheduled.
- */
-void __ram_code __idle(void)
+void __keep __idle_init(void)
{
console_expire_time.val = get_time().val + CONSOLE_IN_USE_ON_BOOT_TIME;
/* init hw timer and clock source is 32.768 KHz */
@@ -611,6 +620,18 @@ void __ram_code __idle(void)
* their task inits and have gone to sleep.
*/
CPRINTS("low power idle task started");
+}
+
+/**
+ * Low power idle task. Executed when no tasks are ready to be scheduled.
+ */
+void __ram_code __idle(void)
+{
+ /*
+ * There is not enough space from ram code section to cache entire idle
+ * function, hence pull initialization function out of the section.
+ */
+ __idle_init();
while (1) {
/* Disable interrupts */
@@ -636,8 +657,21 @@ void __ram_code __idle(void)
clock_ec_pll_ctrl(EC_PLL_DOZE);
idle_doze_cnt++;
}
+ /* Set flag before entering low power mode. */
+ if (IS_ENABLED(CHIP_CORE_RISCV))
+ wait_interrupt_fired = 1;
clock_cpu_standby();
interrupt_enable();
+ /*
+ * Sometimes wfi instruction may fail due to CPU's MTIP@mip
+ * register is non-zero.
+ * If the wait_interrupt_fired flag is true at this point,
+ * it means that EC waked-up by the above issue not an
+ * interrupt. Hence we loop running wfi instruction here until
+ * wfi success.
+ */
+ while (IS_ENABLED(CHIP_CORE_RISCV) && wait_interrupt_fired)
+ clock_cpu_standby();
}
}
#endif /* CONFIG_LOW_POWER_IDLE */