> ## Documentation Index
> Fetch the complete documentation index at: https://dragonwingdocs.qualcomm.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Power optimization considerations

Qualcomm<sup>®</sup> 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**

| State                       | PSCI state ID | Target residency | Description                                              |
| --------------------------- | ------------- | ---------------- | -------------------------------------------------------- |
| WFI (C1)                    | `0x00000000`  | \~1 µs           | CPU clock gated; cache retained. Fastest entry and exit. |
| Core power-down (C2)        | `0x00000003`  | \~100 µs         | CPU powered down; L1/L2 flushed. State retained in DDR.  |
| Cluster power-collapse (C3) | `0x00000F03`  | \~1–3 ms         | Entire 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:

```bash theme={null}
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

```bash theme={null}
# 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**

| Governor | Behavior                                                                                                                                                                       |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `menu`   | Default for tickless systems. Uses historical idle duration patterns and the next timer event to predict residency. Suitable for general-purpose workloads.                    |
| `TEO`    | Timer 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. |

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```text theme={null}
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

```c theme={null}
/* 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:

```c theme={null}
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);  /* 50 ms */
pm_runtime_use_autosuspend(&pdev->dev);
```

### Monitor runtime PM state

```bash theme={null}
# 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:

```bash theme={null}
ls /sys/kernel/debug/pm_genpd/
cat /sys/kernel/debug/pm_genpd/summary
```

Required Kconfig:

```text theme={null}
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

```bash theme={null}
# 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**

| Governor          | Behavior                                                                                                                |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------- |
| `step_wise`       | Incremental cooling: increases cooling one step at a time per polling interval.                                         |
| `power_allocator` | Uses an Intelligent Power Allocator (IPA) power model. Recommended for Qualcomm SoCs when an Energy Model is available. |
| `bang_bang`       | Binary on/off cooling based on trip hysteresis.                                                                         |

```bash theme={null}
# 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:

```text theme={null}
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

```bash theme={null}
# 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:

```bash theme={null}
# 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:

```bash theme={null}
echo 1 > /sys/kernel/debug/pm_debug/suspend_stats
cat /sys/kernel/debug/suspend_stats
```

Required Kconfig:

```text theme={null}
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:

```bash theme={null}
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:

```text theme={null}
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:

```bash theme={null}
# 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:

```c theme={null}
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:

```bash theme={null}
# 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

```bash theme={null}
# 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

```bash theme={null}
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
```
