diff options
author | Dino Li <Dino.Li@ite.com.tw> | 2021-09-08 12:01:31 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-09-27 06:44:09 +0000 |
commit | 4e2d1981915533a3f214b4075babd49c8ca6c0ef (patch) | |
tree | 5626aeec1fb410c9c540892de1323e2519cfae5a /chip/it83xx/clock.c | |
parent | 8e132f7c5b61466bcca6d7ab7403f44611cbd032 (diff) | |
download | chrome-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>
Diffstat (limited to 'chip/it83xx/clock.c')
-rw-r--r-- | chip/it83xx/clock.c | 46 |
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 */ |