ITE: soc: add cpu idle task
Implement the CPU idle task. The system should enter this task when there is no any task to ensure power saving. Tested on it8xxx2_evb board. It will reduce 12.5mA when system enters the CPU idle task. Signed-off-by: Tim Lin <tim2.lin@ite.corp-partner.google.com>
This commit is contained in:
parent
d5520f2e59
commit
41c9b71450
4 changed files with 59 additions and 2 deletions
|
@ -198,6 +198,8 @@ uint8_t get_irq(void *arg)
|
|||
intc_irq -= IVECT_OFFSET_WITH_IRQ;
|
||||
/* clear interrupt status */
|
||||
ite_intc_isr_clear(intc_irq);
|
||||
/* Clear flag on each interrupt. */
|
||||
wait_interrupt_fired = 0;
|
||||
/* return interrupt number */
|
||||
return intc_irq;
|
||||
}
|
||||
|
|
|
@ -9,4 +9,7 @@
|
|||
#include <dt-bindings/interrupt-controller/ite-intc.h>
|
||||
#include <soc.h>
|
||||
|
||||
/* use data type int here not bool to get better instruction number. */
|
||||
volatile int wait_interrupt_fired;
|
||||
|
||||
#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_ITE_IT8XXX2_H_ */
|
||||
|
|
|
@ -23,6 +23,9 @@ config UART_NS16550_WA_ISR_REENABLE_INTERRUPT
|
|||
default y
|
||||
depends on UART_NS16550
|
||||
|
||||
config RISCV_HAS_CPU_IDLE
|
||||
default y
|
||||
|
||||
if ITE_IT8XXX2_INTC
|
||||
config NUM_IRQS
|
||||
default 185
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <arch/riscv/csr.h>
|
||||
#include <kernel.h>
|
||||
#include <device.h>
|
||||
#include <init.h>
|
||||
|
@ -51,9 +52,15 @@ static const struct pll_config_t pll_configuration[] = {
|
|||
|
||||
void __intc_ram_code chip_pll_ctrl(enum chip_pll_mode mode)
|
||||
{
|
||||
volatile uint8_t _pll_ctrl __unused;
|
||||
|
||||
IT8XXX2_ECPM_PLLCTRL = mode;
|
||||
/* for deep doze / sleep mode */
|
||||
IT8XXX2_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 = IT8XXX2_ECPM_PLLCTRL;
|
||||
}
|
||||
|
||||
void __intc_ram_code chip_run_pll_sequence(const struct pll_config_t *pll)
|
||||
|
@ -132,6 +139,48 @@ static int chip_change_pll(const struct device *dev)
|
|||
SYS_INIT(chip_change_pll, POST_KERNEL, 0);
|
||||
#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */
|
||||
|
||||
extern volatile int wait_interrupt_fired;
|
||||
|
||||
static ALWAYS_INLINE void riscv_idle(unsigned int key)
|
||||
{
|
||||
/* Disable M-mode external interrupt */
|
||||
csr_clear(mie, MIP_MEIP);
|
||||
|
||||
sys_trace_idle();
|
||||
/* Chip doze after wfi instruction */
|
||||
chip_pll_ctrl(CHIP_PLL_DOZE);
|
||||
/* Set flag before entering low power mode. */
|
||||
wait_interrupt_fired = 1;
|
||||
/* unlock interrupts */
|
||||
irq_unlock(key);
|
||||
/* Wait for interrupt */
|
||||
__asm__ volatile ("wfi");
|
||||
|
||||
/* Enable M-mode external interrupt */
|
||||
csr_set(mie, MIP_MEIP);
|
||||
/*
|
||||
* 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 (wait_interrupt_fired) {
|
||||
__asm__ volatile ("wfi");
|
||||
}
|
||||
}
|
||||
|
||||
void arch_cpu_idle(void)
|
||||
{
|
||||
riscv_idle(MSTATUS_IEN);
|
||||
}
|
||||
|
||||
void arch_cpu_atomic_idle(unsigned int key)
|
||||
{
|
||||
riscv_idle(key);
|
||||
}
|
||||
|
||||
static int ite_it8xxx2_init(const struct device *arg)
|
||||
{
|
||||
ARG_UNUSED(arg);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue