doc: pm: split sections and move to guides
Splitted the PM reference document into smaller chunks (overview, system, device and device_runtime). Moved this content to the guides section, since the documentation intent is to provide general PM subsys information and usage guidelines. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
This commit is contained in:
parent
11cf06f5d5
commit
4d6803383d
9 changed files with 464 additions and 456 deletions
|
@ -18,6 +18,7 @@ User and Developer Guides
|
||||||
device_mgmt/index
|
device_mgmt/index
|
||||||
dts/index
|
dts/index
|
||||||
pinctrl/index
|
pinctrl/index
|
||||||
|
pm/index
|
||||||
emulator/index.rst
|
emulator/index.rst
|
||||||
|
|
||||||
modules.rst
|
modules.rst
|
||||||
|
|
236
doc/guides/pm/device.rst
Normal file
236
doc/guides/pm/device.rst
Normal file
|
@ -0,0 +1,236 @@
|
||||||
|
Device Power Management Infrastructure
|
||||||
|
######################################
|
||||||
|
|
||||||
|
The device power management infrastructure consists of interfaces to the
|
||||||
|
:ref:`device_model_api`. These APIs send control commands to the device driver
|
||||||
|
to update its power state or to get its current power state.
|
||||||
|
|
||||||
|
Zephyr RTOS supports two methods of doing device power management.
|
||||||
|
|
||||||
|
* Runtime Device Power Management
|
||||||
|
* System Power Management
|
||||||
|
|
||||||
|
Runtime Device Power Management
|
||||||
|
*******************************
|
||||||
|
|
||||||
|
In this method, the application or any component that deals with devices directly
|
||||||
|
and has the best knowledge of their use, performs the device power management. This
|
||||||
|
saves power if some devices that are not in use can be turned off or put
|
||||||
|
in power saving mode. This method allows saving power even when the CPU is
|
||||||
|
active. The components that use the devices need to be power aware and should
|
||||||
|
be able to make decisions related to managing device power.
|
||||||
|
|
||||||
|
In this method, the SOC interface can enter CPU or SOC power states quickly when
|
||||||
|
:code:`pm_system_suspend()` gets called. This is because it does not need to
|
||||||
|
spend time doing device power management if the devices are already put in the
|
||||||
|
appropriate power state by the application or component managing the devices.
|
||||||
|
|
||||||
|
System Power Management
|
||||||
|
***********************
|
||||||
|
|
||||||
|
In this method device power management is mostly done inside
|
||||||
|
:code:`pm_system_suspend()` along with entering a CPU or SOC power state.
|
||||||
|
|
||||||
|
If a decision to enter a lower power state is made, the implementation would enter it
|
||||||
|
only after checking if the devices are not in the middle of a hardware
|
||||||
|
transaction that cannot be interrupted. This method can be used in
|
||||||
|
implementations where the applications and components using devices are not
|
||||||
|
expected to be power aware and do not implement runtime device power management.
|
||||||
|
|
||||||
|
.. image:: images/central_method.svg
|
||||||
|
:align: center
|
||||||
|
|
||||||
|
This method can also be used to emulate a hardware feature supported by some
|
||||||
|
SOCs which triggers automatic entry to a lower power state when all devices are idle.
|
||||||
|
Refer to `Busy Status Indication`_ to see how to indicate whether a device is busy
|
||||||
|
or idle.
|
||||||
|
|
||||||
|
Device Power Management States
|
||||||
|
******************************
|
||||||
|
The power management subsystem defines four device states.
|
||||||
|
These states are classified based on the degree of device context that gets lost
|
||||||
|
in those states, kind of operations done to save power, and the impact on the
|
||||||
|
device behavior due to the state transition. Device context includes device
|
||||||
|
registers, clocks, memory etc.
|
||||||
|
|
||||||
|
The three device power states:
|
||||||
|
|
||||||
|
:code:`PM_DEVICE_STATE_ACTIVE`
|
||||||
|
|
||||||
|
Normal operation of the device. All device context is retained.
|
||||||
|
|
||||||
|
:code:`PM_DEVICE_STATE_SUSPENDED`
|
||||||
|
|
||||||
|
The system is idle and entering a low power state. Most device context is
|
||||||
|
lost by the hardware. Device drivers must save and restore or reinitialize
|
||||||
|
any context lost by the hardware. Devices can check which state the system
|
||||||
|
is entering calling :c:func:`pm_power_state_next_get()` .
|
||||||
|
|
||||||
|
:code:`PM_DEVICE_STATE_OFF`
|
||||||
|
|
||||||
|
Power has been fully removed from the device. The device context is lost
|
||||||
|
when this state is entered. Need to reinitialize the device when powering
|
||||||
|
it back on.
|
||||||
|
|
||||||
|
Device Power Management Operations
|
||||||
|
**********************************
|
||||||
|
|
||||||
|
Zephyr RTOS power management subsystem provides a control function interface
|
||||||
|
to device drivers to indicate power management operations to perform. Each
|
||||||
|
device driver defines:
|
||||||
|
|
||||||
|
* The device's supported power states.
|
||||||
|
* The device's supported transitions between power states.
|
||||||
|
* The device's necessary operations to handle the transition between power states.
|
||||||
|
|
||||||
|
The following are some examples of operations that the device driver may perform
|
||||||
|
in transition between power states:
|
||||||
|
|
||||||
|
* Save/Restore device states.
|
||||||
|
* Gate/Un-gate clocks.
|
||||||
|
* Gate/Un-gate power.
|
||||||
|
* Mask/Un-mask interrupts.
|
||||||
|
|
||||||
|
Device Model with Power Management Support
|
||||||
|
******************************************
|
||||||
|
|
||||||
|
Drivers initialize the devices using macros. See :ref:`device_model_api` for
|
||||||
|
details on how these macros are used. Use the DEVICE_DEFINE macro to initialize
|
||||||
|
drivers providing power management support via the PM control function.
|
||||||
|
One of the macro parameters is the pointer to the PM action callback.
|
||||||
|
If the driver doesn't implement any power control operations, it can initialize
|
||||||
|
the corresponding pointer with ``NULL``.
|
||||||
|
|
||||||
|
Device Power Management API
|
||||||
|
***************************
|
||||||
|
|
||||||
|
The SOC interface and application use these APIs to perform power management
|
||||||
|
operations on the devices.
|
||||||
|
|
||||||
|
Get Device List
|
||||||
|
===============
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
size_t z_device_get_all_static(struct device const **device_list);
|
||||||
|
|
||||||
|
The Zephyr RTOS kernel internally maintains a list of all devices in the system.
|
||||||
|
The SOC interface uses this API to get the device list. The SOC interface can use the list to
|
||||||
|
identify the devices on which to execute power management operations.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Ensure that the SOC interface does not alter the original list. Since the kernel
|
||||||
|
uses the original list, it must remain unchanged.
|
||||||
|
|
||||||
|
Device Set Power State
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int pm_device_state_set(const struct device *dev, enum pm_device_state state);
|
||||||
|
|
||||||
|
Calls the device PM action callback with the provided state.
|
||||||
|
|
||||||
|
Device Get Power State
|
||||||
|
======================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int pm_device_state_get(const struct device *dev, enum pm_device_state *state);
|
||||||
|
|
||||||
|
.. _pm-device-busy:
|
||||||
|
|
||||||
|
Busy Status Indication
|
||||||
|
**********************
|
||||||
|
|
||||||
|
The SOC interface executes some power policies that can turn off power to devices,
|
||||||
|
causing them to lose their state. If the devices are in the middle of some
|
||||||
|
hardware transaction, like writing to flash memory when the power is turned
|
||||||
|
off, then such transactions would be left in an inconsistent state. This
|
||||||
|
infrastructure guards such transactions by indicating to the SOC interface that
|
||||||
|
the device is in the middle of a hardware transaction.
|
||||||
|
|
||||||
|
When the :c:func:`pm_system_suspend()` is called, depending on the power state
|
||||||
|
returned by the policy manager, the system may suspend or put devices in low
|
||||||
|
power if they are not marked as busy.
|
||||||
|
|
||||||
|
Here are the APIs used to set, clear, and check the busy status of devices.
|
||||||
|
|
||||||
|
Indicate Busy Status API
|
||||||
|
========================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void device_busy_set(const struct device *busy_dev);
|
||||||
|
|
||||||
|
Sets a bit corresponding to the device, in a data structure maintained by the
|
||||||
|
kernel, to indicate whether or not it is in the middle of a transaction.
|
||||||
|
|
||||||
|
Clear Busy Status API
|
||||||
|
=====================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void device_busy_clear(const struct device *busy_dev);
|
||||||
|
|
||||||
|
Clears the bit corresponding to the device in a data structure
|
||||||
|
maintained by the kernel to indicate that the device is not in the middle of
|
||||||
|
a transaction.
|
||||||
|
|
||||||
|
Check Busy Status of Single Device API
|
||||||
|
======================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int device_busy_check(const struct device *chk_dev);
|
||||||
|
|
||||||
|
Checks whether a device is busy. The API returns 0 if the device
|
||||||
|
is not busy.
|
||||||
|
|
||||||
|
This API is used by the system power management.
|
||||||
|
|
||||||
|
Check Busy Status of All Devices API
|
||||||
|
====================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int device_any_busy_check(void);
|
||||||
|
|
||||||
|
Checks if any device is busy. The API returns 0 if no device in the system is busy.
|
||||||
|
|
||||||
|
Wakeup capability
|
||||||
|
*****************
|
||||||
|
|
||||||
|
Some devices are capable of waking the system up from a sleep state.
|
||||||
|
When a device has such capability, applications can enable or disable
|
||||||
|
this feature on a device dynamically using
|
||||||
|
:c:func:`pm_device_wakeup_enable`.
|
||||||
|
|
||||||
|
This property can be set on device declaring the property ``wakeup-source`` in
|
||||||
|
the device node in devicetree. For example, this devicetree fragment sets the
|
||||||
|
``gpio0`` device as a "wakeup" source:
|
||||||
|
|
||||||
|
.. code-block:: devicetree
|
||||||
|
|
||||||
|
gpio0: gpio@40022000 {
|
||||||
|
compatible = "ti,cc13xx-cc26xx-gpio";
|
||||||
|
reg = <0x40022000 0x400>;
|
||||||
|
interrupts = <0 0>;
|
||||||
|
status = "disabled";
|
||||||
|
label = "GPIO_0";
|
||||||
|
gpio-controller;
|
||||||
|
wakeup-source;
|
||||||
|
#gpio-cells = <2>;
|
||||||
|
};
|
||||||
|
|
||||||
|
By default, "wakeup" capable devices do not have this functionality enabled
|
||||||
|
during the device initialization. Applications can enable this functionality
|
||||||
|
later calling :c:func:`pm_device_wakeup_enable`.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This property is **only** used by the system power management to identify
|
||||||
|
devices that should not be suspended.
|
||||||
|
It is responsability of driver or the application to do any additional
|
||||||
|
configuration required by the device to support it.
|
73
doc/guides/pm/device_runtime.rst
Normal file
73
doc/guides/pm/device_runtime.rst
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
Device Runtime Power Management
|
||||||
|
###############################
|
||||||
|
|
||||||
|
The Device Runtime Power Management framework is an Active Power
|
||||||
|
Management mechanism which reduces the overall system Power consumtion
|
||||||
|
by suspending the devices which are idle or not being used while the
|
||||||
|
System is active or running.
|
||||||
|
|
||||||
|
The framework uses :c:func:`pm_device_state_set()` API set the
|
||||||
|
device power state accordingly based on the usage count.
|
||||||
|
|
||||||
|
The interfaces and APIs provided by the Device Runtime PM are
|
||||||
|
designed to be generic and architecture independent.
|
||||||
|
|
||||||
|
Device Runtime Power Management API
|
||||||
|
***********************************
|
||||||
|
|
||||||
|
The Device Drivers use these APIs to perform device runtime power
|
||||||
|
management operations on the devices.
|
||||||
|
|
||||||
|
Enable Device Runtime Power Management of a Device API
|
||||||
|
======================================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void pm_device_runtime_enable(const struct device *dev);
|
||||||
|
|
||||||
|
Enables Runtime Power Management of the device.
|
||||||
|
|
||||||
|
Disable Device Runtime Power Management of a Device API
|
||||||
|
=======================================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
void pm_device_runtime_disable(const struct device *dev);
|
||||||
|
|
||||||
|
Disables Runtime Power Management of the device.
|
||||||
|
|
||||||
|
Resume Device synchronously API
|
||||||
|
===============================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int pm_device_runtime_get(const struct device *dev);
|
||||||
|
|
||||||
|
Marks the device as being used. It will bring up or resume
|
||||||
|
the device if it is in suspended state based on the device
|
||||||
|
usage count. This call is blocked until the device PM state
|
||||||
|
is changed to active. The API returns 0 on success.
|
||||||
|
|
||||||
|
Suspend Device asynchronously API
|
||||||
|
=================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int pm_device_runtime_put_async(const struct device *dev);
|
||||||
|
|
||||||
|
Releases a device. This API asynchronously puts the device to suspend
|
||||||
|
state if not already in suspend state if the usage count of this device
|
||||||
|
reaches 0.
|
||||||
|
|
||||||
|
Suspend Device synchronously API
|
||||||
|
================================
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
int pm_device_runtime_put(const struct device *dev);
|
||||||
|
|
||||||
|
Marks the device as being released. It will put the device to
|
||||||
|
suspended state if is is in active state based on the device
|
||||||
|
usage count. This call is blocked until the device PM state
|
||||||
|
is changed to resume. The API returns 0 on success. This
|
||||||
|
call is blocked until the device is suspended.
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
16
doc/guides/pm/index.rst
Normal file
16
doc/guides/pm/index.rst
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.. _pm-guide:
|
||||||
|
|
||||||
|
Power Management
|
||||||
|
################
|
||||||
|
|
||||||
|
Zephyr RTOS power management subsystem provides several means for a system
|
||||||
|
integrator to implement power management support that can take full
|
||||||
|
advantage of the power saving features of SOCs.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 2
|
||||||
|
|
||||||
|
overview
|
||||||
|
system
|
||||||
|
device
|
||||||
|
device_runtime
|
17
doc/guides/pm/overview.rst
Normal file
17
doc/guides/pm/overview.rst
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
Overview
|
||||||
|
########
|
||||||
|
|
||||||
|
The interfaces and APIs provided by the power management subsystem
|
||||||
|
are designed to be architecture and SOC independent. This enables power
|
||||||
|
management implementations to be easily adapted to different SOCs and
|
||||||
|
architectures.
|
||||||
|
|
||||||
|
The architecture and SOC independence is achieved by separating the core
|
||||||
|
infrastructure and the SOC specific implementations. The SOC specific
|
||||||
|
implementations are abstracted to the application and the OS using hardware
|
||||||
|
abstraction layers.
|
||||||
|
|
||||||
|
The power management features are classified into the following categories.
|
||||||
|
|
||||||
|
* System Power Management
|
||||||
|
* Device Power Management
|
121
doc/guides/pm/system.rst
Normal file
121
doc/guides/pm/system.rst
Normal file
|
@ -0,0 +1,121 @@
|
||||||
|
System Power Management
|
||||||
|
#######################
|
||||||
|
|
||||||
|
The kernel enters the idle state when it has nothing to schedule. If enabled via
|
||||||
|
the :kconfig:`CONFIG_PM` Kconfig option, the Power Management
|
||||||
|
Subsystem can put an idle system in one of the supported power states, based
|
||||||
|
on the selected power management policy and the duration of the idle time
|
||||||
|
allotted by the kernel.
|
||||||
|
|
||||||
|
It is an application responsibility to set up a wake up event. A wake up event
|
||||||
|
will typically be an interrupt triggered by one of the SoC peripheral modules
|
||||||
|
such as a SysTick, RTC, counter, or GPIO. Depending on the power mode entered,
|
||||||
|
only some SoC peripheral modules may be active and can be used as a wake up
|
||||||
|
source.
|
||||||
|
|
||||||
|
The following diagram describes system power management:
|
||||||
|
|
||||||
|
.. image:: images/system-pm.svg
|
||||||
|
:align: center
|
||||||
|
:alt: System power management
|
||||||
|
|
||||||
|
Some handful examples using different power management features:
|
||||||
|
|
||||||
|
* :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/`
|
||||||
|
* :zephyr_file:`samples/boards/nrf/system_off/`
|
||||||
|
* :zephyr_file:`samples/subsys/pm/device_pm/`
|
||||||
|
* :zephyr_file:`tests/subsys/pm/power_mgmt/`
|
||||||
|
* :zephyr_file:`tests/subsys/pm/power_mgmt_soc/`
|
||||||
|
* :zephyr_file:`tests/subsys/pm/power_state_api/`
|
||||||
|
|
||||||
|
Power States
|
||||||
|
============
|
||||||
|
|
||||||
|
The power management subsystem contains a set of states based on
|
||||||
|
power consumption and context retention.
|
||||||
|
|
||||||
|
The list of available power states is defined by :c:enum:`pm_state`. In
|
||||||
|
general power states with higher indexes will offer greater power savings and
|
||||||
|
have higher wake latencies. Following is a thorough list of available states:
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_ACTIVE
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_RUNTIME_IDLE
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_IDLE
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_STANDBY
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_RAM
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_DISK
|
||||||
|
|
||||||
|
.. doxygenenumvalue:: PM_STATE_SOFT_OFF
|
||||||
|
|
||||||
|
.. _pm_constraints:
|
||||||
|
|
||||||
|
Power States Constraint
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The power management subsystem allows different Zephyr components and
|
||||||
|
applications to set constraints on various power states preventing the
|
||||||
|
system from transitiioning into these states. This can be used by devices when executing
|
||||||
|
tasks in background to avoid the system to go to a specific state where it would
|
||||||
|
lose context. Constraints can be set, released and checked using the
|
||||||
|
follow APIs:
|
||||||
|
|
||||||
|
.. doxygenfunction:: pm_constraint_set
|
||||||
|
|
||||||
|
.. doxygenfunction:: pm_constraint_release
|
||||||
|
|
||||||
|
.. doxygenfunction:: pm_constraint_get
|
||||||
|
|
||||||
|
Power Management Policies
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The power management subsystem supports the following power management policies:
|
||||||
|
|
||||||
|
* Residency based
|
||||||
|
* Application defined
|
||||||
|
|
||||||
|
The policy manager is responsible for informing the power subsystem which
|
||||||
|
power state the system should transition to based on states defined by the
|
||||||
|
platform and possible runtime :ref:`constraints<pm_constraints>`
|
||||||
|
|
||||||
|
Information about states can be found in the device tree, see
|
||||||
|
:zephyr_file:`dts/bindings/power/state.yaml`.
|
||||||
|
|
||||||
|
Residency
|
||||||
|
---------
|
||||||
|
|
||||||
|
The power management system enters the power state which offers the highest
|
||||||
|
power savings, and with a minimum residency value (in device tree, see
|
||||||
|
:zephyr_file:`dts/bindings/power/state.yaml`) less than or equal to
|
||||||
|
the scheduled system idle time duration.
|
||||||
|
|
||||||
|
This policy also accounts for the time necessary to become active
|
||||||
|
again. The core logic used by this policy to select the best power
|
||||||
|
state is:
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
if (time_to_next_scheduled_event >= (state.min_residency_us + state.exit_latency))) {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
|
||||||
|
Application
|
||||||
|
-----------
|
||||||
|
|
||||||
|
The power management policy is defined by the application which has to implement
|
||||||
|
the following function.
|
||||||
|
|
||||||
|
.. code-block:: c
|
||||||
|
|
||||||
|
struct pm_state_info pm_policy_next_state(int32_t ticks);
|
||||||
|
|
||||||
|
In this policy the application is free to decide which power state the
|
||||||
|
system should transition to based on the remaining time for the next scheduled
|
||||||
|
timeout.
|
||||||
|
|
||||||
|
An example of an application that defines its own policy can be found in
|
||||||
|
:zephyr_file:`tests/subsys/pm/power_mgmt/`.
|
|
@ -3,462 +3,6 @@
|
||||||
Power Management
|
Power Management
|
||||||
################
|
################
|
||||||
|
|
||||||
Zephyr RTOS power management subsystem provides several means for a system
|
|
||||||
integrator to implement power management support that can take full
|
|
||||||
advantage of the power saving features of SOCs.
|
|
||||||
|
|
||||||
Overview
|
|
||||||
********
|
|
||||||
|
|
||||||
The interfaces and APIs provided by the power management subsystem
|
|
||||||
are designed to be architecture and SOC independent. This enables power
|
|
||||||
management implementations to be easily adapted to different SOCs and
|
|
||||||
architectures.
|
|
||||||
|
|
||||||
The architecture and SOC independence is achieved by separating the core
|
|
||||||
infrastructure and the SOC specific implementations. The SOC specific
|
|
||||||
implementations are abstracted to the application and the OS using hardware
|
|
||||||
abstraction layers.
|
|
||||||
|
|
||||||
The power management features are classified into the following categories.
|
|
||||||
|
|
||||||
* System Power Management
|
|
||||||
* Device Power Management
|
|
||||||
|
|
||||||
System Power Management
|
|
||||||
***********************
|
|
||||||
|
|
||||||
The kernel enters the idle state when it has nothing to schedule. If enabled via
|
|
||||||
the :kconfig:`CONFIG_PM` Kconfig option, the Power Management
|
|
||||||
Subsystem can put an idle system in one of the supported power states, based
|
|
||||||
on the selected power management policy and the duration of the idle time
|
|
||||||
allotted by the kernel.
|
|
||||||
|
|
||||||
It is an application responsibility to set up a wake up event. A wake up event
|
|
||||||
will typically be an interrupt triggered by one of the SoC peripheral modules
|
|
||||||
such as a SysTick, RTC, counter, or GPIO. Depending on the power mode entered,
|
|
||||||
only some SoC peripheral modules may be active and can be used as a wake up
|
|
||||||
source.
|
|
||||||
|
|
||||||
The following diagram describes system power management:
|
|
||||||
|
|
||||||
.. image:: system-pm.svg
|
|
||||||
:align: center
|
|
||||||
:alt: System power management
|
|
||||||
|
|
||||||
Some handful examples using different power management features:
|
|
||||||
|
|
||||||
* :zephyr_file:`samples/boards/stm32/power_mgmt/blinky/`
|
|
||||||
* :zephyr_file:`samples/boards/nrf/system_off/`
|
|
||||||
* :zephyr_file:`samples/subsys/pm/device_pm/`
|
|
||||||
* :zephyr_file:`tests/subsys/pm/power_mgmt/`
|
|
||||||
* :zephyr_file:`tests/subsys/pm/power_mgmt_soc/`
|
|
||||||
* :zephyr_file:`tests/subsys/pm/power_state_api/`
|
|
||||||
|
|
||||||
Power States
|
|
||||||
============
|
|
||||||
|
|
||||||
The power management subsystem contains a set of states based on
|
|
||||||
power consumption and context retention.
|
|
||||||
|
|
||||||
The list of available power states is defined by :c:enum:`pm_state`. In
|
|
||||||
general power states with higher indexes will offer greater power savings and
|
|
||||||
have higher wake latencies. Following is a thorough list of available states:
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_ACTIVE
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_RUNTIME_IDLE
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_IDLE
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_STANDBY
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_RAM
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_SUSPEND_TO_DISK
|
|
||||||
|
|
||||||
.. doxygenenumvalue:: PM_STATE_SOFT_OFF
|
|
||||||
|
|
||||||
.. _pm_constraints:
|
|
||||||
|
|
||||||
Power States Constraint
|
|
||||||
=======================
|
|
||||||
|
|
||||||
The power management subsystem allows different Zephyr components and
|
|
||||||
applications to set constraints on various power states preventing the
|
|
||||||
system from transitiioning into these states. This can be used by devices when executing
|
|
||||||
tasks in background to avoid the system to go to a specific state where it would
|
|
||||||
lose context. Constraints can be set, released and checked using the
|
|
||||||
follow APIs:
|
|
||||||
|
|
||||||
.. doxygenfunction:: pm_constraint_set
|
|
||||||
|
|
||||||
.. doxygenfunction:: pm_constraint_release
|
|
||||||
|
|
||||||
.. doxygenfunction:: pm_constraint_get
|
|
||||||
|
|
||||||
Power Management Policies
|
|
||||||
=========================
|
|
||||||
|
|
||||||
The power management subsystem supports the following power management policies:
|
|
||||||
|
|
||||||
* Residency based
|
|
||||||
* Application defined
|
|
||||||
|
|
||||||
The policy manager is responsible for informing the power subsystem which
|
|
||||||
power state the system should transition to based on states defined by the
|
|
||||||
platform and possible runtime :ref:`constraints<pm_constraints>`
|
|
||||||
|
|
||||||
Information about states can be found in the device tree, see
|
|
||||||
:zephyr_file:`dts/bindings/power/state.yaml`.
|
|
||||||
|
|
||||||
Residency
|
|
||||||
---------
|
|
||||||
|
|
||||||
The power management system enters the power state which offers the highest
|
|
||||||
power savings, and with a minimum residency value (in device tree, see
|
|
||||||
:zephyr_file:`dts/bindings/power/state.yaml`) less than or equal to
|
|
||||||
the scheduled system idle time duration.
|
|
||||||
|
|
||||||
This policy also accounts for the time necessary to become active
|
|
||||||
again. The core logic used by this policy to select the best power
|
|
||||||
state is:
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
if (time_to_next_scheduled_event >= (state.min_residency_us + state.exit_latency))) {
|
|
||||||
return state
|
|
||||||
}
|
|
||||||
|
|
||||||
Application
|
|
||||||
-----------
|
|
||||||
|
|
||||||
The power management policy is defined by the application which has to implement
|
|
||||||
the following function.
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
struct pm_state_info pm_policy_next_state(int32_t ticks);
|
|
||||||
|
|
||||||
In this policy the application is free to decide which power state the
|
|
||||||
system should transition to based on the remaining time for the next scheduled
|
|
||||||
timeout.
|
|
||||||
|
|
||||||
An example of an application that defines its own policy can be found in
|
|
||||||
:zephyr_file:`tests/subsys/pm/power_mgmt/`.
|
|
||||||
|
|
||||||
Device Power Management Infrastructure
|
|
||||||
**************************************
|
|
||||||
|
|
||||||
The device power management infrastructure consists of interfaces to the
|
|
||||||
:ref:`device_model_api`. These APIs send control commands to the device driver
|
|
||||||
to update its power state or to get its current power state.
|
|
||||||
|
|
||||||
Zephyr RTOS supports two methods of doing device power management.
|
|
||||||
|
|
||||||
* Runtime Device Power Management
|
|
||||||
* System Power Management
|
|
||||||
|
|
||||||
Runtime Device Power Management
|
|
||||||
===============================
|
|
||||||
|
|
||||||
In this method, the application or any component that deals with devices directly
|
|
||||||
and has the best knowledge of their use, performs the device power management. This
|
|
||||||
saves power if some devices that are not in use can be turned off or put
|
|
||||||
in power saving mode. This method allows saving power even when the CPU is
|
|
||||||
active. The components that use the devices need to be power aware and should
|
|
||||||
be able to make decisions related to managing device power.
|
|
||||||
|
|
||||||
In this method, the SOC interface can enter CPU or SOC power states quickly when
|
|
||||||
:code:`pm_system_suspend()` gets called. This is because it does not need to
|
|
||||||
spend time doing device power management if the devices are already put in the
|
|
||||||
appropriate power state by the application or component managing the devices.
|
|
||||||
|
|
||||||
System Power Management
|
|
||||||
=======================
|
|
||||||
|
|
||||||
In this method device power management is mostly done inside
|
|
||||||
:code:`pm_system_suspend()` along with entering a CPU or SOC power state.
|
|
||||||
|
|
||||||
If a decision to enter a lower power state is made, the implementation would enter it
|
|
||||||
only after checking if the devices are not in the middle of a hardware
|
|
||||||
transaction that cannot be interrupted. This method can be used in
|
|
||||||
implementations where the applications and components using devices are not
|
|
||||||
expected to be power aware and do not implement runtime device power management.
|
|
||||||
|
|
||||||
.. image:: central_method.svg
|
|
||||||
:align: center
|
|
||||||
|
|
||||||
This method can also be used to emulate a hardware feature supported by some
|
|
||||||
SOCs which triggers automatic entry to a lower power state when all devices are idle.
|
|
||||||
Refer to `Busy Status Indication`_ to see how to indicate whether a device is busy
|
|
||||||
or idle.
|
|
||||||
|
|
||||||
Device Power Management States
|
|
||||||
==============================
|
|
||||||
The power management subsystem defines four device states.
|
|
||||||
These states are classified based on the degree of device context that gets lost
|
|
||||||
in those states, kind of operations done to save power, and the impact on the
|
|
||||||
device behavior due to the state transition. Device context includes device
|
|
||||||
registers, clocks, memory etc.
|
|
||||||
|
|
||||||
The three device power states:
|
|
||||||
|
|
||||||
:code:`PM_DEVICE_STATE_ACTIVE`
|
|
||||||
|
|
||||||
Normal operation of the device. All device context is retained.
|
|
||||||
|
|
||||||
:code:`PM_DEVICE_STATE_SUSPENDED`
|
|
||||||
|
|
||||||
The system is idle and entering a low power state. Most device context is
|
|
||||||
lost by the hardware. Device drivers must save and restore or reinitialize
|
|
||||||
any context lost by the hardware. Devices can check which state the system
|
|
||||||
is entering calling :c:func:`pm_power_state_next_get()` .
|
|
||||||
|
|
||||||
:code:`PM_DEVICE_STATE_OFF`
|
|
||||||
|
|
||||||
Power has been fully removed from the device. The device context is lost
|
|
||||||
when this state is entered. Need to reinitialize the device when powering
|
|
||||||
it back on.
|
|
||||||
|
|
||||||
Device Power Management Operations
|
|
||||||
==================================
|
|
||||||
|
|
||||||
Zephyr RTOS power management subsystem provides a control function interface
|
|
||||||
to device drivers to indicate power management operations to perform. Each
|
|
||||||
device driver defines:
|
|
||||||
|
|
||||||
* The device's supported power states.
|
|
||||||
* The device's supported transitions between power states.
|
|
||||||
* The device's necessary operations to handle the transition between power states.
|
|
||||||
|
|
||||||
The following are some examples of operations that the device driver may perform
|
|
||||||
in transition between power states:
|
|
||||||
|
|
||||||
* Save/Restore device states.
|
|
||||||
* Gate/Un-gate clocks.
|
|
||||||
* Gate/Un-gate power.
|
|
||||||
* Mask/Un-mask interrupts.
|
|
||||||
|
|
||||||
Device Model with Power Management Support
|
|
||||||
==========================================
|
|
||||||
|
|
||||||
Drivers initialize the devices using macros. See :ref:`device_model_api` for
|
|
||||||
details on how these macros are used. Use the DEVICE_DEFINE macro to initialize
|
|
||||||
drivers providing power management support via the PM control function.
|
|
||||||
One of the macro parameters is the pointer to the PM action callback.
|
|
||||||
If the driver doesn't implement any power control operations, it can initialize
|
|
||||||
the corresponding pointer with ``NULL``.
|
|
||||||
|
|
||||||
Device Power Management API
|
|
||||||
===========================
|
|
||||||
|
|
||||||
The SOC interface and application use these APIs to perform power management
|
|
||||||
operations on the devices.
|
|
||||||
|
|
||||||
Get Device List
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
size_t z_device_get_all_static(struct device const **device_list);
|
|
||||||
|
|
||||||
The Zephyr RTOS kernel internally maintains a list of all devices in the system.
|
|
||||||
The SOC interface uses this API to get the device list. The SOC interface can use the list to
|
|
||||||
identify the devices on which to execute power management operations.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Ensure that the SOC interface does not alter the original list. Since the kernel
|
|
||||||
uses the original list, it must remain unchanged.
|
|
||||||
|
|
||||||
Device Set Power State
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int pm_device_state_set(const struct device *dev, enum pm_device_state state);
|
|
||||||
|
|
||||||
Calls the device PM action callback with the provided state.
|
|
||||||
|
|
||||||
Device Get Power State
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int pm_device_state_get(const struct device *dev, enum pm_device_state *state);
|
|
||||||
|
|
||||||
Busy Status Indication
|
|
||||||
======================
|
|
||||||
|
|
||||||
The SOC interface executes some power policies that can turn off power to devices,
|
|
||||||
causing them to lose their state. If the devices are in the middle of some
|
|
||||||
hardware transaction, like writing to flash memory when the power is turned
|
|
||||||
off, then such transactions would be left in an inconsistent state. This
|
|
||||||
infrastructure guards such transactions by indicating to the SOC interface that
|
|
||||||
the device is in the middle of a hardware transaction.
|
|
||||||
|
|
||||||
When the :c:func:`pm_system_suspend()` is called, depending on the power state
|
|
||||||
returned by the policy manager, the system may suspend or put devices in low
|
|
||||||
power if they are not marked as busy.
|
|
||||||
|
|
||||||
Here are the APIs used to set, clear, and check the busy status of devices.
|
|
||||||
|
|
||||||
Indicate Busy Status API
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
void device_busy_set(const struct device *busy_dev);
|
|
||||||
|
|
||||||
Sets a bit corresponding to the device, in a data structure maintained by the
|
|
||||||
kernel, to indicate whether or not it is in the middle of a transaction.
|
|
||||||
|
|
||||||
Clear Busy Status API
|
|
||||||
---------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
void device_busy_clear(const struct device *busy_dev);
|
|
||||||
|
|
||||||
Clears the bit corresponding to the device in a data structure
|
|
||||||
maintained by the kernel to indicate that the device is not in the middle of
|
|
||||||
a transaction.
|
|
||||||
|
|
||||||
Check Busy Status of Single Device API
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int device_busy_check(const struct device *chk_dev);
|
|
||||||
|
|
||||||
Checks whether a device is busy. The API returns 0 if the device
|
|
||||||
is not busy.
|
|
||||||
|
|
||||||
This API is used by the system power management.
|
|
||||||
|
|
||||||
Check Busy Status of All Devices API
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int device_any_busy_check(void);
|
|
||||||
|
|
||||||
Checks if any device is busy. The API returns 0 if no device in the system is busy.
|
|
||||||
|
|
||||||
Wakeup capability
|
|
||||||
-----------------
|
|
||||||
|
|
||||||
Some devices are capable of waking the system up from a sleep state.
|
|
||||||
When a device has such capability, applications can enable or disable
|
|
||||||
this feature on a device dynamically using
|
|
||||||
:c:func:`pm_device_wakeup_enable`.
|
|
||||||
|
|
||||||
This property can be set on device declaring the property ``wakeup-source`` in
|
|
||||||
the device node in devicetree. For example, this devicetree fragment sets the
|
|
||||||
``gpio0`` device as a "wakeup" source:
|
|
||||||
|
|
||||||
.. code-block:: devicetree
|
|
||||||
|
|
||||||
gpio0: gpio@40022000 {
|
|
||||||
compatible = "ti,cc13xx-cc26xx-gpio";
|
|
||||||
reg = <0x40022000 0x400>;
|
|
||||||
interrupts = <0 0>;
|
|
||||||
status = "disabled";
|
|
||||||
label = "GPIO_0";
|
|
||||||
gpio-controller;
|
|
||||||
wakeup-source;
|
|
||||||
#gpio-cells = <2>;
|
|
||||||
};
|
|
||||||
|
|
||||||
By default, "wakeup" capable devices do not have this functionality enabled
|
|
||||||
during the device initialization. Applications can enable this functionality
|
|
||||||
later calling :c:func:`pm_device_wakeup_enable`.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
This property is **only** used by the system power management to identify
|
|
||||||
devices that should not be suspended.
|
|
||||||
It is responsability of driver or the application to do any additional
|
|
||||||
configuration required by the device to support it.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Device Runtime Power Management
|
|
||||||
*******************************
|
|
||||||
|
|
||||||
The Device Runtime Power Management framework is an Active Power
|
|
||||||
Management mechanism which reduces the overall system Power consumtion
|
|
||||||
by suspending the devices which are idle or not being used while the
|
|
||||||
System is active or running.
|
|
||||||
|
|
||||||
The framework uses :c:func:`pm_device_state_set()` API set the
|
|
||||||
device power state accordingly based on the usage count.
|
|
||||||
|
|
||||||
The interfaces and APIs provided by the Device Runtime PM are
|
|
||||||
designed to be generic and architecture independent.
|
|
||||||
|
|
||||||
Device Runtime Power Management API
|
|
||||||
===================================
|
|
||||||
|
|
||||||
The Device Drivers use these APIs to perform device runtime power
|
|
||||||
management operations on the devices.
|
|
||||||
|
|
||||||
Enable Device Runtime Power Management of a Device API
|
|
||||||
------------------------------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
void pm_device_runtime_enable(const struct device *dev);
|
|
||||||
|
|
||||||
Enables Runtime Power Management of the device.
|
|
||||||
|
|
||||||
Disable Device Runtime Power Management of a Device API
|
|
||||||
-------------------------------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
void pm_device_runtime_disable(const struct device *dev);
|
|
||||||
|
|
||||||
Disables Runtime Power Management of the device.
|
|
||||||
|
|
||||||
Resume Device synchronously API
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int pm_device_runtime_get(const struct device *dev);
|
|
||||||
|
|
||||||
Marks the device as being used. It will bring up or resume
|
|
||||||
the device if it is in suspended state based on the device
|
|
||||||
usage count. This call is blocked until the device PM state
|
|
||||||
is changed to active. The API returns 0 on success.
|
|
||||||
|
|
||||||
Suspend Device asynchronously API
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int pm_device_runtime_put_async(const struct device *dev);
|
|
||||||
|
|
||||||
Releases a device. This API asynchronously puts the device to suspend
|
|
||||||
state if not already in suspend state if the usage count of this device
|
|
||||||
reaches 0.
|
|
||||||
|
|
||||||
Suspend Device synchronously API
|
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
.. code-block:: c
|
|
||||||
|
|
||||||
int pm_device_runtime_put(const struct device *dev);
|
|
||||||
|
|
||||||
Marks the device as being released. It will put the device to
|
|
||||||
suspended state if is is in active state based on the device
|
|
||||||
usage count. This call is blocked until the device PM state
|
|
||||||
is changed to resume. The API returns 0 on success. This
|
|
||||||
call is blocked until the device is suspended.
|
|
||||||
|
|
||||||
|
|
||||||
Power Management Configuration Flags
|
Power Management Configuration Flags
|
||||||
************************************
|
************************************
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue