> ## 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.

# 功耗优化注意事项

Qualcomm<sup>®</sup> Linux 提供多个电源管理子系统:
CPUIdle、运行时 PM、热限频、系统挂起、稳压器和时钟,
必须协同配置这些子系统,才能在 ARM64 平台上实现最优功耗。本页介绍每个子系统及其关键配置和运行时控制。

## **CPUIdle 状态与调速器**

CPUIdle 在 CPU 没有可运行任务时管理空闲状态的选择。在 Qualcomm 平台上,空闲状态在设备树中定义,并通过 PSCI(电源状态协调接口)固件传递给 Linux。

### 空闲状态层级

Qualcomm ARM64 SoC 通常为每个 CPU 提供三个由 PSCI 支持的空闲状态:

**表:典型的 Qualcomm PSCI 空闲状态**

| 状态        | PSCI 状态 ID   | 目标驻留时间   | 说明                              |
| --------- | ------------ | -------- | ------------------------------- |
| WFI(C1)   | `0x00000000` | 约 1 µs   | CPU 时钟门控;缓存保留。进入和退出速度最快。        |
| 核心断电(C2)  | `0x00000003` | 约 100 µs | CPU 断电;L1/L2 缓存被刷新。状态保留在 DDR 中。 |
| 簇电源塌陷(C3) | `0x00000F03` | 约 1–3 ms | 整个簇断电;L3 可能被刷新。                 |

确切的 PSCI 状态标识符和驻留时间值在 SoC DTSI 中每个 CPU 节点下定义。可如下查看:

```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
```

### 在运行时检查空闲状态

```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 调速器

**表:CPUIdle 调速器**

| 调速器    | 行为                                                                               |
| ------ | -------------------------------------------------------------------------------- |
| `menu` | 无时钟滴答(tickless)系统的默认调速器。利用历史空闲时长模式和下一个定时器事件来预测驻留时间。适用于通用工作负载。                    |
| `TEO`  | 面向定时器事件(Timer Events Oriented)。基于距下一个定时器事件的时间来选择空闲状态,忽略模式历史。对于唤醒模式不规律的工作负载,延迟更低。 |

```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 延迟约束

驱动和用户空间可以通过注册延迟约束来阻止 CPU 进入深度空闲状态。通过 sysfs 设置每 CPU 约束:

```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
```

所需的 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
```

## **外设的运行时 PM**

运行时 PM 允许各个外设设备在系统运行时进入低功耗状态。在 Qualcomm SoC 上,电源域由 RPMh 硬件资源管理器通过 `qcom-rpmhpd` 驱动进行管理。

### 在驱动中启用运行时 PM

```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);
```

设置自动挂起延迟以防止快速的电源循环:

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

### 监控运行时 PM 状态

```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
```

替换以下内容:

* 将 `<device>` 替换为 `/sys/bus/platform/devices/` 中的平台设备名称。

### Qualcomm 电源域

RPMh 电源域由 `qcom-rpmhpd` 驱动注册。检查已注册的电源域:

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

所需的 Kconfig:

```text theme={null}
CONFIG_PM=y
CONFIG_PM_GENERIC_DOMAINS=y
CONFIG_QCOM_RPMHPD=y
```

## **热限频**

Linux 热管理框架监控温度传感器,并在越过触发点(trip point)时采取冷却措施。Qualcomm SoC 通过 TSENS(温度传感器)硬件暴露热区(thermal zone),冷却设备则以 CPU 频率上限和 CPU 热插拔的形式实现。

### 检查热区

```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
```

### 热管理调速器

**表:热管理调速器**

| 调速器               | 行为                                              |
| ----------------- | ----------------------------------------------- |
| `step_wise`       | 增量冷却:每个轮询周期逐步增加一级冷却。                            |
| `power_allocator` | 使用智能功率分配器(IPA)功率模型。在有能耗模型可用时,推荐用于 Qualcomm SoC。 |
| `bang_bang`       | 基于触发点迟滞的二元开/关冷却。                                |

```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
```

所需的 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
```

## **系统挂起(S2RAM)**

系统挂起会关闭大部分 SoC 子系统的电源,同时让 DRAM 保持自刷新状态。在 Qualcomm 平台上,挂起路径在 EL3 发出 PSCI `SYSTEM_SUSPEND` 调用,RPMh 硬件时序器按依赖顺序关闭电压轨。

### 触发并验证挂起

```bash theme={null}
# Check supported sleep states
cat /sys/power/state

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

### 识别挂起阻碍者

处于活动状态的唤醒源会阻止系统挂起。识别它们:

```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"
```

### 调试挂起失败

启用按设备的挂起和恢复跟踪:

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

所需的 Kconfig:

```text theme={null}
CONFIG_SUSPEND=y
CONFIG_PM_SLEEP=y
CONFIG_PM_DEBUG=y
CONFIG_PM_SLEEP_DEBUG=y
```

## **稳压器与时钟管理**

减少不必要的常开稳压器和未使用的时钟消费者,可以显著降低静态功耗。

### 稳压器状态

检查所有稳压器及其使能状态:

```bash theme={null}
cat /sys/kernel/debug/regulator/regulator_summary
```

从可选外设(例如并非所有单板都配备的 MIPI-CSI 传感器)的 DT 绑定中移除 `regulator-always-on`,以允许运行时电源门控。仅对关键电压轨保留该属性:

```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;
};
```

### 时钟树

Qualcomm 时钟控制器(GCC、CAMCC、DISPCC 等)由 `clk-qcom` 驱动系列管理。检查已启用的时钟:

```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
```

在驱动中使用 `devm_clk_get_enabled()`(自内核 v5.20 起可用)来获取、启用时钟,并在设备解绑或运行时挂起时自动释放:

```c theme={null}
struct clk *clk = devm_clk_get_enabled(&pdev->dev, "core");
if (IS_ERR(clk))
    return PTR_ERR(clk);
```

## **功耗分析工具**

### powertop

`powertop` 识别功耗大户,报告空闲状态驻留情况,并显示每个进程的唤醒事件速率:

```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
```

需要关注的关键指标:

* **C 状态驻留**:系统空闲时,深度空闲状态(C2/C3)的驻留时间占比应超过 80%。
* **每秒唤醒次数(Wakeups/s)**:任何单一来源每秒超过 50 次唤醒都值得调查。

### 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
```

### 使用 ftrace 进行 cpuidle 跟踪

```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
```
