Skip to content

Commit 523b567

Browse files
ananglrlubos
authored andcommitted
[nrf fromtree] arch: arm: aarch32: Introduce z_arm_on_enter_cpu_idle() hook
Introduce an optional hook to be called when the CPU is made idle. If needed, this hook can be used to prevent the CPU from actually entering sleep by skipping the WFE/WFI instruction. Signed-off-by: Andrzej Głąbek <[email protected]> (cherry picked from commit 22b17e4)
1 parent c1f0438 commit 523b567

File tree

3 files changed

+47
-9
lines changed

3 files changed

+47
-9
lines changed

arch/arm/Kconfig

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,14 @@ config CODE_DATA_RELOCATION_SRAM
5454
config is used to create an MPU entry for the SRAM space used for code
5555
relocation.
5656

57+
config ARM_ON_ENTER_CPU_IDLE_HOOK
58+
bool
59+
help
60+
Enables a hook (z_arm_on_enter_cpu_idle()) that is called when
61+
the CPU is made idle (by k_cpu_idle() or k_cpu_atomic_idle()).
62+
If needed, this hook can be used to prevent the CPU from actually
63+
entering sleep by skipping the WFE/WFI instruction.
64+
5765
rsource "core/aarch32/Kconfig"
5866
rsource "core/aarch32/Kconfig.vfp"
5967

arch/arm/core/aarch32/cpu_idle.S

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,33 @@ SECTION_FUNC(TEXT, z_arm_cpu_idle_init)
4848
#endif
4949
bx lr
5050

51+
.macro _sleep_if_allowed wait_instruction
52+
#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK)
53+
push {r0, lr}
54+
bl z_arm_on_enter_cpu_idle
55+
/* Skip the wait instruction if on_enter_cpu_idle() returns false. */
56+
cmp r0, #0
57+
beq _skip_\@
58+
#endif /* CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK */
59+
60+
/*
61+
* Wait for all memory transactions to complete before entering low
62+
* power state.
63+
*/
64+
dsb
65+
\wait_instruction
66+
67+
#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK)
68+
_skip_\@:
69+
#if defined(CONFIG_ARMV6_M_ARMV8_M_BASELINE)
70+
pop {r0, r1}
71+
mov lr, r1
72+
#else
73+
pop {r0, lr}
74+
#endif /* CONFIG_ARMV6_M_ARMV8_M_BASELINE */
75+
#endif /* CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK */
76+
.endm
77+
5178
SECTION_FUNC(TEXT, arch_cpu_idle)
5279
#ifdef CONFIG_TRACING
5380
push {r0, lr}
@@ -89,14 +116,8 @@ SECTION_FUNC(TEXT, arch_cpu_idle)
89116
*/
90117
#endif /* CONFIG_ARMV7_M_ARMV8_M_MAINLINE */
91118

92-
/*
93-
* Wait for all memory transactions to complete before entering low
94-
* power state.
95-
*/
96-
dsb
97-
98119
/* Enter low power state */
99-
wfi
120+
_sleep_if_allowed wfi
100121

101122
/*
102123
* Clear PRIMASK and flush instruction buffer to immediately service
@@ -139,7 +160,7 @@ SECTION_FUNC(TEXT, arch_cpu_atomic_idle)
139160
/* No BASEPRI, call wfe directly
140161
* (SEVONPEND is set in z_arm_cpu_idle_init())
141162
*/
142-
wfe
163+
_sleep_if_allowed wfe
143164

144165
cmp r0, #0
145166
bne _irq_disabled
@@ -153,7 +174,7 @@ _irq_disabled:
153174
/* unlock BASEPRI so wfe gets interrupted by incoming interrupts */
154175
msr BASEPRI, r1
155176

156-
wfe
177+
_sleep_if_allowed wfe
157178

158179
msr BASEPRI, r0
159180
cpsie i

include/zephyr/arch/arm/aarch32/misc.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,15 @@ static ALWAYS_INLINE void arch_nop(void)
4242
extern bool z_arm_thread_is_in_user_mode(void);
4343
#endif
4444

45+
#if defined(CONFIG_ARM_ON_ENTER_CPU_IDLE_HOOK)
46+
/* Prototype of a hook that can be enabled to be called every time the CPU is
47+
* made idle (the calls will be done from k_cpu_idle() and k_cpu_atomic_idle()).
48+
* If this hook returns false, the CPU is prevented from entering the actual
49+
* sleep (the WFE/WFI instruction is skipped).
50+
*/
51+
bool z_arm_on_enter_cpu_idle(void);
52+
#endif
53+
4554
#endif
4655

4756
#ifdef __cplusplus

0 commit comments

Comments
 (0)