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
|
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` |
|
||||||
+------------------------------+---------------------------+
|
+---------------------------------+---------------------------------------+
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue