1. Framework purpose[edit | edit source]
The purpose of this article is to explain the Linux® Power Management on STM32 Arm® Cortex® MPUs :
- Low-power modes available on the device
- Linux software overview for Power Management (on/off support, Suspend / Resume, Idle behavior, policy and control)
- How to enter and exit a platform low-power mode
2. Software overview[edit | edit source]
The Linux® Power Management (PM) is divided in:
- Static PM or System-Wide Power Management:
- suspend framework, used to trigger a low-power mode entry/exit sequence.
- power off
- Dynamic PM or Working-State Power Management or Active Power Management based on other frameworks:
- CPUfreq, Devfreq (see the page How to change the CPU frequency for details)
- OPP with link to thermal framework
- Genpd (performance states)
- Runtime Power Management (RPM or runtime RPM): dynamically disable the resources of the peripherals (clocks and power supply when applicable) in case of inactivity (see power/runtime_pm.html).
- Clocks
- Regulators
- SCMI framework for system resources
Refer to Linux documentation for more details, for example pages in Documentation/power and in Documentation/admin-guide/pm.
The OpenSTLinux power management support is based on Arm® interface specifications:
2.1. STM32MP1 series[edit | edit source]
On STM32MP1 series, the "System-Wide Power Management" is supported:
The user application issues a suspend request to the kernel. This request is handled by the suspend Framework, which notifies all the device drivers to prepare for low-power entry. It then calls the PSCI service.
See also STM32MP1 power overview for details.
2.2. STM32MP2 series[edit | edit source]
The "System-Wide Power Management" is supported:
When the user application sent a suspend request to the kernel (static), it is treated by the suspend framework with the PSCI suspend support.
For OS initiated low power mode (dynamic), the application idle is detected when the Linux scheduler has no thread to run and treated by CPUIdle PSCI driver and the low power mode is selected with generic power domains (GenPD).
See also STM32MP2 power overview for details.
2.3. Component description[edit | edit source]
Kernel components for low power:
- Suspend framework: this framework schedules the overall sequence by stopping all the ongoing tasks
- GenPD: generic power domain framework, based on runtime PM
- GenPD driver: this STMicrolectronics driver is used for low-power mode selection according to the activated wakeup sources on STM32MP1 series.
- PM runtime: device activity framework, used by each device driver
- PSCI library: this is a set of standardized functions to request a low-power service to the secure monitor
- PSCI cpuidle: CPU activity driver based on CPUIdle framework to handle Idle
- Device driver: any peripheral driver which needs to control power.
Secure monitor and secure world components (OP-TEE) on AArch32 platforms for STM32MP1 series :
- Low power driver: the role of this driver is to choose the low-power mode according to the programmed wakeup source(s)
- PWR driver: this driver is responsible for configuring the low-power mode
- RCC driver: this driver handles the circuit secure clocks
- PSCI libray: generic PSCI stack
Secure world components (OP-TEE) on AArch64 platforms for STM32MP2 series:
- PM framework: call the low-power callback of each device on the call of TF-A BL31 hooks.
- Device drivers: driver of secure device
Secure monitor components (TF-A BL31) on AArch64 platforms for STM32MP2 series
- PM manage PSCI topology and modes and DDR self refresh
- PSCI libray: generic PSCI stack
- DDR driver: DDR driver
STM32 peripherals (Hardware):
2.4. API description[edit | edit source]
The suspend process is triggered from the user space through standard commands (see next chapter for details).
The system sleep control file is the state file, located under: /sys/power/
Further details can be found in admin-guide/pm/sleep-states.html and in power/interface.html.
The sysfs ABI are described in sysfs-power and sysfs-devices-power.
The device power API are described in driver-api/pm/index.html, in particular in driver-api/pm/devices.html.
3. Configuration[edit | edit source]
The objective of this chapter is to explain how to configure the Linux kernel and device tree to have the Power Management (PM) framework activated.
3.1. Kernel configuration[edit | edit source]
The Power Management framework is activated by default in ST deliveries.
It can be deactivated through the kernel menuconfig using Power management options/Suspend to RAM and standby: Menuconfig or how to configure kernel .
3.2. Device tree configuration[edit | edit source]
3.2.1. STM32MP1 series[edit | edit source]
The default system low-power mode mapping can be modified through the secure monitor device tree, as described OP-TEE documentation/devicetree/bindings/regulator/st,stm32mp1-pwr-reg.yaml .
See STM32MP1 power overview for impacts on OP-TEE device tree.
3.2.2. STM32MP2 series[edit | edit source]
The SoC device tree describes the PSCI topology in sub-nodes of cpus/domain-idle-states
in arch/arm64/boot/dts/st/stm32mp251.dtsi , one node for each PSCI_CPU_SUSPEND supported parameter (only the Stop1 modes):
domain-idle-states {
STOP1: domain-stop1 {
compatible = "domain-idle-state";
arm,psci-suspend-param = <0x00000011>;
};
LP_STOP1: domain-lp-stop1 {
compatible = "domain-idle-state";
arm,psci-suspend-param = <0x0000021>;
};
LPLV_STOP1: domain-lplv-stop1 {
compatible = "domain-idle-state";
arm,psci-suspend-param = <0x00000211>;
};
};
The unsupported low power modes and associated references in domain-idle-states power domain nodes must be deleted from TF-A BL31 and Linux board device-tree files.
For example on board without STPMIC25, if the PWR_LP pins control the reduced voltage mode of the VDDCORE and VDDCPU regulators, then only LPLV-StopX modes can be reached. LP-StopX modes must be deleted in Linux device tree (CLUSTER_PD domain-idle-states = <&STOP1>, <&LP_STOP1>;
for CLUSTER_PD in arch/arm64/boot/dts/st/stm32mp251.dts ):
/ { cpus { domain-idle-states { /delete-node/ domain-lp-stop1; }; }; }; &CLUSTER_PD { domain-idle-states = <&STOP1>; };
See STM32MP2_power_overview for impacts on TF-A BL31 device tree.
4. How to use the framework[edit | edit source]
The power framework is managed with userfs API.
For Weston OpenSTLinux distribution, the direct access to sysfs must be avoided and must be replaced by systemctl
command to correctly stop the systemd services and avoid issues on next wake-up.
Linux mode | userFS API | command | STM32MP1 series | STM32MP2 series |
---|---|---|---|---|
S2Idle Suspend-to-Idle (or freeze) |
echo freeze > /sys/power/state | with SuspendState=freeze in /etc/systemd/sleep.confsystemctl suspend |
not supported | Stop1 LP-Stop1 LPLV-Stop1 |
S2RAM Suspend-to-RAM (or deep) |
echo mem > /sys/power/state[mem 1] | with SuspendState=mem in /etc/systemd/sleep.confsystemctl suspend |
Stop LPLV-Stop LPLV-Stop2 |
Stop2 LP-Stop2 LPLV-Stop2 Standby1 |
power off | shutdown -P now systemctl poweroff |
Standby (DDR off) | Standby2 VBAT |
- ↑ "deep" for S2RAM is the default suspend variants associated with the "mem" string in the ``state`` file
cat /sys/power/mem_sleep
s2idle [deep]
See platform power page for more details on each family:
In OpenSTLinux, the low power modes are selected with devices activity and with activated wake up sources.
Information |
You must be sure your wakeup device is able to provide the wake up signal during low-power mode.
E.g. supply, clock, reset, etc... must be present, if any |
Each sysfs device in /sys/devices/ that supports wake up contains the file wakeup
in a device's power sub directory. The file contains wake up trigger's status and can be written to as well. See each device page to know the sysfs path in platform sub-directory and you can found all the possible wake up with:
find /sys/devices/platform | grep 'power/wakeup$'
You can check or control the wake up source with:
cat /sys/devices/platform/<device>/power/wakeup echo enabled > /sys/devices/platform/<device>/power/wakeup echo disabled > /sys/devices/platform/<device>/power/wakeup
The platform also selects the allowed modes depending also the coprocessor state, so you need to call the expected low-power mode for MCU side or stop the MCU firmware. Please refer to Coprocessor power management for Arm® Cortex®-M commands or the MCU firmware can also be stopped before entering in low power (it is mandatory if this firmware is running in DDR).
4.1. Examples[edit | edit source]
With default wake up source (RTC, Wakeup pins), the deepest platform mode is selected: Standby on STM32MP1 series / Standby1 on STM32MP2 series.
The activation of other wake-up sources prevents entering into this deepest low-power mode.
4.1.1. PWR WKUP pins[edit | edit source]
If PWR wake-up pins are enabled, for example see the WKUP button on STMicroelectronics boards, you can directly use the next command to call the low power entry:
systemctl suspend for weston
echo mem > /sys/power/state for distribution without systemctl
Press the WKUP button on STMicroelectronics boards to wake up the board.
4.1.2. RTC wake up[edit | edit source]
The RTC wake up is activated by default in Linux (/sys/devices/platform/*/*.rtc/power/wakeup
), so you just need to program the alarm.
The tools rtcwake
is used to enter a system sleep state until specified wake up time, for example 5 seconds with:
rtcwake --date +5sec -m mem
4.1.3. Serial wake-up[edit | edit source]
With USART wake-up enabled, the low-power mode is limited to
Enable serial wake up on associated TTY wake up source, for example
echo enabled > /sys/class/tty/ttySTM0/power/wakeup
Call the low-power entry command
systemctl suspend for weston
echo mem > /sys/power/state for distribution without systemctl
The MPU is now in low power mode (LP-Stop/LPLV-Stop/LP-Stop2) and can be woken up by sending a character to the console.
4.1.4. GPIO wake-up[edit | edit source]
For GPIO wake-up enabled, the low-power mode is limited at LPLV-Stop on STM32MP1 series / LPLV-Stop2 on STM32MP2 series.
To enable test GPIO wake up, adds the wake up support with the property wakeup-source
on a GPIO button (comaptible "gpio-keys") and is enabled in Linux by default (refer to Overview of GPIO pins for more details).
This property is not present on GPIO button in Linux device tree for STMicroelectronics, so you just need to add it:
&user-pa13 { wakeup-source; };
/ { gpio-keys { compatible = "gpio-keys"; /* gpio needs vdd core in retention for wakeup */ power-domains = <&pd_core_ret>; button-1 { label = "PA13"; linux,code = <BTN_1>; gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; wakeup-source; }; };
&button-user-1 { wakeup-source; };
Call the low-power entry command:
systemctl suspend for weston
echo mem > /sys/power/state for distribution without systemctl
The MPU is now in low power mode (LPLV-Stop or LPLVStop2) and you can wake up by the GPIO button.
You can dynamically check and deactivate the wake up capability for GPIO associated to the button.
cat /sys/devices/platform/gpio-keys/power/wakeup echo enabled > /sys/devices/platform/gpio-keys/power/wakeup echo disabled > /sys/devices/platform/gpio-keys/power/wakeup
4.1. PSCI in Linux[edit | edit source]
The low power modes selection in OpenSTLinux use the PSCI stack:
- in OP-TEE for STM32MP1 series, see STM32MP2 power overview for details
- in TF-A BL31 for STM32MP2 series, see STM32MP1 power overview for details
4.2. S2IDLE and CPUIdle (PSCI_CPU_SUSPEND)[edit | edit source]
This mode is NOT supported for STM32MP1 series.
In Linux the power domain and associated low power modes for S2IDle and CPUIdle OS initiated mode are described in SoC device tree (in arch/arm64/boot/dts/st/stm32mp251.dtsi and in arch/arm64/boot/dts/st/stm32mp253.dtsi ) using the hierarchical model as described in Documentation/devicetree/bindings/arm/psci.yaml .
/ { cpus { idle-states { entry-method = "psci"; CPU_PWRDN: cpu-power-down { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x00000001>; }; }; domain-idle-states { STOP1: domain-stop1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x00000011>; }; LP_STOP1: domain-lp-stop1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x0000021>; }; LPLV_STOP1: domain-lplv-stop1 { compatible = "domain-idle-state"; arm,psci-suspend-param = <0x00000211>; }; }; }; psci { compatible = "arm,psci-1.0"; method = "smc"; CPU_PD0: power-domain-cpu0 { #power-domain-cells = <0>; domain-idle-states = <&CPU_PWRDN>; power-domains = <&CLUSTER_PD>; }; CPU_PD1: power-domain-cpu1 { #power-domain-cells = <0>; domain-idle-states = <&CPU_PWRDN>; power-domains = <&CLUSTER_PD>; }; CLUSTER_PD: power-domain-cluster { #power-domain-cells = <0>; domain-idle-states = <&STOP1>, <&LP_STOP1>; power-domains = <&RET_PD>; }; RET_PD: power-domain-retention { #power-domain-cells = <0>; domain-idle-states = <&LPLV_STOP1>; }; };
This power domain hierarchy is used in generic power domain (GenPD) for S2IDLE request and for dynamic power management, based PSCI OS initiated mode PM runtime: Linux kernel selects the lowest possible low power mode with the associated PSCI State Id, according the state of each power domain (device in the power domain is running, wake-up source is activated) and which respects the OS constraint (wake-up latency in OS initiated mode for example).
The devices are assigned to a domain in Soc device tree according the Table 94. Functionalities depending on system operating mode of the reference manuals (autonomous mode is not managed in OpenSTLinux).
- CLUSTER_PD for peripherals not functional in "Stop1/2 and LP-Stop1/2"
- RET_PD for peripherals not functional in "LPLV-Stop1/2"
The EXTI1 driver is part of RET_PD because LPLV-Stop1 mode is not not allowed for Group2 wake up source.
The dynamic power management is based on driver activity, with device PM runtime and GenPD, so you need to stop ALL the STM32MP25 peripherals activity, including console to allow low power modes.
4.2.1. Scheduling in low power mode[edit | edit source]
The Linux scheduling-clock interrupts use a high-resolution kernel timer (hrtimer) provided by LPTIM Linux driver in low power modes when the ARM generic timer is stopped, see timer documentation for details.
It is indicated in SoC device tree with local-timer-stop; for CPU power down state:
idle-states { entry-method = "psci"; CPU_PWRDN: cpu-power-down { compatible = "arm,idle-state"; arm,psci-suspend-param = <0x00000001>; local-timer-stop; entry-latency-us = <300>; exit-latency-us = <500>; min-residency-us = <1000>; }; };
See Documentation/devicetree/bindings/cpu/idle-states.yaml for details.
To avoid scheduling issue, the low power mode cpu-power-down are supported in Linux kernel for S2IDLE/CPUIdle only if at least one hrtimer is registered on the platform and if this timer is functional in low power mode. Without activated hrtimer the CPU is limited to WFI, the default state defined in /sys/devices/system/cpu/cpu0/cpuidle/state0.
For STM32MP2 series, LPTIMy (y = 3, 4, 5) are functional in low power modes (see Table Functionalities depending on system operating mode in reference manual) when they are clocked by LSE or LSI (see Table Kernel clock distribution overview in reference manual).
For STMicrolectronics board, we are using the LPTIMER3, activated in the board device tree with:
/* use LPTIMER with tick broadcast for suspend mode */ &lptimer3 { status = "okay"; timer { status = "okay"; }; };
We can check if this timer is functional with:
ls /sys/bus/platform/drivers/stm32-lptimer/*.timer
Information |
The modules associated to the lptimer driver must be correctly loaded; on OpenSTLinux, the MFD LPTIM Linux driver is compiled in module by default (CONFIG_MFD_STM32_LPTIMER), if lsmod command does not show this module run the command modprobe stm32-lptimer to get it properly loaded.
|
.
NB: the firewall configuration must provide access by Linux to LPTIM Linux driver ressource, including associated interruption.
4.3. S2RAM (PSCI_SYSTEM_SUSPEND)[edit | edit source]
For deep
request the PSCI_SYSTEM_SUSPEND is sent to PSCI stack when the secondary core is stopped and all the process are frozen. The activated wake-up are consolidated to select the lowest supported mode in:
- OP-TEE for STM32MP1 series.
- TF-A BL31 for STM32MP2 series, based on activated wake up and co-processor activity (See STM32MP2 power overview for details).
4.3.1. STM32MP1 series power domains[edit | edit source]
The lowest power mode on STM32MP15 is based on power domain state of stm32-pm-domain driver in Linux GENPD framework. The power domain activity (with GENPD_FLAG_ACTIVE_WAKEUP , the domain is OFF when wake up are not activated on associated device) is provided to OP-TEE low power is based on proprietary SMC (0x82001008
) based on the topology is defined in SoC device tree, arch/arm/boot/dts/st/stm32mp131.dtsi or arch/arm/boot/dts/st/stm32mp151.dtsi :
pm_domain { #address-cells = <1>; #size-cells = <0>; compatible = "st,stm32mp157c-pd"; pd_core_ret: core-ret-power-domain@1 { #address-cells = <1>; #size-cells = <0>; reg = <1>; #power-domain-cells = <0>; label = "CORE-RETENTION"; pd_core: core-power-domain@2 { reg = <2>; #power-domain-cells = <0>; label = "CORE"; }; }; };
See STM32MP1 power overview for OP-TEE configuration.
5. Source code location[edit | edit source]
The source files are located inside the Linux kernel.
- power core:
- power drivers:
- drivers/base/power/
- GENPD driver: domain.c
- CPUIdle driver: drivers/cpuidle/
- PSCI drivers:
- STM32MP specific driver:
- drivers/soc/st/stm32_pm_domain.c for STM32MP1 series
- drivers/base/power/
- bindings:
For the framework used in Linux power management, see the associated pages:
And drivers in other software component for each internal peripheral or external component are described in the associated pages:
6. How to trace and debug[edit | edit source]
6.1. suspend/resume[edit | edit source]
The suspend/resume process execution is logged in the MPU console. It gives useful information on the platform state (sleeping or active).
root@stm32mp1:~# echo mem > /sys/power/state [ 1072.267571] PM: suspend entry (deep) [ 1072.269687] PM: Syncing filesystems ... done. [ 1072.279114] Freezing user space processes ... (elapsed 0.008 seconds) done. [ 1072.292835] OOM killer disabled. [ 1072.296046] Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done. [ 1072.303431] Suspending console(s) (use no_console_suspend to debug) [ 1072.332520] dwc2 49000000.usb-otg: suspending usb gadget configfs-gadget [ 1072.332537] dwc2 49000000.usb-otg: dwc2_hsotg_ep_disable: called for ep0 [ 1072.332546] dwc2 49000000.usb-otg: dwc2_hsotg_ep_disable: called for ep0 [ 1072.468536] Disabling non-boot CPUs ... [ 1072.507876] CPU1 killed. [ 1072.509635] Enabling non-boot CPUs ... [ 1072.510508] CPU1 is up [ 1072.527553] dwmac4: Master AXI performs any burst length [ 1072.527583] stm32-dwmac 5800a000.ethernet eth0: No Safety Features support found [ 1072.527621] stm32-dwmac 5800a000.ethernet eth0: ERROR failed to create debugfs directory [ 1072.527631] stm32-dwmac 5800a000.ethernet eth0: stmmac_hw_setup: failed debugFS registration [ 1072.588234] dwc2 49000000.usb-otg: resuming usb gadget configfs-gadget [ 1072.738469] OOM killer enabled. [ 1072.741575] Restarting tasks ... done. [ 1072.752596] PM: suspend exit
Get more debug information from the console with the following commands:
echo N > /sys/module/printk/parameters/console_suspend
This command allows to see the last linux kernel trace and also the PSCI stack traces, in OP-TEE for STM32MP1 and the the TF-A BL31 traces for STM32MP2 (which indicate the selected low power mode).
You can also activate the dynamic debug in Linux:
echo "func pm_dev_dbg +p" > /sys/kernel/debug/dynamic_debug/control
echo "func pm_pr_dbg +p" > /sys/kernel/debug/dynamic_debug/control echo "func dpm_show_time +p" > /sys/kernel/debug/dynamic_debug/control echo "func s2idle_loop +p" > /sys/kernel/debug/dynamic_debug/control
And use power sysfs ABI sysfs-devices-power, for example:
echo 1 > /sys/power/pm_debug_messages echo 0 > /sys/power/pm_async
You can also activate CONFIG_PM_DEBUG
and CONFIG_PM_TRACE
.
6.2. wakeup interruption[edit | edit source]
For each wakeup device, you can check wakeup status with sysfs ABI sysfs-devices-power, for example:
more `find /sys/devices/. | grep wakeup_active_count`
Moreover, if you activate CONFIG_PM_SLEEP_DEBUG
You can get the IRQ number that triggered the wakeup with:
cat /sys/power/pm_wakeup_irq
And the interruption can be identified with sysfs:
cat /proc/interrupts
6.3. other debug tips[edit | edit source]
To go further see the kernel documentation power/basic-pm-debugging.rst and power/s2ram.rst.
It is also possible to monitor the hardware signals related to the system low-power modes thanks to the HDP internal peripheral.
Please refer to HDP Linux driver for its configuration.
7. To go further[edit | edit source]
Please refer to the STM32MPU reference manuals for a detailed description of low-power modes and peripheral wakeup sources and to pages:
See documentation in Linux and presentations:
- Documentation/power
- Documentation/admin-guide/pm.
- Linaro connect presentation "Device Power Management for Idle"[3]
8. References[edit | edit source]
- ↑ Arm Power State Coordination Interface (PSCI):
https://developer.arm.com/documentation/den0022 - ↑ Arm System Control and Management Interface Platform Design Document (SCMI) specification:
https://developer.arm.com/documentation/den0056 - ↑ Linaro connect presentation "Device Power Management for Idle"