Power Management¶
Zephyr RTOS power management subsystem provides several means for a system integrator to implement power management support that can take full advantage of the power saving features of SOCs.
Terminology¶
- SOC interface
This is a general term for the components that have knowledge of the SOC and provide interfaces to the hardware features. It will abstract the SOC specific implementations to the applications and the OS.
- SOC Power State
SOC Power State describes processor and device power states implemented at the SOC level. Deep Sleep State is an example of SOC Power State.
- Active State
The CPU and clocks are powered on. This is the normal operating state when the system is running.
- Sleep State
Some of the SoC clocks are gated. The CPU is stopped but does not lose execution context. Configuration of the peripherals is preserved.
- Deep Sleep State
The SoC is power gated and loses context. Most peripherals would also be power gated. RAM may be selectively retained.
- Idle Thread
A system thread that runs when there are no other threads ready to run.
- Power gating
Power gating reduces power consumption by shutting off current to blocks of the integrated circuit that are not in use.
Overview¶
The interfaces and APIs provided by the power management subsystem are designed to be architecture and SOC independent. This enables power management implementations to be easily adapted to different SOCs and architectures.
The architecture and SOC independence is achieved by separating the core infrastructure and the SOC specific implementations. The SOC specific implementations are abstracted to the application and the OS using hardware abstraction layers.
The power management features are classified into the following categories.
Tickless Idle
System Power Management
Device Power Management
Tickless Idle¶
This is the name used to identify the event-based idling mechanism of the Zephyr RTOS kernel scheduler. The kernel scheduler can run in two modes. During normal operation, when at least one thread is active, it sets up the system timer in periodic mode and runs in an interval-based scheduling mode. The interval-based mode allows it to time slice between threads. Many times, the threads would be waiting on semaphores, timeouts or for events. When there are no threads running, it is inefficient for the kernel scheduler to run in interval-based mode. This is because, in this mode the timer would trigger an interrupt at fixed intervals causing the scheduler to be invoked at each interval. The scheduler checks if any thread is ready to run. If no thread is ready to run then it is a waste of power because of the unnecessary CPU processing. This is avoided by the kernel switching to event-based idling mode whenever there is no thread ready to run.
The kernel holds an ordered list of thread timeouts in the system. These are the amount of time each thread has requested to wait. When the last active thread goes to wait, the idle thread is scheduled. The idle thread programs the timer to one-shot mode and programs the count to the earliest timeout from the ordered thread timeout list. When the timer expires, a timer event is generated. The ISR of this event will invoke the scheduler, which would schedule the thread associated with the timeout. Before scheduling the thread, the scheduler would switch the timer again to periodic mode. This method saves power because the CPU is removed from the wait only when there is a thread ready to run or if an external event occurred.
System Power Management¶
The kernel enters the idle state when it has nothing to schedule. If enabled via
the CONFIG_PM
Kconfig option, the Power Management
Subsystem can put an idle system in one of the supported power states, based
on the selected power management policy and the duration of the idle time
allotted by the kernel.
It is an application responsibility to set up a wake up event. A wake up event will typically be an interrupt triggered by one of the SoC peripheral modules such as a SysTick, RTC, counter, or GPIO. Depending on the power mode entered, only some SoC peripheral modules may be active and can be used as a wake up source.
Enabling system power management compels the Zephyr kernel scheduler to work in
tickless idle mode (see CONFIG_TICKLESS_IDLE
).
Power States¶
The power management subsystem classifies power states into two categories, Sleep State and Deep Sleep State, based on whether the CPU loses execution context during the power state transition.
The list of available power states is defined by enum power_states
. In
general power states with higher indexes will offer greater power savings and
have higher wake latencies.
Sleep State¶
CPU is stopped but does not lose execution context. Some of the SoC clocks are gated. Configuration of the peripherals is preserved but some of them may be no longer functional. Execution will resume at the place it stopped. The wake latencies of power states in this category are relatively low.
Deep Sleep State¶
CPU is power gated and loses execution context. Execution will resume at OS startup code or at a resume point determined by a bootloader that supports deep sleep resume. Depending on the SOC’s implementation of the power saving feature, it may turn off power to most devices. RAM may be retained by some implementations, while others may remove power from RAM saving considerable power. Power states in this category save more power than Sleep states and would have higher wake latencies.
Power Management Policies¶
The power management subsystem supports the following power management policies:
Residency
Application
Dummy
Residency¶
The power management system enters the power state which offers the highest power savings, and with a minimum residency value (defined by the respective Kconfig option) less than or equal to the scheduled system idle time duration.
Application¶
The power management policy is defined by the application which has to implement the following function.
enum power_states pm_policy_next_state(int32_t ticks);
Dummy¶
This policy returns the next supported power state in a loop. It is used mainly for testing purposes.
Device Power Management Infrastructure¶
The device power management infrastructure consists of interfaces to the Zephyr RTOS device model. These APIs send control commands to the device driver to update its power state or to get its current power state.
Zephyr RTOS supports two methods of doing device power management.
Distributed method
Central method
Distributed method¶
In this method, the application or any component that deals with devices directly
and has the best knowledge of their use does the device power management. This
saves power if some devices that are not in use can be turned off or put
in power saving mode. This method allows saving power even when the CPU is
active. The components that use the devices need to be power aware and should
be able to make decisions related to managing device power. In this method, the
SOC interface can enter CPU or SOC power states quickly when
sys_suspend()
gets called. This is because it does not need to
spend time doing device power management if the devices are already put in
the appropriate power state by the application or component managing the
devices.
Central method¶
In this method device power management is mostly done inside
sys_suspend()
along with entering a CPU or SOC power state.
If a decision to enter deep sleep is made, the implementation would enter it only after checking if the devices are not in the middle of a hardware transaction that cannot be interrupted. This method can be used in implementations where the applications and components using devices are not expected to be power aware and do not implement device power management.
This method can also be used to emulate a hardware feature supported by some SOCs which cause automatic entry to deep sleep when all devices are idle. Refer to Busy Status Indication to see how to indicate whether a device is busy or idle.
Device Power Management States¶
The Zephyr RTOS power management subsystem defines four device states. These states are classified based on the degree of device context that gets lost in those states, kind of operations done to save power, and the impact on the device behavior due to the state transition. Device context includes device registers, clocks, memory etc.
The four device power states:
DEVICE_PM_ACTIVE_STATE
Normal operation of the device. All device context is retained.
DEVICE_PM_LOW_POWER_STATE
Device context is preserved by the HW and need not be restored by the driver.
DEVICE_PM_SUSPEND_STATE
Most device context is lost by the hardware. Device drivers must save and restore or reinitialize any context lost by the hardware.
DEVICE_PM_OFF_STATE
Power has been fully removed from the device. The device context is lost when this state is entered. Need to reinitialize the device when powering it back on.
Device Power Management Operations¶
Zephyr RTOS power management subsystem provides a control function interface to device drivers to indicate power management operations to perform. The supported PM control commands are:
DEVICE_PM_SET_POWER_STATE
DEVICE_PM_GET_POWER_STATE
Each device driver defines:
The device’s supported power states.
The device’s supported transitions between power states.
The device’s necessary operations to handle the transition between power states.
The following are some examples of operations that the device driver may perform in transition between power states:
Save/Restore device states.
Gate/Un-gate clocks.
Gate/Un-gate power.
Mask/Un-mask interrupts.
Device Model with Power Management Support¶
Drivers initialize the devices using macros. See Device Driver Model for details on how these macros are used. Use the DEVICE_DEFINE macro to initialize drivers providing power management support via the PM control function. One of the macro parameters is the pointer to the device_pm_control handler function.
Default Initializer Function¶
int device_pm_control_nop(const struct device *unused_device, uint32_t unused_ctrl_command, void *unused_context);
If the driver doesn’t implement any power control operations, the driver can initialize the corresponding pointer with this default nop function. This default nop function does nothing and should be used instead of implementing a dummy function to avoid wasting code memory in the driver.
Device Power Management API¶
The SOC interface and application use these APIs to perform power management operations on the devices.
Get Device List¶
size_t z_device_get_all_static(struct device const **device_list);
The Zephyr RTOS kernel internally maintains a list of all devices in the system. The SOC interface uses this API to get the device list. The SOC interface can use the list to identify the devices on which to execute power management operations.
Note
Ensure that the SOC interface does not alter the original list. Since the kernel uses the original list, it must remain unchanged.
Device Set Power State¶
int device_set_power_state(const struct device *device, uint32_t device_power_state, device_pm_cb cb, void *arg);
Calls the device_pm_control()
handler function implemented by the
device driver with DEVICE_PM_SET_POWER_STATE command.
Device Get Power State¶
int device_get_power_state(const struct device *device, uint32_t * device_power_state);
Calls the device_pm_control()
handler function implemented by the
device driver with DEVICE_PM_GET_POWER_STATE command.
Busy Status Indication¶
The SOC interface executes some power policies that can turn off power to devices, causing them to lose their state. If the devices are in the middle of some hardware transaction, like writing to flash memory when the power is turned off, then such transactions would be left in an inconsistent state. This infrastructure guards such transactions by indicating to the SOC interface that the device is in the middle of a hardware transaction.
When the sys_suspend()
is called, the SOC interface checks if any device
is busy. The SOC interface can then decide to execute a power management scheme other than deep sleep or
to defer power management operations until the next call of
sys_suspend()
.
An alternative to using the busy status mechanism is to use the
distributed method of device power management. In such a method where the
device power management is handled in a distributed manner rather than centrally in
sys_suspend()
, the decision to enter deep sleep can be made based
on whether all devices are already turned off.
This feature can be also used to emulate a hardware feature found in some SOCs
that causes the system to automatically enter deep sleep when all devices are idle.
In such an usage, the busy status can be set by default and cleared as each
device becomes idle. When sys_suspend()
is called, deep sleep can
be entered if no device is found to be busy.
Here are the APIs used to set, clear, and check the busy status of devices.
Indicate Busy Status API¶
void device_busy_set(const struct device *busy_dev);
Sets a bit corresponding to the device, in a data structure maintained by the kernel, to indicate whether or not it is in the middle of a transaction.
Clear Busy Status API¶
void device_busy_clear(const struct device *busy_dev);
Clears the bit corresponding to the device in a data structure maintained by the kernel to indicate that the device is not in the middle of a transaction.
Check Busy Status of Single Device API¶
int device_busy_check(const struct device *chk_dev);
Checks whether a device is busy. The API returns 0 if the device is not busy.
Check Busy Status of All Devices API¶
int device_any_busy_check(void);
Checks if any device is busy. The API returns 0 if no device in the system is busy.
Device Idle Power Management¶
The Device Idle Power Management framework is a Active Power Management mechanism which reduces the overall system Power consumtion by suspending the devices which are idle or not being used while the System is active or running.
The framework uses device_set_power_state() API set the device power state accordingly based on the usage count.
The interfaces and APIs provided by the Device Idle PM are designed to be generic and architecture independent.
Device Idle Power Management API¶
The Device Drivers use these APIs to perform device idle power management operations on the devices.
Enable Device Idle Power Management of a Device API¶
void device_pm_enable(const struct device *dev);
Enbles Idle Power Management of the device.
Disable Device Idle Power Management of a Device API¶
void device_pm_disable(const struct device *dev);
Disables Idle Power Management of the device.
Resume Device asynchronously API¶
int device_pm_get(const struct device *dev);
Marks the device as being used. This API will asynchronously bring the device to resume state. The API returns 0 on success.
Resume Device synchronously API¶
int device_pm_get_sync(const struct device *dev);
Marks the device as being used. It will bring up or resume the device if it is in suspended state based on the device usage count. This call is blocked until the device PM state is changed to active. The API returns 0 on success.
Suspend Device asynchronously API¶
int device_pm_put(const struct device *dev);
Marks the device as being released. This API asynchronously put the device to suspend state if not already in suspend state. The API returns 0 on success.
Suspend Device synchronously API¶
int device_pm_put_sync(const struct device *dev);
Marks the device as being released. It will put the device to suspended state if is is in active state based on the device usage count. This call is blocked until the device PM state is changed to resume. The API returns 0 on success. This call is blocked until the device is suspended.
Power Management Configuration Flags¶
The Power Management features can be individually enabled and disabled using the following configuration flags.
This flag enables the power management subsystem.
This flag enables the tickless idle power saving feature.
This flag enables support for the Sleep states.
This flag enables support for the Deep Sleep states.
This flag is enabled if the SOC interface and the devices support device power management.
CONFIG_PM_DEVICE_IDLE
This flag enables the Device Idle Power Management.
API Reference¶
Power Management Hook Interface¶
-
group
power_management_hook_interface
Power Management Hooks.
Functions
-
void
pm_system_resume_from_deep_sleep
(void)¶ Restore context to the point where system entered the deep sleep state.
This function is optionally called when exiting from deep sleep if the SOC interface does not have bootloader support to handle resume from deep sleep. This function should restore context to the point where system entered the deep sleep state.
If the function is called at cold boot it should return immediately.
- Note
This function is not supported on all architectures.
-
void
pm_system_resume
(void)¶ Notify exit from kernel idling after PM operations.
This function would notify exit from kernel idling if a corresponding pm_system_suspend() notification was handled and did not return POWER_STATE_ACTIVE.
This function would be called from the ISR context of the event that caused the exit from kernel idling. This will be called immediately after interrupts are enabled. This is called to give a chance to do any operations before the kernel would switch tasks or processes nested interrupts. This is required for cpu low power states that would require interrupts to be enabled while entering low power states. e.g. C1 in x86. In those cases, the ISR would be invoked immediately after the event wakes up the CPU, before code following the CPU wait, gets a chance to execute. This can be ignored if no operation needs to be done at the wake event notification. Alternatively pm_idle_exit_notification_disable() can be called in pm_system_suspend to disable this notification.
-
enum power_states
pm_system_suspend
(int32_t ticks)¶ Allow entry to power state.
When the kernel is about to go idle, it calls this function to notify the power management subsystem, that the kernel is ready to enter the idle state.
At this point, the kernel has disabled interrupts and computed the maximum time the system can remain idle. The function passes the time that the system can remain idle. The SOC interface performs power operations that can be done in the available time. The power management operations must halt execution of the CPU.
This function assumes that a wake up event has already been set up by the application.
This function is entered with interrupts disabled. It should re-enable interrupts if it had entered a power state.
- Return
Power state which was entered or POWER_STATE_ACTIVE if SoC was kept in the active state.
- Parameters
ticks
: The upcoming kernel idle time.
-
void
pm_power_state_exit_post_ops
(enum power_states state)¶ Do any SoC or architecture specific post ops after sleep state exits.
This function is a place holder to do any operations that may be needed to be done after sleep state exits. Currently it enables interrupts after resuming from sleep state. In future, the enabling of interrupts may be moved into the kernel.
-
void
pm_notifier_register
(struct pm_notifier *notifier)¶ Register a power management notifier.
Register the given notifier from the power management notification list.
- Parameters
notifier
: pm_notifier object to be registered.
-
int
pm_notifier_unregister
(struct pm_notifier *notifier)¶ Unregister a power management notifier.
Remove the given notifier from the power management notification list. After that this object callbacks will not be called.
- Return
0 if the notifier was successfully removed, a negative value otherwise.
- Parameters
notifier
: pm_notifier object to be unregistered.
-
void
System Power Management APIs¶
-
group
system_power_management_api
System Power Management API.
Functions
-
static inline bool
pm_is_sleep_state
(enum power_states state)¶ Check if particular power state is a sleep state.
This function returns true if given power state is a sleep state.
-
static inline bool
pm_is_deep_sleep_state
(enum power_states state)¶ Check if particular power state is a deep sleep state.
This function returns true if given power state is a deep sleep state.
-
static inline void
pm_idle_exit_notification_disable
(void)¶ Function to disable power management idle exit notification.
The pm_system_resume() would be called from the ISR of the event that caused exit from kernel idling after PM operations. For some power operations, this notification may not be necessary. This function can be called in pm_system_suspend to disable the corresponding pm_system_resume notification.
-
void
pm_power_state_force
(enum power_states state)¶ Force usage of given power state.
This function overrides decision made by PM policy forcing usage of given power state in the ongoing suspend operation. And before the end of suspend, the state of forced_pm_state is cleared with interrupt disabled.
If enabled PM_DIRECT_FORCE_MODE, this function can only run in thread context.
- Parameters
state
: Power state which should be used in the ongoing suspend operation or POWER_STATE_AUTO.
-
void
pm_power_state_set
(enum power_states state)¶ Put processor into a power state.
This function implements the SoC specific details necessary to put the processor into available power states.
-
struct
pm_notifier
¶ - #include <power.h>
Power management notifier struct
This struct contains callbacks that are called when the target enters and exits power states.
As currently implemented the entry callback is invoked when transitioning from PM_STATE_ACTIVE to another state, and the exit callback is invoked when transitioning from a non-active state to PM_STATE_ACTIVE. This behavior may change in the future.
- Note
These callbacks can be called from the ISR of the event that caused the kernel exit from idling.
-
static inline bool
Device Power Management APIs¶
-
group
device_power_management_api
Device Power Management APIs.
Defines
-
DEVICE_PM_ACTIVE_STATE
¶ device is in ACTIVE power state
Normal operation of the device. All device context is retained.
-
DEVICE_PM_LOW_POWER_STATE
¶ device is in LOW power state
Device context is preserved by the HW and need not be restored by the driver.
-
DEVICE_PM_SUSPEND_STATE
¶ device is in SUSPEND power state
Most device context is lost by the hardware. Device drivers must save and restore or reinitialize any context lost by the hardware
-
DEVICE_PM_FORCE_SUSPEND_STATE
¶ device is in force SUSPEND power state
Driver puts the device in suspended state after completing the ongoing transactions and will not process any queued work or will not take any new requests for processing. Most device context is lost by the hardware. Device drivers must save and restore or reinitialize any context lost by the hardware.
-
DEVICE_PM_OFF_STATE
¶ device is in OFF power state
Power has been fully removed from the device. The device context is lost when this state is entered, so the OS software will reinitialize the device when powering it back on
-
DEVICE_PM_SET_POWER_STATE
¶
-
DEVICE_PM_GET_POWER_STATE
¶
Enums
Functions
-
const char *
device_pm_state_str
(uint32_t state)¶ Get name of device PM state.
- Parameters
state
: State id which name should be returned
-
void
device_busy_set
(const struct device *busy_dev)¶ Indicate that the device is in the middle of a transaction.
Called by a device driver to indicate that it is in the middle of a transaction.
- Parameters
busy_dev
: Pointer to device structure of the driver instance.
-
void
device_busy_clear
(const struct device *busy_dev)¶ Indicate that the device has completed its transaction.
Called by a device driver to indicate the end of a transaction.
- Parameters
busy_dev
: Pointer to device structure of the driver instance.
-
int
device_pm_control_nop
(const struct device *unused_device, uint32_t unused_ctrl_command, void *unused_context, device_pm_cb cb, void *unused_arg)¶ No-op function to initialize unimplemented hook.
This function should be used to initialize device hook for which a device has no PM operations.
- Parameters
unused_device
: Unusedunused_ctrl_command
: Unusedunused_context
: Unusedcb
: Unusedunused_arg
: Unused
- Return Value
-ENOTSUP
: for all operations.
-
static inline int
device_set_power_state
(const struct device *dev, uint32_t device_power_state, device_pm_cb cb, void *arg)¶ Call the set power state function of a device.
Called by the application or power management service to let the device do required operations when moving to the required power state Note that devices may support just some of the device power states
- Parameters
dev
: Pointer to device structure of the driver instance.device_power_state
: Device power state to be setcb
: Callback function to notify device power statusarg
: Caller passed argument to callback function
- Return Value
0
: If successful in queuing the request or changing the state.Errno
: Negative errno code if failure. Callback will not be called.
-
static inline int
device_get_power_state
(const struct device *dev, uint32_t *device_power_state)¶ Call the get power state function of a device.
This function lets the caller know the current device power state at any time. This state will be one of the defined power states allowed for the devices in that system
- Parameters
dev
: pointer to device structure of the driver instance.device_power_state
: Device power state to be filled by the device
- Return Value
0
: If successful.Errno
: Negative errno code if failure.
-
static inline void
device_list_get
(const struct device **device_list, int *device_count)¶ Gets the device structure list array and device count.
Called by the Power Manager application to get the list of device structures associated with the devices in the system. The PM app would use this list to create its own sorted list based on the order it wishes to suspend or resume the devices.
- Deprecated:
in 2.4 release, replace with z_device_get_all_static()
- Parameters
device_list
: Pointer to receive the device list arraydevice_count
: Pointer to receive the device count
-
int
device_any_busy_check
(void)¶ Check if any device is in the middle of a transaction.
Called by an application to see if any device is in the middle of a critical transaction that cannot be interrupted.
- Return Value
0
: if no device is busy-EBUSY
: if any device is busy
-
int
device_busy_check
(const struct device *chk_dev)¶ Check if a specific device is in the middle of a transaction.
Called by an application to see if a particular device is in the middle of a critical transaction that cannot be interrupted.
- Parameters
chk_dev
: Pointer to device structure of the specific device driver the caller is interested in.
- Return Value
0
: if the device is not busy-EBUSY
: if the device is busy
-
void
device_pm_enable
(const struct device *dev)¶ Enable device idle PM.
Called by a device driver to enable device idle power management. The device might be asynchronously suspended if Idle PM is enabled when the device is not use.
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
-
void
device_pm_disable
(const struct device *dev)¶ Disable device idle PM.
Called by a device driver to disable device idle power management. The device might be asynchronously resumed if Idle PM is disabled
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
-
int
device_pm_get
(const struct device *dev)¶ Call device resume asynchronously based on usage count.
Called by a device driver to mark the device as being used. This API will asynchronously bring the device to resume state if it not already in active state.
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
- Return Value
0
: If successfully queued the Async request. If queued, the caller need to wait on the poll event linked to device pm signal mechanism to know the completion of resume operation.Errno
: Negative errno code if failure.
-
int
device_pm_get_sync
(const struct device *dev)¶ Call device resume synchronously based on usage count.
Called by a device driver to mark the device as being used. It will bring up or resume the device if it is in suspended state based on the device usage count. This call is blocked until the device PM state is changed to resume.
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
- Return Value
0
: If successful.Errno
: Negative errno code if failure.
-
int
device_pm_put
(const struct device *dev)¶ Call device suspend asynchronously based on usage count.
Called by a device driver to mark the device as being released. This API asynchronously put the device to suspend state if it not already in suspended state.
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
- Return Value
0
: If successfully queued the Async request. If queued, the caller need to wait on the poll event linked to device pm signal mechanism to know the completion of suspend operation.Errno
: Negative errno code if failure.
-
int
device_pm_put_sync
(const struct device *dev)¶ Call device suspend synchronously based on usage count.
Called by a device driver to mark the device as being released. It will put the device to suspended state if is is in active state based on the device usage count. This call is blocked until the device PM state is changed to resume.
- Parameters
dev
: Pointer to device structure of the specific device driver the caller is interested in.
- Return Value
0
: If successful.Errno
: Negative errno code if failure.
-