diff options
Diffstat (limited to 'chip/it83xx/clock.c')
-rw-r--r-- | chip/it83xx/clock.c | 701 |
1 files changed, 0 insertions, 701 deletions
diff --git a/chip/it83xx/clock.c b/chip/it83xx/clock.c deleted file mode 100644 index 41f800721a..0000000000 --- a/chip/it83xx/clock.c +++ /dev/null @@ -1,701 +0,0 @@ -/* Copyright 2013 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. - */ - -/* Clocks and power management settings */ - -#include "adc_chip.h" -#include "clock.h" -#include "common.h" -#include "console.h" -#include "hwtimer.h" -#include "hwtimer_chip.h" -#include "intc.h" -#include "irq_chip.h" -#include "it83xx_pd.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "uart.h" -#include "util.h" - -/* Console output macros. */ -#define CPUTS(outstr) cputs(CC_CLOCK, outstr) -#define CPRINTS(format, args...) cprints(CC_CLOCK, format, ## args) - -#ifdef CONFIG_LOW_POWER_IDLE -#define SLEEP_SET_HTIMER_DELAY_USEC 250 -#define SLEEP_FTIMER_SKIP_USEC (HOOK_TICK_INTERVAL * 2) - -static timestamp_t sleep_mode_t0; -static timestamp_t sleep_mode_t1; -static int idle_doze_cnt; -static int idle_sleep_cnt; -static uint64_t total_idle_sleep_time_us; -static uint32_t ec_sleep; -/* - * Fixed amount of time to keep the console in use flag true after boot in - * order to give a permanent window in which the heavy sleep mode is not used. - */ -#define CONSOLE_IN_USE_ON_BOOT_TIME (15*SECOND) -static int console_in_use_timeout_sec = 5; -static timestamp_t console_expire_time; - -/* clock source is 32.768KHz */ -#define TIMER_32P768K_CNT_TO_US(cnt) ((uint64_t)(cnt) * 1000000 / 32768) -#define TIMER_CNT_8M_32P768K(cnt) (((cnt) / (8000000 / 32768)) + 1) -#endif /*CONFIG_LOW_POWER_IDLE */ - -static int freq; - -struct clock_gate_ctrl { - volatile uint8_t *reg; - uint8_t mask; -}; - -static void clock_module_disable(void) -{ - /* bit0: FSPI interface tri-state */ - IT83XX_SMFI_FLHCTRL3R |= BIT(0); - /* bit7: USB pad power-on disable */ - IT83XX_GCTRL_PMER2 &= ~BIT(7); - /* bit7: USB debug disable */ - IT83XX_GCTRL_MCCR &= ~BIT(7); - clock_disable_peripheral((CGC_OFFSET_EGPC | CGC_OFFSET_CIR), 0, 0); - clock_disable_peripheral((CGC_OFFSET_SMBA | CGC_OFFSET_SMBB | - CGC_OFFSET_SMBC | CGC_OFFSET_SMBD | CGC_OFFSET_SMBE | - CGC_OFFSET_SMBF), 0, 0); - clock_disable_peripheral((CGC_OFFSET_SSPI | CGC_OFFSET_PECI | - CGC_OFFSET_USB), 0, 0); -} - -enum pll_freq_idx { - PLL_24_MHZ = 1, - PLL_48_MHZ = 2, - PLL_96_MHZ = 4, -}; - -static const uint8_t pll_to_idx[8] = { - 0, - 0, - PLL_24_MHZ, - 0, - PLL_48_MHZ, - 0, - 0, - PLL_96_MHZ -}; - -struct clock_pll_t { - int pll_freq; - uint8_t pll_setting; - uint8_t div_fnd; - uint8_t div_uart; - uint8_t div_usb; - uint8_t div_smb; - uint8_t div_sspi; - uint8_t div_ec; - uint8_t div_jtag; - uint8_t div_pwm; - uint8_t div_usbpd; -}; - -const struct clock_pll_t clock_pll_ctrl[] = { - /* - * UART: 24MHz - * SMB: 24MHz - * EC: 8MHz - * JTAG: 24MHz - * USBPD: 8MHz - * USB: 48MHz(no support if PLL=24MHz) - * SSPI: 48MHz(24MHz if PLL=24MHz) - */ - /* PLL:24MHz, MCU:24MHz, Fnd(e-flash):24MHz */ - [PLL_24_MHZ] = {24000000, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0x2}, -#ifdef CONFIG_IT83XX_FLASH_CLOCK_48MHZ - /* PLL:48MHz, MCU:48MHz, Fnd:48MHz */ - [PLL_48_MHZ] = {48000000, 4, 0, 1, 0, 1, 0, 6, 1, 0, 0x5}, - /* PLL:96MHz, MCU:96MHz, Fnd:48MHz */ - [PLL_96_MHZ] = {96000000, 7, 1, 3, 1, 3, 1, 6, 3, 1, 0xb}, -#else - /* PLL:48MHz, MCU:48MHz, Fnd:24MHz */ - [PLL_48_MHZ] = {48000000, 4, 1, 1, 0, 1, 0, 2, 1, 0, 0x5}, - /* PLL:96MHz, MCU:96MHz, Fnd:32MHz */ - [PLL_96_MHZ] = {96000000, 7, 2, 3, 1, 3, 1, 4, 3, 1, 0xb}, -#endif -}; - -static uint8_t pll_div_fnd; -static uint8_t pll_div_ec; -static uint8_t pll_div_jtag; -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 - * 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 - /* - * WORKAROUND: this workaround is used to fix EC gets stuck in low power - * mode when WRST# is asserted. - * - * By default, flash will go into deep power down mode automatically - * when EC is in low power mode. But we got an issue on IT83202BX that - * flash won't be able to wake up correctly when WRST# is asserted - * under this condition. - * This issue might cause cold reset failure so we fix it. - * - * NOTE: this fix will increase power number about 40uA in low power - * mode. - */ - if (mode == EC_PLL_DOZE) - IT83XX_SMFI_SMECCS &= ~IT83XX_SMFI_MASK_HOSTWA; - else - /* - * Don't send deep power down mode command to flash when EC in - * low power mode. - */ - IT83XX_SMFI_SMECCS |= IT83XX_SMFI_MASK_HOSTWA; -#endif - /* - * barrier: ensure low power mode setting is taken into control - * register before standby instruction. - */ - data_serialization_barrier(); -} - -void __ram_code clock_pll_changed(void) -{ - IT83XX_GCTRL_SSCR &= ~BIT(0); - /* - * Update PLL settings. - * Writing data to this register doesn't change the - * PLL frequency immediately until the status is changed - * into wakeup from the sleep mode. - * The following code is intended to make the system - * enter sleep mode, and set up a HW timer to wakeup EC to - * complete PLL update. - */ - IT83XX_ECPM_PLLFREQR = pll_setting; - /* Pre-set FND clock frequency = PLL / 3 */ - IT83XX_ECPM_SCDCR0 = (2 << 4); - /* JTAG and EC */ - IT83XX_ECPM_SCDCR3 = (pll_div_jtag << 4) | pll_div_ec; - /* EC sleep after standby instruction */ - clock_ec_pll_ctrl(EC_PLL_SLEEP); - if (IS_ENABLED(CHIP_CORE_NDS32)) { - /* Global interrupt enable */ - asm volatile ("setgie.e"); - /* EC sleep */ - asm("standby wake_grant"); - /* Global interrupt disable */ - asm volatile ("setgie.d"); - } else if (IS_ENABLED(CHIP_CORE_RISCV)) { - /* Global interrupt enable */ - asm volatile ("csrsi mstatus, 0x8"); - /* EC sleep */ - asm("wfi"); - /* Global interrupt disable */ - asm volatile ("csrci mstatus, 0x8"); - } - /* New FND clock frequency */ - IT83XX_ECPM_SCDCR0 = (pll_div_fnd << 4); - /* EC doze after standby instruction */ - clock_ec_pll_ctrl(EC_PLL_DOZE); -} - -/* NOTE: Don't use this function in other place. */ -static void clock_set_pll(enum pll_freq_idx idx) -{ - int pll; - - pll_div_fnd = clock_pll_ctrl[idx].div_fnd; - pll_div_ec = clock_pll_ctrl[idx].div_ec; - pll_div_jtag = clock_pll_ctrl[idx].div_jtag; - pll_setting = clock_pll_ctrl[idx].pll_setting; - - /* Update PLL settings or not */ - if (((IT83XX_ECPM_PLLFREQR & 0xf) != pll_setting) || - ((IT83XX_ECPM_SCDCR0 & 0xf0) != (pll_div_fnd << 4)) || - ((IT83XX_ECPM_SCDCR3 & 0xf) != pll_div_ec)) { - /* Enable hw timer to wakeup EC from the sleep mode */ - ext_timer_ms(LOW_POWER_EXT_TIMER, EXT_PSR_32P768K_HZ, - 1, 1, 5, 1, 0); - task_clear_pending_irq(et_ctrl_regs[LOW_POWER_EXT_TIMER].irq); -#ifdef CONFIG_HOSTCMD_ESPI - /* - * Workaround for (b:70537592): - * We have to set chip select pin as input mode in order to - * change PLL. - */ - IT83XX_GPIO_GPCRM5 = (IT83XX_GPIO_GPCRM5 & ~0xc0) | BIT(7); -#ifdef IT83XX_ESPI_INHIBIT_CS_BY_PAD_DISABLED - /* - * On DX version, we have to disable eSPI pad before changing - * PLL sequence or sequence will fail if CS# pin is low. - */ - espi_enable_pad(0); -#endif -#endif - /* Update PLL settings. */ - clock_pll_changed(); -#ifdef CONFIG_HOSTCMD_ESPI -#ifdef IT83XX_ESPI_INHIBIT_CS_BY_PAD_DISABLED - /* Enable eSPI pad after changing PLL sequence. */ - espi_enable_pad(1); -#endif - /* (b:70537592) Change back to ESPI CS# function. */ - IT83XX_GPIO_GPCRM5 &= ~0xc0; -#endif - } - - /* Get new/current setting of PLL frequency */ - pll = pll_to_idx[IT83XX_ECPM_PLLFREQR & 0xf]; - /* USB and UART */ - IT83XX_ECPM_SCDCR1 = (clock_pll_ctrl[pll].div_usb << 4) | - clock_pll_ctrl[pll].div_uart; - /* SSPI and SMB */ - IT83XX_ECPM_SCDCR2 = (clock_pll_ctrl[pll].div_sspi << 4) | - clock_pll_ctrl[pll].div_smb; - /* USBPD and PWM */ - IT83XX_ECPM_SCDCR4 = (clock_pll_ctrl[pll].div_usbpd << 4) | - clock_pll_ctrl[pll].div_pwm; - /* Current PLL frequency */ - freq = clock_pll_ctrl[pll].pll_freq; -} - -void clock_init(void) -{ - uint32_t image_type = (uint32_t)clock_init; - - /* To change interrupt vector base if at RW image */ - if (image_type > CONFIG_RW_MEM_OFF) - /* Interrupt Vector Table Base Address, in 64k Byte unit */ - IT83XX_GCTRL_IVTBAR = (CONFIG_RW_MEM_OFF >> 16) & 0xFF; - -#if (PLL_CLOCK == 24000000) || \ - (PLL_CLOCK == 48000000) || \ - (PLL_CLOCK == 96000000) - /* Set PLL frequency */ - clock_set_pll(PLL_CLOCK / 24000000); -#else -#error "Support only for PLL clock speed of 24/48/96MHz." -#endif - /* - * The VCC power status is treated as power-on. - * The VCC supply of LPC and related functions (EC2I, - * KBC, SWUC, PMC, CIR, SSPI, UART, BRAM, and PECI). - * It means VCC (pin 11) should be logic high before using - * these functions, or firmware treats VCC logic high - * as following setting. - */ - IT83XX_GCTRL_RSTS = (IT83XX_GCTRL_RSTS & 0x3F) + 0x40; - -#if defined(IT83XX_ESPI_RESET_MODULE_BY_FW) && defined(CONFIG_HOSTCMD_ESPI) - /* - * Because we don't support eSPI HW reset function (b/111480168) on DX - * version, so we have to reset eSPI configurations during init to - * ensure Host and EC are synchronized (especially for the field of - * I/O mode) - */ - if (!system_jumped_to_this_image()) - espi_fw_reset_module(); -#endif - /* Turn off auto clock gating. */ - IT83XX_ECPM_AUTOCG = 0x00; - - /* Default doze mode */ - clock_ec_pll_ctrl(EC_PLL_DOZE); - - clock_module_disable(); - -#ifdef CONFIG_HOSTCMD_X86 - IT83XX_WUC_WUESR4 = BIT(2); - task_clear_pending_irq(IT83XX_IRQ_WKINTAD); - /* bit2, wake-up enable for LPC access */ - IT83XX_WUC_WUENR4 |= BIT(2); -#endif -} - -int clock_get_freq(void) -{ - return freq; -} - -/** - * Enable clock to specified peripheral - * - * @param offset Should be element of clock_gate_offsets enum. - * Bits 8-15 specify the ECPM offset of the specific clock reg. - * Bits 0-7 specify the mask for the clock register. - * @param mask Unused - * @param mode Unused - */ -void clock_enable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode) -{ - volatile uint8_t *reg = (volatile uint8_t *) - (IT83XX_ECPM_BASE + (offset >> 8)); - uint8_t reg_mask = offset & 0xff; - - /* - * Note: CGCTRL3R, bit 6, must always write 1, but since there is no - * offset argument that addresses this bit, then we are guaranteed - * that this line will write a 1 to that bit. - */ - *reg &= ~reg_mask; -} - -/** - * Disable clock to specified peripheral - * - * @param offset Should be element of clock_gate_offsets enum. - * Bits 8-15 specify the ECPM offset of the specific clock reg. - * Bits 0-7 specify the mask for the clock register. - * @param mask Unused - * @param mode Unused - */ -void clock_disable_peripheral(uint32_t offset, uint32_t mask, uint32_t mode) -{ - volatile uint8_t *reg = (volatile uint8_t *) - (IT83XX_ECPM_BASE + (offset >> 8)); - uint8_t reg_mask = offset & 0xff; - uint8_t tmp_mask = 0; - - /* CGCTRL3R, bit 6, must always write a 1. */ - tmp_mask |= ((offset >> 8) == IT83XX_ECPM_CGCTRL3R_OFF) ? 0x40 : 0x00; - - *reg |= reg_mask | tmp_mask; -} - -#ifdef CONFIG_LOW_POWER_IDLE -void clock_refresh_console_in_use(void) -{ - /* Set console in use expire time. */ - console_expire_time = get_time(); - console_expire_time.val += console_in_use_timeout_sec * SECOND; -} - -static void clock_event_timer_clock_change(enum ext_timer_clock_source clock, - uint32_t count) -{ - IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) &= ~BIT(0); - IT83XX_ETWD_ETXPSR(EVENT_EXT_TIMER) = clock; - IT83XX_ETWD_ETXCNTLR(EVENT_EXT_TIMER) = count; - IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) |= 0x3; -} - -static void clock_htimer_enable(void) -{ - uint32_t c; - - /* change event timer clock source to 32.768 KHz */ -#ifdef IT83XX_EXT_OBSERVATION_REG_READ_TWO_TIMES - c = TIMER_CNT_8M_32P768K(ext_observation_reg_read(EVENT_EXT_TIMER)); -#else - c = TIMER_CNT_8M_32P768K(IT83XX_ETWD_ETXCNTOR(EVENT_EXT_TIMER)); -#endif - clock_event_timer_clock_change(EXT_PSR_32P768K_HZ, c); -} - -static int clock_allow_low_power_idle(void) -{ - /* - * Avoiding using low frequency clock run the same count as awaken in - * sleep mode, so don't go to sleep mode before timer reload count. - */ - if (!(IT83XX_ETWD_ETXCTRL(EVENT_EXT_TIMER) & BIT(0))) - return 0; - - /* If timer interrupt status is set, don't go to sleep mode. */ - if (*et_ctrl_regs[EVENT_EXT_TIMER].isr & - et_ctrl_regs[EVENT_EXT_TIMER].mask) - return 0; - - /* - * If timer is less than 250us to expire, then we don't go to sleep - * mode. - */ -#ifdef IT83XX_EXT_OBSERVATION_REG_READ_TWO_TIMES - if (EVENT_TIMER_COUNT_TO_US(ext_observation_reg_read(EVENT_EXT_TIMER)) < -#else - if (EVENT_TIMER_COUNT_TO_US(IT83XX_ETWD_ETXCNTOR(EVENT_EXT_TIMER)) < -#endif - SLEEP_SET_HTIMER_DELAY_USEC) - return 0; - - /* - * We calculate 32bit free clock overflow counts for 64bit value, - * if clock almost reach overflow, we don't go to sleep mode for - * avoiding miss overflow count. - */ - sleep_mode_t0 = get_time(); - if ((sleep_mode_t0.le.lo > (0xffffffff - SLEEP_FTIMER_SKIP_USEC)) || - (sleep_mode_t0.le.lo < SLEEP_FTIMER_SKIP_USEC)) - return 0; - - /* If we are waked up by console, then keep awake at least 5s. */ - if (sleep_mode_t0.val < console_expire_time.val) - return 0; - - return 1; -} - -int clock_ec_wake_from_sleep(void) -{ - return ec_sleep; -} - -void __ram_code clock_cpu_standby(void) -{ - /* standby instruction */ - if (IS_ENABLED(CHIP_CORE_NDS32)) { - asm("standby wake_grant"); - } else if (IS_ENABLED(CHIP_CORE_RISCV)) { - if (!IS_ENABLED(IT83XX_RISCV_WAKEUP_CPU_WITHOUT_INT_ENABLED)) - /* - * we have to enable interrupts before - * standby instruction on IT83202 bx version. - */ - interrupt_enable(); - - asm("wfi"); - } -} - -void __enter_hibernate(uint32_t seconds, uint32_t microseconds) -{ - int i; - - /* disable all interrupts */ - interrupt_disable(); - for (i = 0; i < IT83XX_IRQ_COUNT; i++) { - chip_disable_irq(i); - chip_clear_pending_irq(i); - } - /* bit5: watchdog is disabled. */ - IT83XX_ETWD_ETWCTRL |= BIT(5); - - /* - * Setup GPIOs for hibernate. On some boards, it's possible that this - * may not return at all. On those boards, power to the EC is likely - * being turn off entirely. - */ - if (board_hibernate_late) { - /* - * Set reset flag in case board_hibernate_late() doesn't - * return. - */ - chip_save_reset_flags(EC_RESET_FLAG_HIBERNATE); - board_hibernate_late(); - } - - if (seconds || microseconds) { - /* At least 1 ms for hibernate. */ - uint64_t c = (seconds * 1000 + microseconds / 1000 + 1) * 1024; - - uint64divmod(&c, 1000); - /* enable a 56-bit timer and clock source is 1.024 KHz */ - ext_timer_stop(FREE_EXT_TIMER_L, 1); - ext_timer_stop(FREE_EXT_TIMER_H, 1); - IT83XX_ETWD_ETXPSR(FREE_EXT_TIMER_L) = EXT_PSR_1P024K_HZ; - IT83XX_ETWD_ETXPSR(FREE_EXT_TIMER_H) = EXT_PSR_1P024K_HZ; - IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_L) = c & 0xffffff; - IT83XX_ETWD_ETXCNTLR(FREE_EXT_TIMER_H) = (c >> 24) & 0xffffffff; - ext_timer_start(FREE_EXT_TIMER_H, 1); - ext_timer_start(FREE_EXT_TIMER_L, 0); - } - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_ITE_ON_CHIP)) { - /* - * Disable active cc and pd modules and only left Rd_5.1k (Not - * Rd_DB) alive in hibernate for better power consumption. - */ - for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; i++) - it83xx_Rd_5_1K_only_for_hibernate(i); - } - - if (IS_ENABLED(CONFIG_ADC_VOLTAGE_COMPARATOR)) { - /* - * Disable all voltage comparator modules in hibernate - * for better power consumption. - */ - for (i = CHIP_VCMP0; i < CHIP_VCMP_COUNT; i++) - vcmp_enable(i, 0); - } - - for (i = 0; i < hibernate_wake_pins_used; ++i) - gpio_enable_interrupt(hibernate_wake_pins[i]); - - /* EC sleep */ - ec_sleep = 1; -#if defined(IT83XX_ESPI_INHIBIT_CS_BY_PAD_DISABLED) && \ -defined(CONFIG_HOSTCMD_ESPI) - /* Disable eSPI pad. */ - espi_enable_pad(0); -#endif - clock_ec_pll_ctrl(EC_PLL_SLEEP); - interrupt_enable(); - /* standby instruction */ - clock_cpu_standby(); - - /* we should never reach that point */ - __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) && \ -defined(CONFIG_HOSTCMD_ESPI) - /* - * Enable eSPI pad. - * We will not need to enable eSPI pad here if Dx is able to - * enable watchdog hardware reset function. But the function is - * failed (b:111264984), so the following system reset is - * software reset (PLL setting is not reset). - * We will not go into the change PLL sequence on reboot if PLL - * setting is the same, so the operation of enabling eSPI pad we - * added in clock_set_pll() will not be applied. - */ - espi_enable_pad(1); -#endif - system_reset(SYSTEM_RESET_HARD); - } - - if (IT83XX_ECPM_PLLCTRL == EC_PLL_DEEP_DOZE) { - clock_ec_pll_ctrl(EC_PLL_DOZE); - /* update free running timer */ - c = LOW_POWER_TIMER_MASK - - IT83XX_ETWD_ETXCNTOR(LOW_POWER_EXT_TIMER); - st_us = TIMER_32P768K_CNT_TO_US(c); - sleep_mode_t1.val = sleep_mode_t0.val + st_us; - __hw_clock_source_set(sleep_mode_t1.le.lo); - - /* reset event timer and clock source is 8 MHz */ - clock_event_timer_clock_change(EXT_PSR_8M_HZ, 0xffffffff); - task_clear_pending_irq(et_ctrl_regs[EVENT_EXT_TIMER].irq); - process_timers(0); -#ifdef CONFIG_HOSTCMD_X86 - /* disable lpc access wui */ - task_disable_irq(IT83XX_IRQ_WKINTAD); - IT83XX_WUC_WUESR4 = BIT(2); - task_clear_pending_irq(IT83XX_IRQ_WKINTAD); -#endif - /* disable uart wui */ - uart_exit_dsleep(); - /* Record time spent in sleep. */ - total_idle_sleep_time_us += st_us; - } -} - -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 */ - ext_timer_ms(LOW_POWER_EXT_TIMER, EXT_PSR_32P768K_HZ, 1, 0, - 0xffffffff, 1, 1); - - /* - * Print when the idle task starts. This is the lowest priority task, - * so this only starts once all other tasks have gotten a chance to do - * 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 */ - interrupt_disable(); - /* Check if the EC can enter deep doze mode or not */ - if (DEEP_SLEEP_ALLOWED && clock_allow_low_power_idle()) { - /* reset low power mode hw timer */ - IT83XX_ETWD_ETXCTRL(LOW_POWER_EXT_TIMER) |= BIT(1); - sleep_mode_t0 = get_time(); -#ifdef CONFIG_HOSTCMD_X86 - /* enable lpc access wui */ - task_enable_irq(IT83XX_IRQ_WKINTAD); -#endif - /* enable uart wui */ - uart_enter_dsleep(); - /* enable hw timer for deep doze / sleep mode wake-up */ - clock_htimer_enable(); - /* deep doze mode */ - clock_ec_pll_ctrl(EC_PLL_DEEP_DOZE); - idle_sleep_cnt++; - } else { - /* doze mode */ - 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 */ - -#ifdef CONFIG_LOW_POWER_IDLE -#ifdef CONFIG_CMD_IDLE_STATS -/** - * Print low power idle statistics - */ -static int command_idle_stats(int argc, char **argv) -{ - timestamp_t ts = get_time(); - - ccprintf("Num idle calls that doze: %d\n", idle_doze_cnt); - ccprintf("Num idle calls that sleep: %d\n", idle_sleep_cnt); - - ccprintf("Total Time spent in sleep(sec): %.6lld(s)\n", - total_idle_sleep_time_us); - ccprintf("Total time on: %.6llds\n\n", ts.val); - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(idlestats, command_idle_stats, - "", - "Print last idle stats"); - -#endif /* CONFIG_CMD_IDLE_STATS */ -#endif /* CONFIG_LOW_POWER_IDLE */ |