📺 B站视频讲解(Bilibili):https://www.bilibili.com/video/BV1k1C9BYEAB/
📘 《Yocto项目实战教程》京东购买链接:Yocto项目实战教程
SoC 低功耗实战方针与原理:以 Rockchip RK3588 为例
把 RK3588 这类复杂 SoC 的功耗优化,从“玄学调参”变成可复现的工程流程:
- 你知道功耗是谁在耗(电源轨/时钟域/功耗域/外设/DDR/CPU 簇/AI/ISP/显示)
- 你知道怎么让它不耗(Idle → Runtime PM → DVFS → Domain gating → System suspend)
- 你知道如何验证确实不耗(电流计 + PMIC rail + trace + debugfs + wakelock)

1. 低功耗工程“实战方针”
1.1 从产品需求反推策略(最关键)
不同产品形态,低功耗目标完全不同:
- 深度待机(Deep standby):
- 目标:mW 级(甚至更低)
- 允许:绝大多数 IP 断电,DDR 进入 self‑refresh 或完全掉电(取决于 suspend-to-RAM / suspend-to-idle / suspend-to-disk)
- 关键:唤醒源、唤醒时间、数据保持
- 轻待机(Light standby / Screen-off idle):
- 目标:几十 mW ~ 几百 mW
- 允许:屏幕/显示域关,CPU 进入深度 idle,Wi‑Fi/BT 可选择保活
- 关键:网络保活、RTC/触摸/蓝牙/按键唤醒
- “工作态”低功耗(Performance-per-watt):
- 目标:在同等 FPS/码率/吞吐下最低功耗
- 关键:DVFS、热设计、带宽(DDR/NoC)与硬件加速器使用方式
实战建议:先把产品分成 3~5 个“功耗状态”(Power State),每个状态写成表格:
- 允许开启的子系统
- 必须关闭的子系统
- 唤醒源列表
- 典型功耗目标(mA@电压)
- 唤醒时间目标(ms)
1.2 三条工程纪律
纪律 A:先测量,再优化。
- 没有电流/电压与功耗状态的基线,所有优化都不可控。
纪律 B:先做“关掉不用的”,再做“更省电”。
- 先关显示/ISP/AI/USB/PCIe/DP/HDMI 等大户,再微调 CPU DVFS。
纪律 C:任何节能都必须可验证、可回归。
- 每个 PR/每次改动,都要有 “before/after” 的指标与脚本。
2. RK3588 的低功耗“硬件地图”:你要知道的物理事实
低功耗不是“内核开关”,而是硬件结构的控制:电源轨、时钟树、复位、隔离、保留、唤醒路径。
2.1 电源:PMIC + 多路 rail 的本质
RK3588 常见板级设计(核心板 + 载板)里:
- PMIC 输出多路电压(例如:VDD_CPU、VDD_GPU、VDD_NPU、VDD_LOGIC、VDD_DDR、VCC_IO 等)
- 每一路 rail 可能对应一个 power domain 或者一个电压域
- SoC 内部还有:LDO/隔离/保留寄存器/电源门控
你需要建立一张“电源树(Power Tree)”与 Linux power domain 的映射表:
| PMIC rail | 典型供电对象 | Linux 侧映射 | 关键观测点 |
|---|---|---|---|
| VDD_CPU_BIG | A76 cluster | cpufreq/OPP | 电压随频率变化 |
| VDD_CPU_LITTLE | A55 cluster | cpufreq/OPP | idle 深度是否进入 |
| VDD_GPU | Mali | devfreq/OPP | GPU 空闲是否降频/关域 |
| VDD_NPU | NPU | devfreq/OPP | NPU 是否 runtime suspend |
| VDD_LOGIC | SoC logic | genpd | 大部分 domain gating |
| VDD_DDR | DDR PHY/DRAM | PMU/DDR | SR/PD 状态 |
为什么要映射?
因为“电流下降”必须能追溯到“哪个 rail 被关/被降压/哪个 domain 被 gated”。否则你只是在猜。
2.2 时钟树:低功耗的第二把刀
-
没关电源域之前,先关时钟(clock gating)通常更安全
-
绝大多数 IP 的功耗来自:
- 时钟在跑(翻转功耗)
- DDR 带宽(NoC 活动)
- 外设 IO(PHY、SerDes)
Linux 对应的控制点:
- Common Clock Framework(CCF):
/sys/kernel/debug/clk/clk_summary - 驱动:
clk_prepare_enable()/clk_disable_unprepare() - 运行时:runtime PM 在
->runtime_suspend()里停时钟
2.3 复位/隔离/保留(Reset/Isolation/Retention)
当一个 power domain 断电,需要:
- 先停止 IP 活动
- 再关时钟
- 再隔离(isolation)
- 再断电
- 恢复时反向执行 + 状态恢复
这些动作大多在:
- SoC 的 PMU/PMGR 控制器
- Linux 的 genpd(generic power domain)框架
2.4 唤醒源:低功耗设计的“门”
- RTC
- GPIO(按键/霍尔/唤醒线)
- 触摸(I2C/SPI 设备具备 wakeup)
- Bluetooth/Wi‑Fi(取决于芯片、固件、接口与板级唤醒线)
- USB(设备插拔/充电)
唤醒源必须在硬件上可达:
- 有唤醒线到 PMU/Always‑on 域
- IO rail 在低功耗状态仍供电
3. Linux 低功耗的“四层模型”(建议你用这四层做文章骨架)
低功耗在 Linux 里不是一套机制,是四套机制叠加:Idle、Runtime PM、DVFS、System Suspend。
3.1 CPU Idle:让 CPU 真正睡下去
-
目标:让 CPU 从 WFI 到更深的 idle state
-
框架:cpuidle / PSCI(ARM)
-
关键:
cpuidlestate 进入次数与驻留时间- 中断是否频繁唤醒(定时器、workqueue、网络)
常用观测:
/sys/devices/system/cpu/cpuidle/- trace:
trace-cmd record -e power -e irq等
3.2 Runtime PM:不用的设备随时睡
-
最常见、收益最大
-
框架:
pm_runtime_*+ 驱动->runtime_suspend()/->runtime_resume() -
关键:
- 引用计数(usage_count)必须归零
- 驱动必须正确停 DMA/IRQ/clk/regulator
- 用户态不要持续打开设备节点
观测:
cat /sys/devices/.../power/runtime_statuscat /sys/kernel/debug/pm_genpd/pm_genpd_summary
3.3 DVFS/OPP:让电压跟着需求走
-
CPU:cpufreq
-
GPU/NPU/DDR:devfreq + OPP
-
关键:
- OPP 表正确(频率/电压/功耗)
- governor 选择(schedutil/performance/powersave)
- 负载统计是否真实
3.4 System Suspend:进入系统级休眠
suspend-to-idle(s2idle)suspend-to-RAM(deep)
RK3588 在 vendor 内核通常由 Rockchip PM 体系实现 deep suspend:
- PMU 控制 power domain
- DDR 进入 self‑refresh
- 唤醒源由 PMU/RTC/GPIO 触发
4. RK3588 的“功耗状态机”设计(你可以直接照抄落地)
建议定义 5 态:
- P0:Full‑On(全开工作态)
- camera/ISP/encoder/display 可开
- CPU/GPU/NPU 按需 DVFS
- P1:Interactive(屏幕亮但轻负载)
- 限制最高频率
- GPU/NPU 进入更激进的 devfreq
- P2:Screen‑Off Idle(灭屏待机)
- display domain off
- camera off
- Wi‑Fi/BT 视需求(保活或低功耗)
- CPU 允许 deeper idle
- P3:Standby(深度待机,RAM 保持)
- system suspend-to-RAM
- 只保留 wakeup 设备
- P4:Shipping / Ultra‑Low(超低功耗/运输模式)
- 近似断电,仅 RTC/少量 always‑on
4.1 每个状态必须有“入口脚本 + 验收脚本”
入口脚本例(思路):
- 停止业务进程
- 释放设备句柄
- 关闭大户:显示、摄像头、USB3/PCIe
- 写入 governor/频率上限
- 执行 suspend
验收脚本例(思路):
- 记录功耗(外部仪表)
- dump:clk_summary、pm_genpd、wakeup_sources
- 记录 60s 内唤醒原因统计
5. 你必须会的“测量体系”:没有它就别谈低功耗
5.1 外部测量:电流/电压/功耗
- 最可靠:在供电入口串接电流计(或使用功率分析仪)
- 如果有分 rail 采样(INA219/INA226/PMIC ADC),可做更细粒度分析
基线必须统一:
- 固定亮度、固定网络状态、固定温度
- 同一套 workload
5.2 内部观测:Linux 侧证据链
- 唤醒源
/sys/kernel/debug/wakeup_sources/proc/interrupts/sys/devices/.../power/wakeup
- 时钟
/sys/kernel/debug/clk/clk_summary
- 电源域(genpd)
/sys/kernel/debug/pm_genpd/pm_genpd_summary
- Runtime PM 状态
/sys/devices/.../power/runtime_status
- CPU idle/cpufreq
cpupower frequency-info(若可用)/sys/devices/system/cpu/cpu*/cpufreq//sys/devices/system/cpu/cpuidle/
5.3 一套“标准采集包”(建议你做成脚本)
#!/bin/sh
OUT=/tmp/power_dump_$(date +%F_%H%M%S)
mkdir -p $OUT
# 1) wakelocks / wakeup sources
cat /sys/kernel/debug/wakeup_sources > $OUT/wakeup_sources.txt 2>/dev/null || true
# 2) interrupts
cat /proc/interrupts > $OUT/interrupts.txt
# 3) clocks
cat /sys/kernel/debug/clk/clk_summary > $OUT/clk_summary.txt 2>/dev/null || true
# 4) genpd
cat /sys/kernel/debug/pm_genpd/pm_genpd_summary > $OUT/pm_genpd_summary.txt 2>/dev/null || true
# 5) runtime pm snapshot (top-level)
find /sys/devices -maxdepth 5 -name runtime_status -print -exec sh -c 'echo "=== {}"; cat {}' \; \
> $OUT/runtime_status.txt 2>/dev/null || true
echo "dump saved to $OUT"
6. RK3588 低功耗的“最大功耗源”清单(按优先级)
经验规律:对 RK3588 这种大 SoC,省电先抓“大户”。
6.1 显示链路(VOP2/DSI/DP/HDMI/PHY)
- 显示亮起来后,时钟域、NoC、DDR 带宽都会上去
- DP/HDMI 的 PHY/SerDes 也很耗
策略:
-
灭屏状态必须确保:
- DRM/KMS 关闭 pipeline
- 对应 PHY runtime suspend
- backlight PWM 关闭
6.2 摄像头链路(CIF/ISP/MPP/编码)
- ISP/DRM/编码器是典型大户
- MPP 编码如果保持常开,功耗维持高位
策略:
-
camera idle 时必须:
- 停止 stream
- 释放 v4l2 node
- 让 ISP/MPP runtime suspend
6.3 DDR/NoC(带宽就是功耗)
- 很多“看起来没干活”的系统,实际 DDR 一直高频
策略:
- devfreq governor 合理
- 减少后台日志/轮询
- 避免无意义 memcpy
6.4 无线(Wi‑Fi/BT)
- 取决于芯片(Broadcom/Realtek)与固件
- 扫描/保持连接/热点都会显著增加功耗
策略:
-
待机态:
- Wi‑Fi 彻底断电(若允许),或进入 WOWLAN/DTIM 优化
- BT 进入低功耗(sniff/advertising 参数)
6.5 USB3/PCIe/SerDes
- SerDes/PHY 常开耗电明显
策略:
- 没插设备时 runtime suspend
- LPM(U1/U2/U3、PCIe ASPM)
7. RK3588 内核侧:关键框架与代码路径(务实版)
下面给出“你改代码时真正会用到的路径与套路”。具体文件名会因 vendor 内核版本不同略有差异,但框架一致。
7.1 设备树:低功耗信息的“事实源”
你需要在 DTS 里明确:
- power domains
- clocks
- regulators
- operating-points
- wakeup-source
- pinctrl 的 sleep state
7.1.1 wakeup-source(示意)
&i2c3 {
status = "okay";
touch@38 {
compatible = "goodix,gt911";
reg = <0x38>;
interrupt-parent = <&gpio4>;
interrupts = <10 IRQ_TYPE_EDGE_FALLING>;
wakeup-source; /* 关键:允许作为唤醒源 */
pinctrl-names = "default", "sleep";
pinctrl-0 = <&touch_int_default>;
pinctrl-1 = <&touch_int_sleep>; /* 关键:低功耗引脚态 */
};
};
7.1.2 OPP(示意)
cpu0_opp_table: opp-table {
compatible = "operating-points-v2";
opp-shared;
opp-1200000 {
opp-hz = /bits/ 64 <1200000000>;
opp-microvolt = <800000>;
};
opp-1800000 {
opp-hz = /bits/ 64 <1800000000>;
opp-microvolt = <950000>;
};
};
扩展写作点(用于加厚字数):
- RK3588 各电压域的 OPP 案例(CPU big/little、GPU、NPU、DDR)
- regulator 依赖关系、supply 名称、board power tree 对应
- pinctrl sleep state 的电气意义(上拉/下拉/保持/高阻)
7.2 Runtime PM:驱动必须写对的“模板”
下面是你在外设驱动里最常写的结构:
static int foo_runtime_suspend(struct device *dev)
{
struct foo *f = dev_get_drvdata(dev);
/* 1) 停止 DMA/队列 */
foo_stop_hw(f);
/* 2) 禁用中断(如果中断不是唤醒源) */
disable_irq(f->irq);
/* 3) 关时钟 */
clk_disable_unprepare(f->clk);
/* 4) 关 regulator(如果允许) */
regulator_disable(f->vdd);
return 0;
}
static int foo_runtime_resume(struct device *dev)
{
struct foo *f = dev_get_drvdata(dev);
regulator_enable(f->vdd);
clk_prepare_enable(f->clk);
enable_irq(f->irq);
foo_start_hw(f);
return 0;
}
static const struct dev_pm_ops foo_pm_ops = {
SET_RUNTIME_PM_OPS(foo_runtime_suspend, foo_runtime_resume, NULL)
};
常见坑:
- usage_count 永远不归零(用户态句柄没关、或者驱动 get/put 不平衡)
- 中断频繁唤醒(GPIO 抖动、IRQ type 配错)
- suspend 时没停 DMA,导致总线一直活跃
7.3 genpd:电源域关不掉的“根因”通常在这里
你应重点看:
- 哪些 domain 一直显示
on - 谁在引用它(设备 runtime PM 没睡)
调试:
pm_genpd_summary- 逐个排查设备 runtime_status
扩展写作点:
- RK3588 常见 power domain 列表(VOP/ISP/USB/PCIe/NPU/GPU)
- domain 之间的 parent/child 关系
- Rockchip PMU 驱动的关键代码阅读(vendor kernel)
7.4 cpufreq / devfreq:让性能按需,而不是全速跑
- CPU governor 推荐:
schedutil(通常) - 但要确保:schedutil 的采样与负载统计不会“被任务唤醒误导”
GPU/NPU/DDR 常用:devfreq governor(simple_ondemand 等)
实战建议:
- 先限制 max freq 看功耗下降幅度,再回推是否需要更细 OPP
8. 系统层低功耗:从“进程行为”把功耗压下去
8.1 轮询是待机功耗第一杀手
任何 100ms/1s 轮询都会:
- 唤醒 CPU
- 触发 timer
- 让 cpuidle 无法进入深度 state
策略:
- 用 event 驱动(epoll、inotify、netlink)替代轮询
- 合并定时器
8.2 日志与监控:你以为的“轻量”,可能是高功耗
- 高频打印(dmesg/logcat)
- 高频采样 CPU/GPU/温度
策略:
- 待机态关闭监控
- 降低采样频率
8.3 网络保活:必须明确“是否需要”
- 需要:用 WOWLAN/DTIM/keepalive,评估代价
- 不需要:直接断电/ifdown/stop supplicant
9. 以 RK3588 相机/平板类产品为例:一套可执行的低功耗落地步骤
你现在的项目场景(4 路 camera + 平板/主控 + BLE 唤醒)非常适合用这套步骤。
Step 1:建立功耗基线(必须)
- P0/P1/P2/P3 各跑一次
- 每次都 dump 采集包 + 外部电流
Step 2:优先关大户
- 灭屏:确保 display pipeline 关 + PHY 睡
- 停 camera:释放所有 v4l2 节点
- USB/PCIe:没用则 runtime suspend
Step 3:修 runtime PM
- 从
runtime_status=active的设备开始逐个清 - 每清掉一个设备,看 rail 电流是否下降
Step 4:修唤醒源与中断
-
查看
wakeup_sourcestop offenders -
对应到
/proc/interrupts -
解决:
- IRQ 抖动(GPIO 配置、上拉、触发沿)
- 不必要 wakeup(关闭设备 wakeup)
Step 5:做 system suspend(P3)
- 确认进入 suspend-to-RAM
- 唤醒路径验证:GPIO/RTC/BT
Step 6:回归与自动化
- 每天跑一次“待机 8 小时”回归
- 输出功耗曲线与唤醒统计
10. BLE/Wi‑Fi 做唤醒源:工程视角要点(与你当前项目强相关)
你之前讨论过“scan 到设备但不连接就唤醒”。这属于:
- 平板侧:保持扫描(耗电)
- 相机侧:广告(耗电),或低功耗广播
- 唤醒:需要硬件上能触发 wakeup(GPIO/host wake/BT wake)
10.1 结论先说清
-
“仅靠扫描结果唤醒对端”:本质是“对端一直在广播,你一直在扫描”。
- 扫描端功耗通常更高。
-
更合理:让相机侧进入深度待机,由平板侧通过“唤醒链路”触发(GPIO/PMU 唤醒/专用唤醒线/超低功耗无线)。
10.2 如果必须 BLE 唤醒,硬件上至少要满足
- BT 芯片/模组具备 host_wake / device_wake 引脚
- 该引脚连接到 always‑on 域可作为 wakeup IRQ
- 低功耗状态下 BT 仍供电(IO rail 保持)
10.3 软件上要配合
- 将 BT 控制器/驱动设置为 wakeup source
- suspend 时允许控制器保活(视芯片能力)
扩展写作点:
- Broadcom/Realtek BT 的 host_wake 机制与 DTS 配置
- 蓝牙广告间隔/扫描窗口对功耗的量化影响
- 4 路 camera + 平板场景的状态机与协议设计
11. Yocto / 系统集成侧:低功耗不是“改内核就完了”
11.1 systemd:待机态服务裁剪
- 关闭不必要的 daemon
- 待机态停止 camera/AI pipeline
11.2 默认 governor 与限制
-
boot 默认设置:
- cpufreq governor
- devfreq governor
- max freq
11.3 配置接口:用统一的“电源策略服务”管理
建议做一个 power‑manager(守护进程或脚本):
- 统一切换 P0~P4
- 统一输出日志与 dump
12. 常见问题与“定位套路”(很实战)
Q1:为什么进入待机后功耗没怎么降?
排查顺序:
- 显示是否真的关?(clk_summary / domain)
- camera/ISP 是否仍 active?(runtime_status)
- DDR 是否仍高频?(devfreq)
- 是否被频繁唤醒?(wakeup_sources/interrupts)
Q2:为什么 domain 关不掉?
- 某设备没有 runtime suspend
- 某用户态进程一直持有 fd
- IRQ 触发导致设备被唤醒
Q3:为什么 suspend 立即被唤醒?
- wakeup source 配置过多
- GPIO 抖动/浮空
- 网络/蓝牙/USB 事件
13. 章节扩展计划:如何把本文“加厚到 55,000+ 字”(你要的目标)
下面是我为你预留的扩展目录,按它补充就能稳定超过 55,000 字,并且内容不会“水”。每一项都对应:更多硬件原理 + 更多代码阅读 + 更多实测案例。
Part A:RK3588 硬件与电源架构(+12k~18k 字)
- A1:RK3588 电源域/时钟域/复位域的概念对应
- A2:典型核心板 + 载板 Power Tree 实例拆解
- A3:IO rail 与低功耗下的引脚电气(泄漏、电平、保持)
- A4:DDR 自刷新/掉电模式的硬件条件
Part B:Linux 框架深挖(+15k~20k 字)
- B1:cpuidle 深度状态与 PSCI 交互
- B2:runtime PM 引用计数、autosuspend 机制
- B3:genpd 内部实现与 Rockchip PMU 驱动代码解读
- B4:cpufreq/devfreq/OPP 全链路
Part C:RK3588 子系统实战(+15k~20k 字)
- C1:DRM/VOP2/DP/HDMI 低功耗路径(runtime suspend、PHY LPM)
- C2:camera/ISP/MPP 编码器低功耗路径
- C3:Wi‑Fi/BT 低功耗与唤醒(含参数量化)
- C4:USB3/PCIe/SerDes LPM
Part D:工程化与回归(+8k~12k 字)
- D1:功耗回归体系(脚本、指标、阈值)
- D2:外部仪表与 rail 采样方案
- D3:Bug 案例库:10 个真实问题从现象到根因
14. 附录:你可以直接用的“待机自检清单”
- 灭屏后 VOP/PHY domain 进入 suspend
- camera 相关节点 fd 全部释放
-
wakeup_sources前三名可解释 -
clk_summary中高频时钟数量显著下降 -
pm_genpd_summary中大户 domain 为 off - CPU 进入深 idle state 的驻留时间占比高
- DDR/devfreq 在待机态能降到低档
15. 结语:把低功耗当作“系统工程”
RK3588 这种 SoC 的低功耗,靠的不是某个神奇开关,而是:
- 硬件上:电源树/唤醒线/IO rail 必须设计正确
- 内核上:runtime PM + genpd + DVFS 路径必须打通
- 系统上:业务进程要配合释放资源、减少唤醒
- 工程上:必须有测量、有基线、有回归
📺 B站视频讲解(Bilibili):https://www.bilibili.com/video/BV1k1C9BYEAB/
📘 《Yocto项目实战教程》京东购买链接:Yocto项目实战教程
10万+

被折叠的 条评论
为什么被折叠?



