Skip to content

Commit 41c9b71

Browse files
GTLin08carlescufi
authored andcommitted
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 <[email protected]>
1 parent d5520f2 commit 41c9b71

File tree

4 files changed

+59
-2
lines changed

4 files changed

+59
-2
lines changed

drivers/interrupt_controller/intc_ite_it8xxx2.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ uint8_t get_irq(void *arg)
198198
intc_irq -= IVECT_OFFSET_WITH_IRQ;
199199
/* clear interrupt status */
200200
ite_intc_isr_clear(intc_irq);
201+
/* Clear flag on each interrupt. */
202+
wait_interrupt_fired = 0;
201203
/* return interrupt number */
202204
return intc_irq;
203205
}

drivers/interrupt_controller/intc_ite_it8xxx2.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,7 @@
99
#include <dt-bindings/interrupt-controller/ite-intc.h>
1010
#include <soc.h>
1111

12+
/* use data type int here not bool to get better instruction number. */
13+
volatile int wait_interrupt_fired;
14+
1215
#endif /* ZEPHYR_DRIVERS_INTERRUPT_CONTROLLER_INTC_ITE_IT8XXX2_H_ */

soc/riscv/riscv-ite/it8xxx2/Kconfig.defconfig.series

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ config UART_NS16550_WA_ISR_REENABLE_INTERRUPT
2323
default y
2424
depends on UART_NS16550
2525

26+
config RISCV_HAS_CPU_IDLE
27+
default y
28+
2629
if ITE_IT8XXX2_INTC
2730
config NUM_IRQS
2831
default 185

soc/riscv/riscv-ite/it8xxx2/soc.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*
66
*/
77

8+
#include <arch/riscv/csr.h>
89
#include <kernel.h>
910
#include <device.h>
1011
#include <init.h>
@@ -51,9 +52,15 @@ static const struct pll_config_t pll_configuration[] = {
5152

5253
void __intc_ram_code chip_pll_ctrl(enum chip_pll_mode mode)
5354
{
55+
volatile uint8_t _pll_ctrl __unused;
56+
5457
IT8XXX2_ECPM_PLLCTRL = mode;
55-
/* for deep doze / sleep mode */
56-
IT8XXX2_ECPM_PLLCTRL = mode;
58+
/*
59+
* for deep doze / sleep mode
60+
* This load operation will ensure PLL setting is taken into
61+
* control register before wait for interrupt instruction.
62+
*/
63+
_pll_ctrl = IT8XXX2_ECPM_PLLCTRL;
5764
}
5865

5966
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)
132139
SYS_INIT(chip_change_pll, POST_KERNEL, 0);
133140
#endif /* CONFIG_SOC_IT8XXX2_PLL_FLASH_48M */
134141

142+
extern volatile int wait_interrupt_fired;
143+
144+
static ALWAYS_INLINE void riscv_idle(unsigned int key)
145+
{
146+
/* Disable M-mode external interrupt */
147+
csr_clear(mie, MIP_MEIP);
148+
149+
sys_trace_idle();
150+
/* Chip doze after wfi instruction */
151+
chip_pll_ctrl(CHIP_PLL_DOZE);
152+
/* Set flag before entering low power mode. */
153+
wait_interrupt_fired = 1;
154+
/* unlock interrupts */
155+
irq_unlock(key);
156+
/* Wait for interrupt */
157+
__asm__ volatile ("wfi");
158+
159+
/* Enable M-mode external interrupt */
160+
csr_set(mie, MIP_MEIP);
161+
/*
162+
* Sometimes wfi instruction may fail due to CPU's MTIP@mip
163+
* register is non-zero.
164+
* If the wait_interrupt_fired flag is true at this point,
165+
* it means that EC waked-up by the above issue not an
166+
* interrupt. Hence we loop running wfi instruction here until
167+
* wfi success.
168+
*/
169+
while (wait_interrupt_fired) {
170+
__asm__ volatile ("wfi");
171+
}
172+
}
173+
174+
void arch_cpu_idle(void)
175+
{
176+
riscv_idle(MSTATUS_IEN);
177+
}
178+
179+
void arch_cpu_atomic_idle(unsigned int key)
180+
{
181+
riscv_idle(key);
182+
}
183+
135184
static int ite_it8xxx2_init(const struct device *arg)
136185
{
137186
ARG_UNUSED(arg);

0 commit comments

Comments
 (0)