blob: 648e5cb39ce7ef93f5abaa4ced814ae0d0fdeb68 [file] [log] [blame]
/*
* Copyright (c) 2025 ITE Corporation. All Rights Reserved.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <soc_common.h>
#include <zephyr/kernel.h>
#include "soc_espi.h"
static mm_reg_t ecpm_base = DT_REG_ADDR(DT_NODELABEL(ecpm));
/* it51xxx ECPM registers definition */
/* 0x03: PLL Control */
#define ECPM_PLLCTRL 0x03
void chip_pll_ctrl(enum chip_pll_mode mode)
{
volatile uint8_t _pll_ctrl __unused;
sys_write8(mode, ecpm_base + ECPM_PLLCTRL);
/*
* for deep doze / sleep mode
* This load operation will ensure PLL setting is taken into
* control register before wait for interrupt instruction.
*/
_pll_ctrl = sys_read8(ecpm_base + ECPM_PLLCTRL);
}
#ifdef CONFIG_SOC_IT51XXX_CPU_IDLE_GATING
/* Preventing CPU going into idle mode during command queue. */
static atomic_t cpu_idle_disabled;
void chip_permit_idle(void)
{
atomic_dec(&cpu_idle_disabled);
}
void chip_block_idle(void)
{
atomic_inc(&cpu_idle_disabled);
}
bool cpu_idle_not_allowed(void)
{
return atomic_get(&cpu_idle_disabled);
}
#endif
/* The routine must be called with interrupts locked */
void riscv_idle(enum chip_pll_mode mode, unsigned int key)
{
/*
* The routine is called with interrupts locked (in kernel/idle()).
* But on kernel/context test_kernel_cpu_idle test, the routine will be
* called without interrupts locked. Hence we disable M-mode external
* interrupt here to protect the below content.
*/
csr_clear(mie, MIP_MEIP);
sys_trace_idle();
#ifdef CONFIG_ESPI
/*
* H2RAM feature requires RAM clock to be active. Since the below doze
* mode will disable CPU and RAM clocks, enable eSPI transaction
* interrupt to restore clocks. With this interrupt, EC will not defer
* eSPI bus while transaction is accepted.
*/
espi_ite_ec_enable_trans_irq(ESPI_ITE_SOC_DEV, true);
#endif
/* Chip doze after wfi instruction */
chip_pll_ctrl(mode);
/* Wait for interrupt */
__asm__ volatile("wfi");
#ifdef CONFIG_ESPI
/* CPU has been woken up, the interrupt is no longer needed */
espi_ite_ec_enable_trans_irq(ESPI_ITE_SOC_DEV, false);
#endif
/*
* Enable M-mode external interrupt
* An interrupt can not be fired yet until we enable global interrupt
*/
csr_set(mie, MIP_MEIP);
/* Restore global interrupt lockout state */
irq_unlock(key);
}
void arch_cpu_idle(void)
{
#ifdef CONFIG_SOC_IT51XXX_CPU_IDLE_GATING
/*
* The EC processor(CPU) cannot be in the k_cpu_idle() during
* the transactions with the CQ mode(DMA mode). Otherwise,
* the EC processor would be clock gated.
*/
if (cpu_idle_not_allowed()) {
/* Restore global interrupt lockout state */
irq_unlock(MSTATUS_IEN);
} else {
#endif
riscv_idle(CHIP_PLL_DOZE, MSTATUS_IEN);
#ifdef CONFIG_SOC_IT51XXX_CPU_IDLE_GATING
}
#endif
}
void arch_cpu_atomic_idle(unsigned int key)
{
riscv_idle(CHIP_PLL_DOZE, key);
}
void soc_prep_hook(void)
{
struct gpio_ite_ec_regs *const gpio_regs = GPIO_ITE_EC_REGS_BASE;
struct gctrl_ite_ec_regs *const gctrl_regs = GCTRL_ITE_EC_REGS_BASE;
/* USB pull down disable */
gpio_regs->GPIO_GCR35 &= ~IT51XXX_GPIO_USBPDEN;
/* Set FSPI pins are tri-state */
sys_write8(sys_read8(IT51XXX_SMFI_FLHCTRL3R) | IT51XXX_SMFI_FFSPITRI,
IT51XXX_SMFI_FLHCTRL3R);
/* Scratch SRAM0 uses the 4KB based form 0x801000h */
gctrl_regs->GCTRL_SCR0BAR = IT51XXX_SEL_SRAM0_BASE_4K;
/* bit4: wake up CPU if it is in low power mode and an interrupt is pending. */
gctrl_regs->GCTRL_SPCTRL9 |= IT51XXX_GCTRL_ALTIE;
/* UART1 and UART2 board init */
/* bit3: UART1 and UART2 belong to the EC side. */
gctrl_regs->GCTRL_RSTDMMC |= IT51XXX_GCTRL_UART1SD | IT51XXX_GCTRL_UART2SD;
/* Reset UART before config it */
gctrl_regs->GCTRL_RSTC4 = IT51XXX_GCTRL_RUART;
/* Switch UART1 and UART2 on without hardware flow control */
gpio_regs->GPIO_GCR1 |=
IT51XXX_GPIO_U1CTRL_SIN0_SOUT0_EN | IT51XXX_GPIO_U2CTRL_SIN1_SOUT1_EN;
/*
* Disable this feature that can detect pre-define hardware target A, B, C through
* I2C0, I2C1, I2C2 respectively. This is for debugging use, so it can be disabled
* to avoid illegal access.
*/
sys_write8(sys_read8(SMB_SADFPCTL) & ~SMB_HSAPE, SMB_SADFPCTL);
sys_write8(sys_read8(SMB_SBDFPCTL) & ~SMB_HSAPE, SMB_SBDFPCTL);
sys_write8(sys_read8(SMB_SCDFPCTL) & ~SMB_HSAPE, SMB_SCDFPCTL);
}