zephyr/arch/arm/core/cpu_idle.S

204 lines
4.1 KiB
ArmAsm
Raw Normal View History

/*
* Copyright (c) 2013-2014 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/**
* @file
* @brief ARM Cortex-M power management
*
*/
kernel/arch: consolidate tTCS and TNANO definitions There was a lot of duplication between architectures for the definition of threads and the "nanokernel" guts. These have been consolidated. Now, a common file kernel/unified/include/kernel_structs.h holds the common definitions. Architectures provide two files to complement it: kernel_arch_data.h and kernel_arch_func.h. The first one contains at least the struct _thread_arch and struct _kernel_arch data structures, as well as the struct _callee_saved and struct _caller_saved register layouts. The second file contains anything that needs what is provided by the common stuff in kernel_structs.h. Those two files are only meant to be included in kernel_structs.h in very specific locations. The thread data structure has been separated into three major parts: common struct _thread_base and struct k_thread, and arch-specific struct _thread_arch. The first and third ones are included in the second. The struct s_NANO data structure has been split into two: common struct _kernel and arch-specific struct _kernel_arch. The latter is included in the former. Offsets files have also changed: nano_offsets.h has been renamed kernel_offsets.h and is still included by the arch-specific offsets.c. Also, since the thread and kernel data structures are now made of sub-structures, offsets have to be added to make up the full offset. Some of these additions have been consolidated in shorter symbols, available from kernel/unified/include/offsets_short.h, which includes an arch-specific offsets_arch_short.h. Most of the code include offsets_short.h now instead of offsets.h. Change-Id: I084645cb7e6db8db69aeaaf162963fe157045d5a Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
2016-11-08 10:36:50 -05:00
#include <offsets_short.h>
#include <toolchain.h>
#include <sections.h>
#include <arch/cpu.h>
#ifdef CONFIG_TICKLESS_IDLE
kernel/arch: consolidate tTCS and TNANO definitions There was a lot of duplication between architectures for the definition of threads and the "nanokernel" guts. These have been consolidated. Now, a common file kernel/unified/include/kernel_structs.h holds the common definitions. Architectures provide two files to complement it: kernel_arch_data.h and kernel_arch_func.h. The first one contains at least the struct _thread_arch and struct _kernel_arch data structures, as well as the struct _callee_saved and struct _caller_saved register layouts. The second file contains anything that needs what is provided by the common stuff in kernel_structs.h. Those two files are only meant to be included in kernel_structs.h in very specific locations. The thread data structure has been separated into three major parts: common struct _thread_base and struct k_thread, and arch-specific struct _thread_arch. The first and third ones are included in the second. The struct s_NANO data structure has been split into two: common struct _kernel and arch-specific struct _kernel_arch. The latter is included in the former. Offsets files have also changed: nano_offsets.h has been renamed kernel_offsets.h and is still included by the arch-specific offsets.c. Also, since the thread and kernel data structures are now made of sub-structures, offsets have to be added to make up the full offset. Some of these additions have been consolidated in shorter symbols, available from kernel/unified/include/offsets_short.h, which includes an arch-specific offsets_arch_short.h. Most of the code include offsets_short.h now instead of offsets.h. Change-Id: I084645cb7e6db8db69aeaaf162963fe157045d5a Signed-off-by: Benjamin Walsh <benjamin.walsh@windriver.com>
2016-11-08 10:36:50 -05:00
#include <kernel_structs.h>
#endif
_ASM_FILE_PROLOGUE
GTEXT(_CpuIdleInit)
#ifdef CONFIG_SYS_POWER_MANAGEMENT
GTEXT(_NanoIdleValGet)
GTEXT(_NanoIdleValClear)
#endif
GTEXT(k_cpu_idle)
GTEXT(k_cpu_atomic_idle)
#define _SCB_SCR 0xE000ED10
#define _SCB_SCR_SEVONPEND (1 << 4)
#define _SCB_SCR_SLEEPDEEP (1 << 2)
#define _SCB_SCR_SLEEPONEXIT (1 << 1)
#define _SCR_INIT_BITS _SCB_SCR_SEVONPEND
/**
*
* @brief Initialization of CPU idle
*
* Only called by kernel_arch_init(). Sets SEVONPEND bit once for the system's
* duration.
*
* @return N/A
*
* C function prototype:
*
* void _CpuIdleInit (void);
*/
SECTION_FUNC(TEXT, _CpuIdleInit)
ldr r1, =_SCB_SCR
movs.n r2, #_SCR_INIT_BITS
str r2, [r1]
bx lr
#ifdef CONFIG_SYS_POWER_MANAGEMENT
/**
*
* @brief Get the kernel idle setting
*
* Returns the kernel idle setting, in ticks. Only called by __systick().
*
* @return the requested number of ticks for the kernel to be idle
*
* C function prototype:
*
* s32_t _NanoIdleValGet (void);
*/
SECTION_FUNC(TEXT, _NanoIdleValGet)
ldr r0, =_kernel
ldr r0, [r0, #_kernel_offset_to_idle]
bx lr
/**
*
* @brief Clear the kernel idle setting
*
* Sets the kernel idle setting to 0. Only called by __systick().
*
* @return N/A
*
* C function prototype:
*
* void _NanoIdleValClear (void);
*/
SECTION_FUNC(TEXT, _NanoIdleValClear)
ldr r0, =_kernel
eors.n r1, r1
str r1, [r0, #_kernel_offset_to_idle]
bx lr
#endif /* CONFIG_SYS_POWER_MANAGEMENT */
/**
*
* @brief Power save idle routine for ARM Cortex-M
*
* This function will be called by the kernel idle loop or possibly within
* an implementation of _sys_power_save_idle in the kernel when the
* '_sys_power_save_flag' variable is non-zero. The ARM 'wfi' instruction
* will be issued, causing a low-power consumption sleep mode.
*
* @return N/A
*
* C function prototype:
*
* void k_cpu_idle (void);
*/
SECTION_FUNC(TEXT, k_cpu_idle)
#ifdef CONFIG_KERNEL_EVENT_LOGGER_SLEEP
push {lr}
bl _sys_k_event_logger_enter_sleep
pop {r0}
mov lr, r0
#endif
#if defined(CONFIG_ARMV6_M)
cpsie i
#elif defined(CONFIG_ARMV7_M)
/* clear BASEPRI so wfi is awakened by incoming interrupts */
eors.n r0, r0
msr BASEPRI, r0
arm: Restructure ARM cpu related preprocessor conditionals. The ARM code base provides for three mutually exclusive ARM architecture related conditional compilation choices. M0_M0PLUS, M3_M4 and M7. Throughout the code base we have conditional compilation gated around these three choices. Adjust the form of this conditional compilation to adopt a uniform structure. The uniform structure always selects code based on the definition of an appropriate config option rather the the absence of a definition. Removing the extensive use of #else ensures that when support for other ARM architecture versions is added we get hard compilation failures rather than attempting to compile inappropriate code for the added architecture with unexpected runtime consequences. Adopting this uniform structure makes it straight forward to replace the adhoc CPU_CORTEX_M3_M4 and CPU_CORTEX_M0_M0PLUS configuration variables with ones that directly represent the actual underlying ARM architectures we provide support for. This change also paves the way for folding adhoc conditional compilation related to CPU_CORTEX_M7 directly in support for ARMv7-M. This change is mechanical in nature involving two transforms: 1) #if !defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... is transformed to: #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) #elif defined(CONFIG_CPU_CORTEX_M3_M4) || defined(CONFIG_CPU_CORTEX_M7) ... 2) #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... #else ... #endif is transformed to: #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... #elif defined(CONFIG_CPU_CORTEX_M3_M4) || defined(CONFIG_CPU_CORTEX_M7) ... #else #error Unknown ARM architecture #endif Change-Id: I7229029b174da3a8b3c6fb2eec63d776f1d11e24 Signed-off-by: Marcus Shawcroft <marcus.shawcroft@arm.com>
2016-12-31 13:18:25 +00:00
#else
#error Unknown ARM architecture
#endif /* CONFIG_ARMV6_M */
wfi
bx lr
/**
*
* @brief Atomically re-enable interrupts and enter low power mode
*
* INTERNAL
* The requirements for k_cpu_atomic_idle() are as follows:
* 1) The enablement of interrupts and entering a low-power mode needs to be
* atomic, i.e. there should be no period of time where interrupts are
* enabled before the processor enters a low-power mode. See the comments
* in k_lifo_get(), for example, of the race condition that occurs
* if this requirement is not met.
*
* 2) After waking up from the low-power mode, the interrupt lockout state
* must be restored as indicated in the 'imask' input parameter.
*
* @return N/A
*
* C function prototype:
*
* void k_cpu_atomic_idle (unsigned int imask);
*/
SECTION_FUNC(TEXT, k_cpu_atomic_idle)
#ifdef CONFIG_KERNEL_EVENT_LOGGER_SLEEP
push {lr}
bl _sys_k_event_logger_enter_sleep
pop {r1}
mov lr, r1
#endif
/*
* Lock PRIMASK while sleeping: wfe will still get interrupted by
* incoming interrupts but the CPU will not service them right away.
*/
cpsid i
/*
* No need to set SEVONPEND, it's set once in _CpuIdleInit() and never
* touched again.
*/
/* r0: interrupt mask from caller */
#if defined(CONFIG_ARMV6_M)
/* No BASEPRI, call wfe directly (SEVONPEND set in _CpuIdleInit()) */
wfe
cmp r0, #0
bne _irq_disabled
cpsie i
_irq_disabled:
#elif defined(CONFIG_ARMV7_M)
/* r1: zero, for setting BASEPRI (needs a register) */
eors.n r1, r1
/* unlock BASEPRI so wfe gets interrupted by incoming interrupts */
msr BASEPRI, r1
wfe
msr BASEPRI, r0
cpsie i
arm: Restructure ARM cpu related preprocessor conditionals. The ARM code base provides for three mutually exclusive ARM architecture related conditional compilation choices. M0_M0PLUS, M3_M4 and M7. Throughout the code base we have conditional compilation gated around these three choices. Adjust the form of this conditional compilation to adopt a uniform structure. The uniform structure always selects code based on the definition of an appropriate config option rather the the absence of a definition. Removing the extensive use of #else ensures that when support for other ARM architecture versions is added we get hard compilation failures rather than attempting to compile inappropriate code for the added architecture with unexpected runtime consequences. Adopting this uniform structure makes it straight forward to replace the adhoc CPU_CORTEX_M3_M4 and CPU_CORTEX_M0_M0PLUS configuration variables with ones that directly represent the actual underlying ARM architectures we provide support for. This change also paves the way for folding adhoc conditional compilation related to CPU_CORTEX_M7 directly in support for ARMv7-M. This change is mechanical in nature involving two transforms: 1) #if !defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... is transformed to: #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) #elif defined(CONFIG_CPU_CORTEX_M3_M4) || defined(CONFIG_CPU_CORTEX_M7) ... 2) #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... #else ... #endif is transformed to: #if defined(CONFIG_CPU_CORTEX_M0_M0PLUS) ... #elif defined(CONFIG_CPU_CORTEX_M3_M4) || defined(CONFIG_CPU_CORTEX_M7) ... #else #error Unknown ARM architecture #endif Change-Id: I7229029b174da3a8b3c6fb2eec63d776f1d11e24 Signed-off-by: Marcus Shawcroft <marcus.shawcroft@arm.com>
2016-12-31 13:18:25 +00:00
#else
#error Unknown ARM architecture
#endif /* CONFIG_ARMV6_M */
bx lr