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:
parent
8b29fb720c
commit
c00cbb7bbf
1 changed files with 403 additions and 355 deletions
|
@ -4,212 +4,252 @@ Power Management
|
|||
################
|
||||
|
||||
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.
|
||||
|
||||
Terminology
|
||||
***********
|
||||
|
||||
`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.
|
||||
:dfn:`PMA`
|
||||
|
||||
`LPS`
|
||||
Any of the CPU low power states supported by the processor.
|
||||
The system integrator provides the :abbr:`PMA (Power Manager
|
||||
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`
|
||||
Power state implemented at the SoC level which includes processor and
|
||||
device power state.
|
||||
:dfn:`LPS`
|
||||
|
||||
`Hook function`
|
||||
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.
|
||||
:abbr:`LPS (Low Power States)` refers to any one of the low power states supported by the CPU.
|
||||
|
||||
**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`
|
||||
The CPU is currently active and running in the hardware defined
|
||||
C0
|
||||
The CPU is active and running.
|
||||
|
||||
`Idle`
|
||||
The CPU is not currently active, and continues to be powered
|
||||
on. The CPU may be in one of any lower C-states (i.e. C1, C2, etc).
|
||||
`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.
|
||||
Stops the processor clock. The ARM documentation describes
|
||||
this as *Sleep*.
|
||||
|
||||
`Deep Sleep`
|
||||
Stops the system clock and switches off the PLL and flash
|
||||
memory. RAM retained.
|
||||
**On ARC:**
|
||||
memory. RAM is retained.
|
||||
|
||||
On ARC
|
||||
------
|
||||
|
||||
`Active`
|
||||
The CPU is currently active and running in the SS0 state.
|
||||
|
||||
`Idle`
|
||||
Defined as the SS1, 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.
|
||||
Defined as the SS1 and SS2 states.
|
||||
|
||||
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
|
||||
********
|
||||
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
|
||||
architecture independent interface. The Zephyr kernel will provide
|
||||
notification methods in both the Microkernel and Nanokernel for the PMA when
|
||||
the OS is about to enter and exit system idle. The PMA will do various power
|
||||
management policy enforcement operations during these notifications.
|
||||
The Zephyr power management subsystem provides interfaces that a system
|
||||
integrator can use to create a PMA. The PMA then enforces any policies
|
||||
needed. The design is based on the philosophy of not enforcing any policies
|
||||
in the kernel giving full flexibility to the PMA.
|
||||
|
||||
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
|
||||
********
|
||||
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
|
||||
on relative power savings and the corresponding wake latencies. These also
|
||||
loosely map to common power states supported by processors and SoCs in the
|
||||
supported architectures. The PMA should map its fine grain custom policies to
|
||||
the policy categories defined by the Power Management subsystem listed below.
|
||||
When the power management subsystem notifies the PMA that the kernel is about
|
||||
to enter a system idle state, it specifies the period of time the system
|
||||
intends to stay idle. The PMA performs any power management operations during
|
||||
this time. The PMA can perform various operations. For example, put the
|
||||
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
|
||||
======================
|
||||
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
|
||||
management operations may involve turning off peripherals and gating device
|
||||
clocks. If any of those operations result in the device registers losing
|
||||
state, then those states would need to be saved and restored. The PMA should
|
||||
map fine grain policies to this category, with relatively less wake latency
|
||||
than those that it maps to `SYS_PM_DEEP_SLEEP`_ category. The exit from this
|
||||
policy is from an external interrupt, a wake up event set by the PMA or when
|
||||
the idle time alloted by the Power Management subsystem expires.
|
||||
|
||||
In this policy category, the PMA performs power management operations on some
|
||||
or all devices and puts the processor into a low power state. The device
|
||||
power management operations can involve turning off peripherals and gating
|
||||
device clocks. When any of those operations causes the device registers to
|
||||
lose their state, then those states must be saved and restored. The PMA
|
||||
should map fine grain policies with relatively less wake latency to this
|
||||
category. Policies with larger wake latency should be mapped to the
|
||||
`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
|
||||
=================
|
||||
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
|
||||
would be turned off. The processor is turned off and would lose state. RAM is
|
||||
expected to be retained and can be used to save and restore processor states.
|
||||
Depending on the SoC, selected devices would also be turned off in the deep
|
||||
sleep power state. Since this would cause device registers to lose state, they
|
||||
would need to be saved and restored. The PMA should map fine grain policies
|
||||
with the highest wake latency to this policy category. The exit from this
|
||||
policy is from SoC dependent wake events.
|
||||
|
||||
In this policy category, the PMA puts the system into the deep sleep power
|
||||
states supported by SoCs. In this state, the system clock is turned off. The
|
||||
processor is turned off and loses its state. RAM is expected to be retained
|
||||
and can save and restore processor states. Only the devices necessary to wake
|
||||
up the system from the deep sleep power state stay on. The SoC turns off the
|
||||
power to all other devices. Since this causes device registers to lose their
|
||||
state, they must be saved and restored. The PMA should map fine grain
|
||||
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
|
||||
==========================
|
||||
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
|
||||
state that it is associated with. e.g. :c:macro:`SYS_PM_DEEP_SLEEP`. However,
|
||||
they should be seen as policy categories and are not intended to indicate any
|
||||
specific processor or SoC power state by itself.
|
||||
Some policy categories names are similar to the power states of processors or
|
||||
SoCs, for example, :code:`SYS_PM_DEEP_SLEEP`. However, they must be seen
|
||||
as policy categories and do not indicate any specific processor or SoC power
|
||||
state by themselves.
|
||||
|
||||
.. _pm_hook_infra:
|
||||
|
||||
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
|
||||
idle state i.e. when it has nothing to schedule. This section will give a
|
||||
general overview and concepts of the hook functions. Refer to
|
||||
:ref:`Power Management APIs <power_management_api>` for detailed description
|
||||
of the APIs.
|
||||
|
||||
This infrastructure consists of the hook functions that the PMA implemented.
|
||||
The power management subsystem calls these hook functions when the kernel
|
||||
enters and exits the idle state, in other words, when the kernel has nothing
|
||||
to schedule. This section provides a general overview and general concepts of
|
||||
the hook functions. Refer to :ref:`power_management_api` for the detailed
|
||||
description of the APIs.
|
||||
|
||||
Suspend Hook function
|
||||
=====================
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int _sys_soc_suspend(int32_t ticks);
|
||||
|
||||
When kernel is about to go idle, the kernel itself will disable interrupts. The
|
||||
kernel will then call the :c:func:`_sys_soc_suspend()` function, notifying the
|
||||
PMA of the operation. Included in the notification are the maximum number of
|
||||
ticks that the system can be set idle for. The PMA will then determine what
|
||||
policies can be executed within the allotted time frame.
|
||||
When the kernel is about to go idle, the power management subsystem calls the
|
||||
:code:`_sys_soc_suspend()` function, notifying the PMA that the kernel is
|
||||
ready to enter the idle state.
|
||||
|
||||
The kernel expects the :c:func:`_sys_soc_suspend()` to return one of the
|
||||
following values based on the policy operation the PMA executed:
|
||||
At this point, the kernel has disabled interrupts and computed the maximum
|
||||
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`
|
||||
No PM operations. Indicating the PMA was not able to accomplish any
|
||||
action in the time allotted by the kernel.
|
||||
The power management subsystem expects the :code:`_sys_soc_suspend()` to
|
||||
return one of the following values based on the power management operations
|
||||
the PMA executed:
|
||||
|
||||
`SYS_PM_DEVICE_SUSPEND_ONLY`
|
||||
Only Devices are suspended. Indicating that the PMA has accomplished
|
||||
any device suspend operations. This does not include any CPU or SOC power
|
||||
operations.
|
||||
:code:`SYS_PM_NOT_HANDLED`
|
||||
|
||||
`SYS_PM_LOW_POWER_STATE`
|
||||
Low Power State. Indicating that the PMA was successful at putting the
|
||||
CPU into a low power state.
|
||||
No power management operations. Indicates that the PMA could not
|
||||
accomplish any actions in the time allotted by the kernel.
|
||||
|
||||
`SYS_PM_DEEP_SLEEP`
|
||||
Deep Sleep. Indicating that the PMA was successful at pushing the SOC
|
||||
into the Deep Sleep state.
|
||||
:code:`SYS_PM_DEVICE_SUSPEND_ONLY`
|
||||
|
||||
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
|
||||
====================
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
void _sys_soc_resume(void);
|
||||
|
||||
This hook function will be called by the kernel when exiting from idle state or
|
||||
from the low power state the PMA put the processor and SoC in. Based on the
|
||||
policy executed by the PMA in :c:func:`_sys_soc_suspend()`, it should do the
|
||||
necessary recovery operations in this function.
|
||||
The kernel calls this hook function when exiting from an idle state or a low
|
||||
power state. Based on which policy the PMA executed in the
|
||||
:code:`_sys_soc_suspend()` function, the PMA performs the necessary recovery
|
||||
operations in this hook function.
|
||||
|
||||
.. note::
|
||||
Since the hook functions are called with interrupts disabled, the PMA should
|
||||
ensure that it completes operations quick so that the kernel's scheduling
|
||||
performance is not disrupted.
|
||||
Since the hook functions are called with the interrupts disabled, the PMA
|
||||
should ensure that its operations are completed quickly. Thus, the PMA
|
||||
ensures that the kernel's scheduling performance is not disrupted.
|
||||
|
||||
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
|
||||
:ref:`Power Management APIs <power_management_api>` for detailed description of
|
||||
the APIs.
|
||||
|
||||
The device power management infrastructure consists of interfaces to the
|
||||
Zephyr device model. These interfaces enable the PMA to suspend and resume
|
||||
operations on devices. Refer to :ref:`power_management_api` for detailed
|
||||
description of the APIs.
|
||||
|
||||
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
|
||||
|
||||
struct device_pm_ops {
|
||||
|
@ -218,353 +258,361 @@ Device PM Operations structure
|
|||
};
|
||||
|
||||
This structure contains pointers to the :c:func:`suspend()` and
|
||||
:c:func:`resume()` handler functions. The device driver should initialize
|
||||
those pointers with the corresponding handler functions that is implemented in
|
||||
the driver.
|
||||
:c:func:`resume()` handler functions. The device driver initializes those
|
||||
pointers with the corresponding handler functions implemented in the
|
||||
driver.
|
||||
|
||||
Default Initializer function for PM ops
|
||||
---------------------------------------
|
||||
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.
|
||||
Default Initializer Function
|
||||
----------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
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
|
||||
|
||||
int suspend(struct device *device, int pm_policy);
|
||||
|
||||
This function is implemented by the device driver to perform suspend operations
|
||||
on the devices it handles. The PMA would call it passing the power policy it
|
||||
is currently executing. The device driver would do operations necessary to
|
||||
handle the transitions associated with the policy specified by the PMA.
|
||||
Example operations that the device driver would do are:
|
||||
The device driver implements this function to perform the suspend operations
|
||||
on the handled devices. The PMA calls the function and passes the power
|
||||
policy to execute. The device driver performs the operations necessary to
|
||||
handle the transitions associated with the policy the PMA specified. Here 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
|
||||
appropriate negative :c:macro:`errno` value.
|
||||
This function returns 0 if successful. Otherwise, the function returns an
|
||||
appropriate negative `errno` value.
|
||||
|
||||
.. _dev_resume_handler:
|
||||
|
||||
Device Resume Operation Handler function
|
||||
Device Resume Operation Handler Function
|
||||
----------------------------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int resume(struct device *device, int pm_policy);
|
||||
|
||||
PMA would call this when it is doing resume operations on devices. The device
|
||||
driver would do the necessary resume operation on its device based on the
|
||||
policy specified by the PMA in the argument.
|
||||
The PMA calls this function to resume operations on the devices on which it
|
||||
had previously performed suspend operations. The device driver performs the
|
||||
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
|
||||
appropriate negative :c:macro:`errno` value.
|
||||
The function returns 0 if successful. In all other cases it returns an
|
||||
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
|
||||
used
|
||||
These macros should be 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
|
||||
=====================
|
||||
These APIs will be used by the PMA to do suspend and resume operations on the
|
||||
:code:`SYS_INIT_PM`
|
||||
|
||||
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.
|
||||
|
||||
Getting the Device List
|
||||
-----------------------
|
||||
Get Device List
|
||||
---------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
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
|
||||
internally maintains for all devices in the system. The device structure in
|
||||
the list will be used to identify devices that the PMA would chose to do PM
|
||||
operations on.
|
||||
The Zephyr kernel internally maintains a list of all devices in the system.
|
||||
The PMA uses this API to get the device list. The PMA can use the list to
|
||||
identify the devices on which to execute power management operations.
|
||||
|
||||
The PMA can use this list to create its own sorted order list based on device
|
||||
dependencies. It can also create device groups to execute different policies
|
||||
The PMA can use this list to create a sorted order list based on device
|
||||
dependencies. The PMA creates device groups to execute different policies
|
||||
on each device group.
|
||||
|
||||
.. 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
|
||||
----------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int device_suspend(struct device *device, int pm_policy);
|
||||
|
||||
This function would call the :c:func:`suspend()` handler function implemented
|
||||
by the device driver for the device. Refer to
|
||||
`Device Suspend Operation Handler function`_ for more information.
|
||||
Calls the :c:func:`suspend()` handler function implemented by the device
|
||||
driver. See :ref:`dev_suspend_handler` for more information.
|
||||
|
||||
PMA Device Resume API
|
||||
---------------------
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
int device_resume(struct device *device, int pm_policy);
|
||||
|
||||
This function would call the :c:func:`resume()` handler function implemented by
|
||||
the device driver for the device. Refer to
|
||||
`Device Resume Operation Handler function`_ for more information.
|
||||
Calls the :c:func:`resume()` handler function implemented by the device
|
||||
driver. See :ref:`dev_resume_handler` for more information.
|
||||
|
||||
Device 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.
|
||||
Busy Status Indication
|
||||
======================
|
||||
|
||||
During a call to :c:func:`_sys_soc_suspend()`, if PMA finds any device is busy,
|
||||
then it may decide to choose a policy other than Deep Sleep or defer PM
|
||||
operations till the next call to :c:func:`_sys_soc_suspend()`.
|
||||
The PMA 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 PMA that
|
||||
the device is in the middle of a hardware transaction.
|
||||
|
||||
.. note::
|
||||
It is up to the device driver writer to decide whether a transaction needs
|
||||
to be guarded using these APIs. If there are other recovery or retrial
|
||||
methods in place, then the driver could choose to avoid guarding the
|
||||
transactions.
|
||||
When the :code:`_sys_soc_suspend()` is called, the PMA checks if any device
|
||||
is busy. The PMA can then decide to execute a policy other than deep sleep or
|
||||
to defer power management operations until the next call of
|
||||
:code:`_sys_soc_suspend()`.
|
||||
|
||||
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
|
||||
|
||||
void device_busy_set(struct device *busy_dev);
|
||||
|
||||
This API will set a bit corresponding to the device, in a data structure
|
||||
maintained by the kernel, to indicate it is in the middle of a transaction.
|
||||
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
|
||||
---------------------
|
||||
|
||||
Device API to Clear Busy Status
|
||||
-------------------------------
|
||||
.. code-block:: c
|
||||
|
||||
void device_busy_clear(struct device *busy_dev);
|
||||
|
||||
This API will clear a bit corresponding to the device, in a data structure
|
||||
maintained by the kernel, to indicate it is not in the middle of a transaction.
|
||||
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
|
||||
--------------------------------------
|
||||
|
||||
PMA API to Check Busy Status of Single Device
|
||||
---------------------------------------------
|
||||
.. code-block:: c
|
||||
|
||||
int device_busy_check(struct device *chk_dev);
|
||||
|
||||
This API is called by the PMA for each device to check its busy status. It
|
||||
returns 0 if the device is not busy.
|
||||
Checks whether a device is busy. The API returns 0 if the device
|
||||
is not busy.
|
||||
|
||||
Check Busy Status of All Devices API
|
||||
------------------------------------
|
||||
|
||||
PMA API to Check Busy Status of All Devices
|
||||
-------------------------------------------
|
||||
.. code-block:: c
|
||||
|
||||
int device_any_busy_check(void);
|
||||
|
||||
This API is called by the PMA to check if any device is busy. It returns 0 if
|
||||
no device in the system is busy.
|
||||
Checks if any device is busy. The API returns 0 if 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 following config flags.
|
||||
the following configuration flags.
|
||||
|
||||
`CONFIG_SYS_POWER_MANAGEMENT`
|
||||
This enables the Power Management Subsystem.
|
||||
:code:`CONFIG_SYS_POWER_MANAGEMENT`
|
||||
|
||||
`CONFIG_SYS_POWER_LOW_POWER_STATE`
|
||||
PMA should enable this flag if it would use `SYS_PM_LOW_POWER_STATE`
|
||||
policy.
|
||||
This flag enables the power management subsystem.
|
||||
|
||||
`CONFIG_SYS_POWER_DEEP_SLEEP`
|
||||
This flag would enable support for the `SYS_PM_DEEP_SLEEP` policy.
|
||||
:code:`CONFIG_SYS_POWER_LOW_POWER_STATE`
|
||||
|
||||
`CONFIG_DEVICE_POWER_MANAGEMENT`
|
||||
This flag should be enabled if device power management is supported by
|
||||
the PMA and the devices.
|
||||
The PMA enables this flag to use the :code:`SYS_PM_LOW_POWER_STATE` policy.
|
||||
|
||||
: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
|
||||
**************************************
|
||||
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
|
||||
that does more than just power management. Here we refer to the Power
|
||||
Management part of the application.
|
||||
The PMA is part of a larger application doing more than just power
|
||||
management. This section focuses on the power management aspects of the
|
||||
application.
|
||||
|
||||
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
|
||||
`Power Management Config Flags`_.
|
||||
#. Enable the :code:`CONFIG_SYS_POWER_MANAGEMENT` flag
|
||||
|
||||
- Implement the hook functions described in
|
||||
`Power Management Hook Infrastructure`_.
|
||||
#. Enable other required config flags described in :ref:`pm_config_flags`.
|
||||
|
||||
Get Device List and Create Policies
|
||||
===================================
|
||||
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.
|
||||
#. Implement the hook functions described in :ref:`pm_hook_infra`.
|
||||
|
||||
The :c:func:`device_list_get()` function will return an array of current
|
||||
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
|
||||
this time fits within the allotted time provided by the kernel. This time
|
||||
value is highly dependent upon each specific device used in the final platform
|
||||
and SOC.
|
||||
Device List and Policies
|
||||
========================
|
||||
|
||||
The PMA retrieves the list of enabled devices in the system using the
|
||||
:c:func:`device_list_get()` function. Since the PMA is part of the
|
||||
application, the PMA starts after all devices in the system have been
|
||||
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
|
||||
groups and sorted lists based on device dependencies. Using the device lists
|
||||
and the known aggregate wake latency of the combination of power operations,
|
||||
the PMA would then create fine grain custom power policies. Finally it would
|
||||
map these custom policies to the policy categories defined by the Power
|
||||
Management subsystem as described in `Policies`_.
|
||||
groups and sorted lists based on device dependencies. The PMA uses the device
|
||||
lists and the known aggregate wake latency of the combination of power
|
||||
operations to create the fine grain custom power policies. Finally, the PMA
|
||||
maps these custom policies to the policy categories defined by the power
|
||||
management subsystem as described in `Policies`_.
|
||||
|
||||
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
|
||||
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.
|
||||
Scenario 1
|
||||
----------
|
||||
|
||||
**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
|
||||
same time.
|
||||
#. The PMA sets up the wake event, puts the CPU in a LPS, and re- enables
|
||||
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
|
||||
the system integrator, the PMA can choose to ignore the failure.
|
||||
* If the system integrator determined that the device is essential to the
|
||||
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
|
||||
system integrator, the PMA shall take any necessary recovery actions and
|
||||
return SYS_PM_NOT_HANDLED.
|
||||
|
||||
**Case 3:**
|
||||
Scenario 3
|
||||
----------
|
||||
|
||||
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
|
||||
|
||||
Re-enable interrupts
|
||||
|
||||
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.
|
||||
* If the system integrator determined that the device is essential to the
|
||||
suspend process, the PMA takes any necessary recovery actions and
|
||||
returns the :code:`SYS_PM_NOT_HANDLED` code.
|
||||
|
||||
Policy Decision Summary
|
||||
=======================
|
||||
|
||||
+------------------------------+---------------------------+
|
||||
| PM operations | Policy and Return Code |
|
||||
+==============================+===========================+
|
||||
| Suspend some devices & | SYS_PM_LOW_POWER_STATE |
|
||||
| | |
|
||||
| Enter Low Power State | |
|
||||
+------------------------------+---------------------------+
|
||||
| Suspend all devices & | SYS_PM_LOW_POWER_STATE |
|
||||
| | |
|
||||
| Enter Low Power State | |
|
||||
+------------------------------+---------------------------+
|
||||
| Suspend all devices & | SYS_PM_DEEP_SLEEP |
|
||||
| | |
|
||||
| Enter Deep Sleep | |
|
||||
+------------------------------+---------------------------+
|
||||
| Suspend some or all devices &| SYS_PM_DEVICE_SUSPEND_ONLY|
|
||||
| | |
|
||||
| No CPU/SoC PM Operation | |
|
||||
+------------------------------+---------------------------+
|
||||
| No PM operation | SYS_PM_NOT_HANDLED |
|
||||
+------------------------------+---------------------------+
|
||||
+---------------------------------+---------------------------------------+
|
||||
| PM operations | Policy and Return Code |
|
||||
+=================================+=======================================+
|
||||
| Suspend some devices and | :code:`SYS_PM_LOW_POWER_STATE` |
|
||||
| | |
|
||||
| Enter Low Power State | |
|
||||
+---------------------------------+---------------------------------------+
|
||||
| Suspend all devices and | :code:`SYS_PM_LOW_POWER_STATE` |
|
||||
| | |
|
||||
| Enter Low Power State | |
|
||||
+---------------------------------+---------------------------------------+
|
||||
| Suspend all devices and | :code:`SYS_PM_DEEP_SLEEP` |
|
||||
| | |
|
||||
| Enter Deep Sleep | |
|
||||
+---------------------------------+---------------------------------------+
|
||||
| Suspend some or all devices and | :code:`SYS_PM_DEVICE_SUSPEND_ONLY` |
|
||||
| | |
|
||||
| No CPU/SoC PM Operation | |
|
||||
+---------------------------------+---------------------------------------+
|
||||
| No PM operation | :code:`SYS_PM_NOT_HANDLED` |
|
||||
+---------------------------------+---------------------------------------+
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue