Skip to main content
Qualcomm® Linux provides multiple power management subsystems CPUIdle, runtime PM, thermal throttling, system suspend, regulators, and clocks, that must be configured together to achieve optimal power consumption on ARM64 platforms. This page covers each subsystem and its key configuration and runtime controls.

CPUIdle states and governors

CPUIdle manages idle state selection when a CPU has no runnable tasks. On Qualcomm platforms, idle states are defined in the device tree and communicated to Linux through the PSCI (Power State Coordination Interface) firmware.

Idle state hierarchy

Qualcomm ARM64 SoCs typically expose three PSCI-backed idle states per CPU: Table: Typical Qualcomm PSCI idle states
StatePSCI state IDTarget residencyDescription
WFI (C1)0x00000000~1 µsCPU clock gated; cache retained. Fastest entry and exit.
Core power-down (C2)0x00000003~100 µsCPU powered down; L1/L2 flushed. State retained in DDR.
Cluster power-collapse (C3)0x00000F03~1–3 msEntire cluster powered off; L3 may be flushed.
The exact PSCI state identifiers and residency values are defined in the SoC DTSI under each CPU node. Inspect them:
cat /proc/device-tree/cpus/cpu@*/idle-states/*/entry-latency-us
cat /proc/device-tree/cpus/cpu@*/idle-states/*/min-residency-us

Inspect idle states at runtime

# List all idle states for cpu0
ls /sys/devices/system/cpu/cpu0/cpuidle/

# Per-state details
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/name
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/latency    # exit latency µs
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/residency  # target residency µs
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/usage      # entry count
cat /sys/devices/system/cpu/cpu0/cpuidle/state0/time       # total time µs

# Disable deep idle on cpu0 for latency debugging
echo 1 > /sys/devices/system/cpu/cpu0/cpuidle/state2/disable

CPUIdle governors

Table: CPUIdle governors
GovernorBehavior
menuDefault for tickless systems. Uses historical idle duration patterns and the next timer event to predict residency. Suitable for general-purpose workloads.
TEOTimer Events Oriented. Selects idle state based on the distance to the next timer event, ignoring pattern history. Lower latency for workloads with irregular wakeup patterns.
# Check current governor
cat /sys/devices/system/cpu/cpuidle/current_governor

# Switch to TEO
echo teo > /sys/devices/system/cpu/cpuidle/current_governor

PM QoS latency constraints

Drivers and user space can prevent CPUs from entering deep idle states by registering a latency constraint. Per-CPU constraints via sysfs:
# Limit cpu4 to states with exit latency under 200 µs
echo 200 > /sys/devices/system/cpu/cpu4/power/pm_qos_resume_latency_us

# Remove constraint
echo 0 > /sys/devices/system/cpu/cpu4/power/pm_qos_resume_latency_us
Required Kconfig:
CONFIG_CPU_IDLE=y
CONFIG_CPU_IDLE_GOV_MENU=y
CONFIG_CPU_IDLE_GOV_TEO=y
CONFIG_ARM_PSCI_CPUIDLE=y

Runtime PM for peripherals

Runtime PM allows individual peripheral devices to enter low-power states while the system is running. On Qualcomm SoCs, power domains are managed by the RPMh hardware resource manager through the qcom-rpmhpd driver.

Enable runtime PM in a driver

/* In probe() */
pm_runtime_enable(&pdev->dev);
pm_runtime_set_active(&pdev->dev);

/* When the device becomes idle */
pm_runtime_put_autosuspend(&pdev->dev);

/* When the device is needed again */
ret = pm_runtime_get_sync(&pdev->dev);
Set an autosuspend delay to prevent rapid power cycling:
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);  /* 50 ms */
pm_runtime_use_autosuspend(&pdev->dev);

Monitor runtime PM state

# Runtime PM status for all platform devices
grep -r "" /sys/bus/platform/devices/*/power/runtime_status 2>/dev/null

# Detailed stats for a specific device
cat /sys/bus/platform/devices/<device>/power/runtime_status
cat /sys/bus/platform/devices/<device>/power/runtime_active_time
cat /sys/bus/platform/devices/<device>/power/runtime_suspended_time
Replace the following:
  • <device> by the platform device name from /sys/bus/platform/devices/.

Qualcomm power domains

RPMh power domains are registered by the qcom-rpmhpd driver. Inspect registered domains:
ls /sys/kernel/debug/pm_genpd/
cat /sys/kernel/debug/pm_genpd/summary
Required Kconfig:
CONFIG_PM=y
CONFIG_PM_GENERIC_DOMAINS=y
CONFIG_QCOM_RPMHPD=y

Thermal throttling

The Linux thermal framework monitors temperature sensors and applies cooling actions when trip points are crossed. Qualcomm SoCs expose thermal zones through TSENS (temperature sensor) hardware, with cooling devices implemented as CPU frequency caps and CPU hotplug.

Inspect thermal zones

# Current temperature for all zones (millidegrees Celsius)
cat /sys/class/thermal/thermal_zone*/temp

# Zone type identifies the physical sensor
cat /sys/class/thermal/thermal_zone*/type

# Trip point temperatures and types for zone 0
cat /sys/class/thermal/thermal_zone0/trip_point_0_temp
cat /sys/class/thermal/thermal_zone0/trip_point_0_type

# Active cooling device states
cat /sys/class/thermal/cooling_device*/cur_state
cat /sys/class/thermal/cooling_device*/max_state

Thermal governors

Table: Thermal governors
GovernorBehavior
step_wiseIncremental cooling: increases cooling one step at a time per polling interval.
power_allocatorUses an Intelligent Power Allocator (IPA) power model. Recommended for Qualcomm SoCs when an Energy Model is available.
bang_bangBinary on/off cooling based on trip hysteresis.
# Check current governor per zone
cat /sys/class/thermal/thermal_zone*/policy

# Switch to power_allocator
echo power_allocator > /sys/class/thermal/thermal_zone0/policy
Required Kconfig:
CONFIG_THERMAL=y
CONFIG_THERMAL_GOV_STEP_WISE=y
CONFIG_THERMAL_GOV_POWER_ALLOCATOR=y
CONFIG_CPU_THERMAL=y
CONFIG_QCOM_TSENS=y

System suspend (S2RAM)

System suspend powers off most SoC subsystems while retaining DRAM in self-refresh. On Qualcomm platforms, the suspend path issues a PSCI SYSTEM_SUSPEND call in EL3, and the RPMh hardware sequencer powers down voltage rails in dependency order.

Trigger and verify suspend

# Check supported sleep states
cat /sys/power/state

# Trigger suspend to RAM
echo mem > /sys/power/state

Identify suspend blockers

Wakeup sources that are active prevent the system from suspending. Identify them:
# Show all active wakeup sources
cat /sys/kernel/debug/wakeup_sources | awk '$4 > 0'

# Show which wakeup source caused the last resume
cat /sys/power/pm_wakeup_irq
dmesg | grep -i "wakeup\|wake irq"

Debug suspend failures

Enable per-device suspend and resume tracing:
echo 1 > /sys/kernel/debug/pm_debug/suspend_stats
cat /sys/kernel/debug/suspend_stats
Required Kconfig:
CONFIG_SUSPEND=y
CONFIG_PM_SLEEP=y
CONFIG_PM_DEBUG=y
CONFIG_PM_SLEEP_DEBUG=y

Regulator and clock management

Reducing unnecessary always-on regulators and unused clock consumers can significantly reduce static power draw.

Regulator state

Inspect all regulators and their enable state:
cat /sys/kernel/debug/regulator/regulator_summary
Remove regulator-always-on from DT bindings of optional peripherals (for example, MIPI-CSI sensors not populated on all boards) to allow runtime power gating. Retain it only for critical rails:
vreg_s1a: smps1 {
    regulator-name           = "vreg_s1a";
    regulator-min-microvolt  = <1800000>;
    regulator-max-microvolt  = <1800000>;
    regulator-always-on;   /* retain only for critical rails */
    regulator-boot-on;
};

Clock tree

The Qualcomm clock controllers (GCC, CAMCC, DISPCC, and others) are managed by the clk-qcom driver family. Inspect enabled clocks:
# Full clock tree with enable counts and rates
cat /sys/kernel/debug/clk/clk_summary

# Find leaf clocks that are enabled but have no enabled children
grep "enabled.*0$" /sys/kernel/debug/clk/clk_summary
Use devm_clk_get_enabled() (available since kernel v5.20) in drivers to acquire, enable, and automatically release a clock when the device is unbound or runtime-suspended:
struct clk *clk = devm_clk_get_enabled(&pdev->dev, "core");
if (IS_ERR(clk))
    return PTR_ERR(clk);

Power analysis tools

powertop

powertop identifies power consumers, reports idle state residency, and shows per-process wakeup event rates:
# Interactive mode
powertop

# Generate an HTML report
powertop --html=/tmp/power_report.html --time=30

# Apply auto-tune suggestions
powertop --auto-tune
Key metrics to examine:
  • C-state residency: deep idle states (C2/C3) should exceed 80% residency when the system is idle.
  • Wakeups/s: any single source exceeding 50 wakeups per second warrants investigation.

pm_debug debugfs

# Suspend and resume statistics
cat /sys/kernel/debug/suspend_stats

# Wakeup sources with timing
cat /sys/kernel/debug/wakeup_sources

# RPMh command history
cat /sys/kernel/debug/qcom_rpmh/*/db

# Power domain summary
cat /sys/kernel/debug/pm_genpd/summary

# Regulator summary
cat /sys/kernel/debug/regulator/regulator_summary

# Clock tree
cat /sys/kernel/debug/clk/clk_summary

cpuidle tracing with ftrace

echo 1 > /sys/kernel/debug/tracing/events/power/cpu_idle/enable
echo 1 > /sys/kernel/debug/tracing/tracing_on
sleep 10
echo 0 > /sys/kernel/debug/tracing/tracing_on
cat /sys/kernel/debug/tracing/trace | grep cpu_idle | head -50