doc: Edit power management technical content.

Edited content for clarity, correctness, completness, markup usage and style.

Change-Id: I526ecf9ce9a2f516cbb01cc38763ef4f71ee52d9
Signed-off-by: Rodrigo Caballero <rodrigo.caballero.abraham@intel.com>
This commit is contained in:
Rodrigo Caballero 2016-05-02 11:00:58 -05:00 committed by Anas Nashif
commit c00cbb7bbf

View file

@ -4,212 +4,252 @@ Power Management
################ ################
The power management infrastructure consists of interfaces exported by the The power management infrastructure consists of interfaces exported by the
power management subsystem for a Power Manager application to implement power power management subsystem. This subsystem exports interfaces that a
:abbr:`Power Management Application (PMA)` uses to implement power management
policies. policies.
Terminology Terminology
*********** ***********
`PMA` :dfn:`PMA`
Shortened form for Power Manager Application, the system integrator
provided application that maintains any power management policies and
enforces power management actions based on them. This would be integrated
into the main Zephyr application.
`LPS` The system integrator provides the :abbr:`PMA (Power Manager
Any of the CPU low power states supported by the processor. Application)`. The PMA maintains any power management policies and
executes the power management actions based on those policies.
The PMA must be integrated into the main Zephyr application.
`SoC Power State` :dfn:`LPS`
Power state implemented at the SoC level which includes processor and
device power state.
`Hook function` :abbr:`LPS (Low Power States)` refers to any one of the low power states supported by the CPU.
A callback function implemented by one component and called by another
component. e.g. functions implemented by PMA that can be called by the
kernel.
**Architecture and SoC dependent Power States:** :dfn:`SoC Power State`
An SoC Power State describes processor and device power statuses
implemented at the SoC level.
:dfn:`Hook function`
A Hook function is a callback function that one component implements and
another component calls. For example, the PMA implements functions that
the kernel calls.
Architecture and SoC dependent Power States:
============================================
On x86:
-------
`Active`
The CPU is active and running in the hardware defined C0 C-state.
`Idle`
The CPU is not active but continues to be powered.
The CPU may be in one of any lower C-states: C1, C2, etc.
`Deep Sleep`
The Power is off to the processor and system clock. RAM is retained.
On ARM
------
**On x86:**
`Active` `Active`
The CPU is currently active and running in the hardware defined The CPU is active and running.
C0
`Idle` `Idle`
The CPU is not currently active, and continues to be powered Stops the processor clock. The ARM documentation describes
on. The CPU may be in one of any lower C-states (i.e. C1, C2, etc). this as *Sleep*.
`Deep Sleep`
Power to the processor and system clock turned off. RAM
retained.
**On ARM:**
`Active`
The CPU is currently active and running
`Idle`
Stops the processor clock. The ARM documentation describes
this as Sleep.
`Deep Sleep` `Deep Sleep`
Stops the system clock and switches off the PLL and flash Stops the system clock and switches off the PLL and flash
memory. RAM retained. memory. RAM is retained.
**On ARC:**
On ARC
------
`Active` `Active`
The CPU is currently active and running in the SS0 state. The CPU is currently active and running in the SS0 state.
`Idle` `Idle`
Defined as the SS1, SS2 states. Defined as the SS1 and SS2 states.
.. note::
These power states are generic terms that map to the power states commonly
supported by processors and SoCs based on the 3 architectures. The PMA
writer should refer to the data sheet of the SoC to get details of each
power state.
The power states described here are generic terms that map to the power
states commonly supported by processors and SoCs based on the three
architectures. When coding a PMA, please refer to the data sheet of the SoC
to get details on each power state.
Overview Overview
******** ********
The Zephyr power management subsystem provides interfaces for a system
integrator to utilize and create their own Power Management Application (PMA)
that can enforce any policies needed. It is based on the philosophy of not
enforcing any policies in the kernel and thus giving full flexibility to the
PMA.
This will be accomplished by providing an infrastructure that has an The Zephyr power management subsystem provides interfaces that a system
architecture independent interface. The Zephyr kernel will provide integrator can use to create a PMA. The PMA then enforces any policies
notification methods in both the Microkernel and Nanokernel for the PMA when needed. The design is based on the philosophy of not enforcing any policies
the OS is about to enter and exit system idle. The PMA will do various power in the kernel giving full flexibility to the PMA.
management policy enforcement operations during these notifications.
The provided infrastructure has an architecture independent interface. Both
the microkernel and nanokernel notify the PMA when the kernel is about to
enter or exit a system idle state. The PMA can perform the power management
policy operations during these notifications.
Policies Policies
******** ********
When the Power Management subsystem notifies the PMA that the kernel is about
to enter system idle, it would specify a time period that it intends to idle.
This time period is the alloted time for the PMA to do any power management
operations. The PMA has the choice to do various operations, like putting the
processor or SoC in low power states, turning off some or all peripherals and
gating device clocks. Using various combinations of these operations, the PMA
would create fine grain custom power management policies. These fine grain
policies would be characterized by different levels of power savings and
different wake latencies. Generally, the operations that save more power have
a higher wake latency. While making policy decisions, the PMA would choose the
policy that would save the most power and at the same time, its total
execution time fits well within the idle time allotted by the Power Management
subsystem.
The Zephyr Power Management subsystem classifies policies into categories based When the power management subsystem notifies the PMA that the kernel is about
on relative power savings and the corresponding wake latencies. These also to enter a system idle state, it specifies the period of time the system
loosely map to common power states supported by processors and SoCs in the intends to stay idle. The PMA performs any power management operations during
supported architectures. The PMA should map its fine grain custom policies to this time. The PMA can perform various operations. For example, put the
the policy categories defined by the Power Management subsystem listed below. processor or the SoC in a low power state, turn off some or all of the
peripherals, and gate device clocks. Using combinations of these operations,
the PMA can create fine grain custom power management policies.
Different levels of power savings and different wake latencies characterize
these fine grain policies. In general, operations that save more power have a
higher wake latency. When making policy decisions, the PMA chooses the
policy that saves the most power. At the same time, the policy's total
execution time must fit well within the idle time allotted by the power
management subsystem.
The Zephyr power management subsystem classifies policies into categories
based on relative power savings and the corresponding wake latencies. These
policies also loosely map to common processor and SoC power states in the
supported architectures. The PMA should map the fine grain custom policies to
the policy categories of the power management subsystem. The power management
subsystem defines three categories:
* SYS_PM_LOW_POWER_STATE
* SYS_PM_DEEP_SLEEP
* SYS_PM_DEVICE_SUSPEND_ONLY
SYS_PM_LOW_POWER_STATE SYS_PM_LOW_POWER_STATE
====================== ======================
In this policy category, the PMA would do power management operations on some
or all devices and put the processor into a low power state. The device power In this policy category, the PMA performs power management operations on some
management operations may involve turning off peripherals and gating device or all devices and puts the processor into a low power state. The device
clocks. If any of those operations result in the device registers losing power management operations can involve turning off peripherals and gating
state, then those states would need to be saved and restored. The PMA should device clocks. When any of those operations causes the device registers to
map fine grain policies to this category, with relatively less wake latency lose their state, then those states must be saved and restored. The PMA
than those that it maps to `SYS_PM_DEEP_SLEEP`_ category. The exit from this should map fine grain policies with relatively less wake latency to this
policy is from an external interrupt, a wake up event set by the PMA or when category. Policies with larger wake latency should be mapped to the
the idle time alloted by the Power Management subsystem expires. `SYS_PM_DEEP_SLEEP`_ category. Policies in this category exit from an
external interrupt, a wake up event set by the PMA, or when the idle time
alloted by the power management subsystem expires.
SYS_PM_DEEP_SLEEP SYS_PM_DEEP_SLEEP
================= =================
In this policy category, the PMA would put the system into the deep sleep
category of power states supported by SoCs. In this state, the system clock In this policy category, the PMA puts the system into the deep sleep power
would be turned off. The processor is turned off and would lose state. RAM is states supported by SoCs. In this state, the system clock is turned off. The
expected to be retained and can be used to save and restore processor states. processor is turned off and loses its state. RAM is expected to be retained
Depending on the SoC, selected devices would also be turned off in the deep and can save and restore processor states. Only the devices necessary to wake
sleep power state. Since this would cause device registers to lose state, they up the system from the deep sleep power state stay on. The SoC turns off the
would need to be saved and restored. The PMA should map fine grain policies power to all other devices. Since this causes device registers to lose their
with the highest wake latency to this policy category. The exit from this state, they must be saved and restored. The PMA should map fine grain
policy is from SoC dependent wake events. policies with the highest wake latency to this policy category. Policies in
this category exit from SoC dependent wake events.
SYS_PM_DEVICE_SUSPEND_ONLY SYS_PM_DEVICE_SUSPEND_ONLY
========================== ==========================
In this policy category, the PMA would do power management operations on some
devices but would not do any operations that would result in a processor or
SoC power state transition. The PMA should map its fine grain policies that have
the least wake latency to this category. Exit from this policy is from an
external interrupt or when the idle time alloted by the Power Management
subsystem expires.
.. note:: In this policy category, the PMA performs power management operations on some
devices but none that result in a processor or SoC power state transition.
The PMA should map its fine grain policies that have the lowest wake latency
to this policy category. Policies in this category exit from an external
interrupt or when the idle time alloted by the power management subsystem
expires.
Some of the policy categories are named similar to the processor or SoC power Some policy categories names are similar to the power states of processors or
state that it is associated with. e.g. :c:macro:`SYS_PM_DEEP_SLEEP`. However, SoCs, for example, :code:`SYS_PM_DEEP_SLEEP`. However, they must be seen
they should be seen as policy categories and are not intended to indicate any as policy categories and do not indicate any specific processor or SoC power
specific processor or SoC power state by itself. state by themselves.
.. _pm_hook_infra:
Power Management Hook Infrastructure Power Management Hook Infrastructure
************************************ ************************************
This consists of hook functions that would be implemented by the PMA and would
be called by the power management subsystem when the kernel enters and exits This infrastructure consists of the hook functions that the PMA implemented.
idle state i.e. when it has nothing to schedule. This section will give a The power management subsystem calls these hook functions when the kernel
general overview and concepts of the hook functions. Refer to enters and exits the idle state, in other words, when the kernel has nothing
:ref:`Power Management APIs <power_management_api>` for detailed description to schedule. This section provides a general overview and general concepts of
of the APIs. the hook functions. Refer to :ref:`power_management_api` for the detailed
description of the APIs.
Suspend Hook function Suspend Hook function
===================== =====================
.. code-block:: c .. code-block:: c
int _sys_soc_suspend(int32_t ticks); int _sys_soc_suspend(int32_t ticks);
When kernel is about to go idle, the kernel itself will disable interrupts. The When the kernel is about to go idle, the power management subsystem calls the
kernel will then call the :c:func:`_sys_soc_suspend()` function, notifying the :code:`_sys_soc_suspend()` function, notifying the PMA that the kernel is
PMA of the operation. Included in the notification are the maximum number of ready to enter the idle state.
ticks that the system can be set idle for. The PMA will then determine what
policies can be executed within the allotted time frame.
The kernel expects the :c:func:`_sys_soc_suspend()` to return one of the At this point, the kernel has disabled interrupts and computed the maximum
following values based on the policy operation the PMA executed: number of ticks the system can remain idle. The function passes the time that
the system can remain idle to the PMA along with the notification. When
notified, the PMA selects and executes one of the fine grain power policies
that can be executed within the allotted time.
`SYS_PM_NOT_HANDLED` The power management subsystem expects the :code:`_sys_soc_suspend()` to
No PM operations. Indicating the PMA was not able to accomplish any return one of the following values based on the power management operations
action in the time allotted by the kernel. the PMA executed:
`SYS_PM_DEVICE_SUSPEND_ONLY` :code:`SYS_PM_NOT_HANDLED`
Only Devices are suspended. Indicating that the PMA has accomplished
any device suspend operations. This does not include any CPU or SOC power
operations.
`SYS_PM_LOW_POWER_STATE` No power management operations. Indicates that the PMA could not
Low Power State. Indicating that the PMA was successful at putting the accomplish any actions in the time allotted by the kernel.
CPU into a low power state.
`SYS_PM_DEEP_SLEEP` :code:`SYS_PM_DEVICE_SUSPEND_ONLY`
Deep Sleep. Indicating that the PMA was successful at pushing the SOC
into the Deep Sleep state. Only devices are suspended. Indicates that the PMA could accomplish any
device suspend operations. These operations do not include any processor
or SOC power operations.
:code:`SYS_PM_LOW_POWER_STATE`
Entered a LPS. Indicates that the PMA could put the processor into a low
power state.
:code:`SYS_PM_DEEP_SLEEP`
Entered deep sleep. Indicates that the PMA could put the SoC in a deep
sleep state.
Resume Hook function Resume Hook function
==================== ====================
.. code-block:: c .. code-block:: c
void _sys_soc_resume(void); void _sys_soc_resume(void);
This hook function will be called by the kernel when exiting from idle state or The kernel calls this hook function when exiting from an idle state or a low
from the low power state the PMA put the processor and SoC in. Based on the power state. Based on which policy the PMA executed in the
policy executed by the PMA in :c:func:`_sys_soc_suspend()`, it should do the :code:`_sys_soc_suspend()` function, the PMA performs the necessary recovery
necessary recovery operations in this function. operations in this hook function.
.. note:: Since the hook functions are called with the interrupts disabled, the PMA
Since the hook functions are called with interrupts disabled, the PMA should should ensure that its operations are completed quickly. Thus, the PMA
ensure that it completes operations quick so that the kernel's scheduling ensures that the kernel's scheduling performance is not disrupted.
performance is not disrupted.
Device Power Management Infrastructure Device Power Management Infrastructure
************************************** **************************************
This infrastructure consists of interfaces into the Zephyr device model which
enables the PMA to do suspend and resume operations on devices. Refer to The device power management infrastructure consists of interfaces to the
:ref:`Power Management APIs <power_management_api>` for detailed description of Zephyr device model. These interfaces enable the PMA to suspend and resume
the APIs. operations on devices. Refer to :ref:`power_management_api` for detailed
description of the APIs.
Device Power Management Operations Device Power Management Operations
================================== ==================================
Drivers would implement handlers for suspend and resume power management
operations. PMA would call each of the drivers suspend and resume handler
functions to do the necessary power management operations on those devices.
Device PM Operations structure Drivers can implement handlers to suspend and resume power management
------------------------------ operations. The PMA performs the necessary power management operations on the
devices by calling each of the suspend and resume handler functions of the
drivers.
Operations Structure
--------------------
.. code-block:: c .. code-block:: c
struct device_pm_ops { struct device_pm_ops {
@ -218,353 +258,361 @@ Device PM Operations structure
}; };
This structure contains pointers to the :c:func:`suspend()` and This structure contains pointers to the :c:func:`suspend()` and
:c:func:`resume()` handler functions. The device driver should initialize :c:func:`resume()` handler functions. The device driver initializes those
those pointers with the corresponding handler functions that is implemented in pointers with the corresponding handler functions implemented in the
the driver. driver.
Default Initializer function for PM ops Default Initializer Function
--------------------------------------- ----------------------------
If the driver does not implement any of of the operations then it can
initialize the corresponding pointer with the following function that does
nothing. This function should be used instead of the driver implementing its
own dummy function to avoid wasting code memory.
.. code-block:: c .. code-block:: c
int device_pm_nop(struct device *unused_device, int unused_policy); int device_pm_nop(struct device *unused_device, int unused_policy);
Device Suspend Operation Handler function When the driver does not implement any operations, the driver can initialize
the corresponding pointer with this function. This default initializer
function does nothing and should be used instead of implementing a dummy
function in the driver to avoid wasting code memory.
.. _dev_suspend_handler:
Device Suspend Operation Handler Function
----------------------------------------- -----------------------------------------
.. code-block:: c .. code-block:: c
int suspend(struct device *device, int pm_policy); int suspend(struct device *device, int pm_policy);
This function is implemented by the device driver to perform suspend operations The device driver implements this function to perform the suspend operations
on the devices it handles. The PMA would call it passing the power policy it on the handled devices. The PMA calls the function and passes the power
is currently executing. The device driver would do operations necessary to policy to execute. The device driver performs the operations necessary to
handle the transitions associated with the policy specified by the PMA. handle the transitions associated with the policy the PMA specified. Here are
Example operations that the device driver would do are: some example operations that the device driver performs:
- Save device states * Save device states.
- Gate clocks * Gate clocks.
- Turn off peripherals * Turn off peripherals.
It would return 0 if successful. In all other cases it would return an This function returns 0 if successful. Otherwise, the function returns an
appropriate negative :c:macro:`errno` value. appropriate negative `errno` value.
.. _dev_resume_handler:
Device Resume Operation Handler function Device Resume Operation Handler Function
---------------------------------------- ----------------------------------------
.. code-block:: c .. code-block:: c
int resume(struct device *device, int pm_policy); int resume(struct device *device, int pm_policy);
PMA would call this when it is doing resume operations on devices. The device The PMA calls this function to resume operations on the devices on which it
driver would do the necessary resume operation on its device based on the had previously performed suspend operations. The device driver performs the
policy specified by the PMA in the argument. necessary resume operations on its device, following the power management
policy specified in the function's argument.
It would return 0 if successful. In all other cases it would return an The function returns 0 if successful. In all other cases it returns an
appropriate negative :c:macro:`errno` value. appropriate negative :code:`errno` value.
Device Model with Power Management support Device Model with Power Management Support
========================================== ==========================================
Drivers that have Power Management support should initialize their devices
using the folllowing macros that are designed to take additional parameters
necessary to initialize the power management related handlers implemented by
the drivers. Following are the macros:
:c:macro:`DEVICE_AND_API_INIT_PM` Drivers initialize the devices using macros. See :ref:`device_drivers` for
details on how these macros are used. Extended versions of the macros are
provided for drivers with power management support. The macros take
additional parameters that are necessary to initialize pointers to the power
management related handler functions.
This should be used where :c:macro:`DEVICE_AND_API_INIT` macro would be These macros should be used:
used
:c:macro:`DEVICE_INIT_PM` :code:`DEVICE_AND_API_INIT_PM`
This should be used where :c:macro:`DEVICE_INIT` macro would be used Use this macro in place of the :code:`DEVICE_AND_API_INIT` macro.
:c:macro:`SYS_INIT_PM` :code:`DEVICE_INIT_PM`
This should be used where :c:macro:`SYS_INIT` macro would be used Use this macro in place of the :code:`DEVICE_INIT` macro.
Device PM API for PMA :code:`SYS_INIT_PM`
=====================
These APIs will be used by the PMA to do suspend and resume operations on the Use this macro in place of the :code:`SYS_INIT` macro.
Device Power Management API for the PMA
=======================================
The PMA uses these APIs to perform suspend and resume operations on the
devices. devices.
Getting the Device List Get Device List
----------------------- ---------------
.. code-block:: c .. code-block:: c
void device_list_get(struct device **device_list, int *device_count); void device_list_get(struct device **device_list, int *device_count);
This api is used by the PMA to get the device list that the Zephyr kernel The Zephyr kernel internally maintains a list of all devices in the system.
internally maintains for all devices in the system. The device structure in The PMA uses this API to get the device list. The PMA can use the list to
the list will be used to identify devices that the PMA would chose to do PM identify the devices on which to execute power management operations.
operations on.
The PMA can use this list to create its own sorted order list based on device The PMA can use this list to create a sorted order list based on device
dependencies. It can also create device groups to execute different policies dependencies. The PMA creates device groups to execute different policies
on each device group. on each device group.
.. note:: .. note::
PMA should take care that it does not alter the original list, since that is
the list the kernel uses. Ensure that the PMA does not alter the original list. Since the kernel
uses the original list, it should remain unchanged.
PMA Device Suspend API PMA Device Suspend API
---------------------- ----------------------
.. code-block:: c .. code-block:: c
int device_suspend(struct device *device, int pm_policy); int device_suspend(struct device *device, int pm_policy);
This function would call the :c:func:`suspend()` handler function implemented Calls the :c:func:`suspend()` handler function implemented by the device
by the device driver for the device. Refer to driver. See :ref:`dev_suspend_handler` for more information.
`Device Suspend Operation Handler function`_ for more information.
PMA Device Resume API PMA Device Resume API
--------------------- ---------------------
.. code-block:: c .. code-block:: c
int device_resume(struct device *device, int pm_policy); int device_resume(struct device *device, int pm_policy);
This function would call the :c:func:`resume()` handler function implemented by Calls the :c:func:`resume()` handler function implemented by the device
the device driver for the device. Refer to driver. See :ref:`dev_resume_handler` for more information.
`Device Resume Operation Handler function`_ for more information.
Device Busy Status Indication Busy Status Indication
============================= ======================
Some power policies executed by the PMA could turn off power to devices causing
them to lose state. If such devices are in the middle of some hardware
transaction (e.g. write to flash memory), when the power is turned off, then
such transactions would be left in an inconsistent state. This infrastructure
is to enable devices guard such transactions by indicating to the PMA that it
is in the middle of a hardware transaction.
During a call to :c:func:`_sys_soc_suspend()`, if PMA finds any device is busy, The PMA executes some power policies that can turn off power to devices,
then it may decide to choose a policy other than Deep Sleep or defer PM causing them to lose their state. If the devices are in the middle of some
operations till the next call to :c:func:`_sys_soc_suspend()`. 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 PMA that
the device is in the middle of a hardware transaction.
.. note:: When the :code:`_sys_soc_suspend()` is called, the PMA checks if any device
It is up to the device driver writer to decide whether a transaction needs is busy. The PMA can then decide to execute a policy other than deep sleep or
to be guarded using these APIs. If there are other recovery or retrial to defer power management operations until the next call of
methods in place, then the driver could choose to avoid guarding the :code:`_sys_soc_suspend()`.
transactions.
If other recovery or retrieval methods are in place, the driver can avoid
guarding the transactions. Not all hardware transactions must be guarded. The
Zephyr kernel provides the following APIs for the device drivers and the PMA
to decide whether a particular transaction must be guarded.
Indicate Busy Status API
------------------------
Device API to Indicate Busy Status
----------------------------------
.. code-block:: c .. code-block:: c
void device_busy_set(struct device *busy_dev); void device_busy_set(struct device *busy_dev);
This API will set a bit corresponding to the device, in a data structure Sets a bit corresponding to the device, in a data structure maintained by the
maintained by the kernel, to indicate it is in the middle of a transaction. kernel, to indicate whether or not it is in the middle of a transaction.
Clear Busy Status API
---------------------
Device API to Clear Busy Status
-------------------------------
.. code-block:: c .. code-block:: c
void device_busy_clear(struct device *busy_dev); void device_busy_clear(struct device *busy_dev);
This API will clear a bit corresponding to the device, in a data structure Clears the bit corresponding to the device in a data structure
maintained by the kernel, to indicate it is not in the middle of a transaction. maintained by the kernel to indicate that the device is not in the middle of
a transaction.
Check Busy Status of Single Device API
--------------------------------------
PMA API to Check Busy Status of Single Device
---------------------------------------------
.. code-block:: c .. code-block:: c
int device_busy_check(struct device *chk_dev); int device_busy_check(struct device *chk_dev);
This API is called by the PMA for each device to check its busy status. It Checks whether a device is busy. The API returns 0 if the device
returns 0 if the device is not busy. is not busy.
Check Busy Status of All Devices API
------------------------------------
PMA API to Check Busy Status of All Devices
-------------------------------------------
.. code-block:: c .. code-block:: c
int device_any_busy_check(void); int device_any_busy_check(void);
This API is called by the PMA to check if any device is busy. It returns 0 if Checks if any device is busy. The API returns 0 if no device in the system is busy.
no device in the system is busy.
.. _pm_config_flags:
Power Management Configuration Flags
************************************
Power Management Config Flags
*****************************
The Power Management features can be individually enabled and disabled using The Power Management features can be individually enabled and disabled using
the following config flags. the following configuration flags.
`CONFIG_SYS_POWER_MANAGEMENT` :code:`CONFIG_SYS_POWER_MANAGEMENT`
This enables the Power Management Subsystem.
`CONFIG_SYS_POWER_LOW_POWER_STATE` This flag enables the power management subsystem.
PMA should enable this flag if it would use `SYS_PM_LOW_POWER_STATE`
policy.
`CONFIG_SYS_POWER_DEEP_SLEEP` :code:`CONFIG_SYS_POWER_LOW_POWER_STATE`
This flag would enable support for the `SYS_PM_DEEP_SLEEP` policy.
`CONFIG_DEVICE_POWER_MANAGEMENT` The PMA enables this flag to use the :code:`SYS_PM_LOW_POWER_STATE` policy.
This flag should be enabled if device power management is supported by
the PMA and the devices. :code:`CONFIG_SYS_POWER_DEEP_SLEEP`
This flag enables support for the :code:`SYS_PM_DEEP_SLEEP` policy.
:code:`CONFIG_DEVICE_POWER_MANAGEMENT`
This flag is enabled if the PMA and the devices support device power
management.
Writing a Power Management Application Writing a Power Management Application
************************************** **************************************
This section describes the steps involved in writing a typical Power Management
Application to enforce policies using the Power Management APIs. This
demonstrates the various scenarios that the PMA would consider in the policy
decision process.
.. note:: A typical PMA executes policies through power management APIS. This section
details various scenarios that can be used to help developers write their own
custom PMAs.
The Power Management Application would be part of a larger application The PMA is part of a larger application doing more than just power
that does more than just power management. Here we refer to the Power management. This section focuses on the power management aspects of the
Management part of the application. application.
Initial Setup Initial Setup
============= =============
To enable Power Management support, the application would do the following:
- Enable CONFIG_SYS_POWER_MANAGEMENT flag To enable the power management support, the application must do the following:
- Enable other required config flags described in #. Enable the :code:`CONFIG_SYS_POWER_MANAGEMENT` flag
`Power Management Config Flags`_.
- Implement the hook functions described in #. Enable other required config flags described in :ref:`pm_config_flags`.
`Power Management Hook Infrastructure`_.
Get Device List and Create Policies #. Implement the hook functions described in :ref:`pm_hook_infra`.
===================================
The first act of the PMA will be to retrieve the known list of devices through
the :c:func:`device_list_get()` function. Because the PMA is part of the
application, it is expected to start after all devices in the system have been
initialized. Thus the list of devices is not expected to change once the
application has begun.
The :c:func:`device_list_get()` function will return an array of current Device List and Policies
enabled devices. It is up to the PMA to walk this list and determine the best ========================
mechanism to store/process this list. It is up to the system integrator to
verify the amount of time each device requires for a power cycle, and ensure The PMA retrieves the list of enabled devices in the system using the
this time fits within the allotted time provided by the kernel. This time :c:func:`device_list_get()` function. Since the PMA is part of the
value is highly dependent upon each specific device used in the final platform application, the PMA starts after all devices in the system have been
and SOC. initialized. Thus, the list of devices will not change once the application
has begun.
Once the device list has been retrieved and stored, the PMA can form device Once the device list has been retrieved and stored, the PMA can form device
groups and sorted lists based on device dependencies. Using the device lists groups and sorted lists based on device dependencies. The PMA uses the device
and the known aggregate wake latency of the combination of power operations, lists and the known aggregate wake latency of the combination of power
the PMA would then create fine grain custom power policies. Finally it would operations to create the fine grain custom power policies. Finally, the PMA
map these custom policies to the policy categories defined by the Power maps these custom policies to the policy categories defined by the power
Management subsystem as described in `Policies`_. management subsystem as described in `Policies`_.
Scenarios During Suspend Scenarios During Suspend
======================== ========================
When the :c:func:`_sys_soc_suspend()` function is called by the Power
Management subsystem, the PMA can select between multiple scenarios.
**Case 1:** When the power management subsystem calls the :code:`_sys_soc_suspend()`
function, the PMA can select between multiple scenarios.
The time allotted is too short for any power management. In this case, the PMA Scenario 1
will leave interrupts disabled, and return the code SYS_PM_NOT_HANDLED. This ----------
will allow the Zephyr kernel to continue with its normal idling process.
**Case 2:** The time allotted is too short for any power management.
The time allotted is enough for some devices to be suspended. In this case, the PMA leaves the interrupts disabled, and returns the code
:code:`SYS_PM_NOT_HANDLED`. This actions allow the Zephyr kernel to continue
with its normal idling process.
.. code-block:: none Scenario 2
----------
Scan through the devices that meet the criteria The time allotted allows the suspension of some devices.
Call device_suspend() for each device The PMA scans through the devices that meet the criteria and calls the
:c:func:`device_suspend()` function for each device.
If everything suspends correctly, the PMA will: After all devices are suspended properly, the PMA executes the following
operations:
If the time allotted is enough for SYS_PM_LOW_POWER_STATE policy * If the time allotted is enough for the :code:`SYS_PM_LOW_POWER_STATE`
policy:
Setup wake event Push the CPU to LPS re-enabling interrupts at the #. The PMA sets up the wake event, puts the CPU in a LPS, and re- enables
same time. the interrupts at the same time.
Return SYS_PM_LOW_POWER_STATE #. The PMA returns the :code:`SYS_PM_LOW_POWER_STATE` code.
If the time allotted is not enough for SYS_PM_LOW_POWER_STATE * If the time allotted is not enough for the :code:`SYS_PM_LOW_POWER_STATE`
policy, the PMA returns the :code:`SYS_PM_DEVICE_SUSPEND_ONLY` code.
Return SYS_PM_DEVICE_SUSPEND_ONLY When a device fails to suspend, the PMA executes the following operations:
If a device fails to suspend, the PMA will: * If the system integrator determined that the device is not essential to the
suspend process, the PMA can ignore the failure.
If the device is not essential to the suspend process, as determined by * If the system integrator determined that the device is essential to the
the system integrator, the PMA can choose to ignore the failure. suspend process, the PMA takes any necessary recovery actions and
returns the :code:`SYS_PM_NOT_HANDLED` code.
If the device is essential to the suspend process, as determined by the Scenario 3
system integrator, the PMA shall take any necessary recovery actions and ----------
return SYS_PM_NOT_HANDLED.
**Case 3:**
The time allotted is enough for all devices to be suspended. The time allotted is enough for all devices to be suspended.
.. code-block:: none The PMA calls the :c:func:`device_suspend()` function for each device.
Call device_suspend() for each device. After all devices are suspended properly and the time allotted is enough for
the :code:`SYS_PM_DEEP_SLEEP` policy, the PMA executes the following
operations:
If everything suspends correctly, the PMA will: #. Calls the :c:func:`device_any_busy_check()` function to get device busy
status. If any device is busy, the PMA must choose a policy other than
:code:`SYS_PM_DEEP_SLEEP`.
#. Sets up wake event.
#. Puts the SOC in the deep sleep state.
#. Re-enables interrupts.
#. Returns the :code:`SYS_PM_DEEP_SLEEP` code.
If the time allotted is enough for SYS_PM_DEEP_SLEEP policy If, on the other hand, the time allotted is only enough for the
:code:`SYS_PM_LOW_POWER_STATE` policy, The PMA executes the following
operations:
Call device_any_busy_check() to get device busy status #. Sets up wake event.
#. Puts the CPU in a LPS re-enabling interrupts at the same time.
#. Returns the :code:`SYS_PM_LOW_POWER_STATE` code.
If any device is busy If the time allotted is not enough for any CPU or SOC power management
operations, the PMA returns the :code:`SYS_PM_DEVICE_SUSPEND_ONLY` code.
Choose policy other than SYS_PM_DEEP_SLEEP When a device fails to suspend, the PMA executes the following operations:
Setup wake event * If the system integrator determined that the device is not essential to the
suspend process the PMA can ignore the failure.
Push the SOC to Deep Sleep * If the system integrator determined that the device is essential to the
suspend process, the PMA takes any necessary recovery actions and
Re-enable interrupts returns the :code:`SYS_PM_NOT_HANDLED` code.
Return SYS_PM_DEEP_SLEEP
If the time allotted is enough for SYS_PM_LOW_POWER_STATE policy
Setup wake event
Push the CPU to LPS re-enabling interrupts at the same time.
Return SYS_PM_LOW_POWER_STATE
If the time allotted is not enough for any CPU or SOC operations
Return SYS_PM_DEVICE_SUSPEND_ONLY
If a device fails to suspend, the PMA will:
If the device is not essential to the suspend process, as determined by
the system integrator, the PMA can choose to ignore the failure.
If the device is essential to the suspend process, as determined by the
system integrator, the PMA shall take any necessary recovery actions and
return SYS_PM_NOT_HANDLED.
Policy Decision Summary Policy Decision Summary
======================= =======================
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+
| PM operations | Policy and Return Code | | PM operations | Policy and Return Code |
+==============================+===========================+ +=================================+=======================================+
| Suspend some devices & | SYS_PM_LOW_POWER_STATE | | Suspend some devices and | :code:`SYS_PM_LOW_POWER_STATE` |
| | | | | |
| Enter Low Power State | | | Enter Low Power State | |
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+
| Suspend all devices & | SYS_PM_LOW_POWER_STATE | | Suspend all devices and | :code:`SYS_PM_LOW_POWER_STATE` |
| | | | | |
| Enter Low Power State | | | Enter Low Power State | |
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+
| Suspend all devices & | SYS_PM_DEEP_SLEEP | | Suspend all devices and | :code:`SYS_PM_DEEP_SLEEP` |
| | | | | |
| Enter Deep Sleep | | | Enter Deep Sleep | |
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+
| Suspend some or all devices &| SYS_PM_DEVICE_SUSPEND_ONLY| | Suspend some or all devices and | :code:`SYS_PM_DEVICE_SUSPEND_ONLY` |
| | | | | |
| No CPU/SoC PM Operation | | | No CPU/SoC PM Operation | |
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+
| No PM operation | SYS_PM_NOT_HANDLED | | No PM operation | :code:`SYS_PM_NOT_HANDLED` |
+------------------------------+---------------------------+ +---------------------------------+---------------------------------------+