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

# 功耗优化注意事项

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

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

当 CPU 没有可运行任务时，CPUIdle 负责管理空闲状态的选择。在 Qualcomm 平台上，空闲状态在设备树中定义，并通过 PSCI（Power State Coordination Interface）固件传递给 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
```

## **外设的运行时电源管理**

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

### 在驱动中启用运行时电源管理

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

### 监控运行时电源管理状态

```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）功率模型。在有能量模型（Energy Model）可用时，推荐用于 Qualcomm SoC。 |
| `bang_bang`       | 基于触发点滞后（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
```

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

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

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

### 稳压器状态

查看所有稳压器及其使能状态：

```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%。
* **每秒唤醒数**：任何单一来源每秒唤醒超过 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
```
