5. Wakeup源电源域:Power Domain概念
聊到Wakeup源,有个概念绕不开——电源域(Power Domain)。
说白了,电源域就是芯片内部一块独立的供电区域。你可以把它想象成一座大楼里的独立电表。每个区域可以单独开关电,互不影响。
我刚开始接触电源管理时,觉得这玩意儿不就是个开关嘛。后来踩了坑才明白,电源域的划分直接决定了你的设备能不能正常唤醒。
5.1 什么是Power Domain?
在SoC设计中,芯片被划分成多个电源域。每个域有自己的供电轨(power rail)。
- Always-on Domain:永远带电的区域。比如RTC、唤醒逻辑、一部分GPIO。
- Core Domain:CPU核心所在的区域。休眠时可以完全断电。
- Peripheral Domain:外设区域。比如USB、I2C、SPI控制器。
- Memory Domain:内存控制器和缓存区域。
每个域之间通过电源开关(Power Switch)和电平转换器(Level Shifter)连接。
举个例子:
// 电源域划分示意(伪代码)
power_domain pd_always_on {
voltage = "1.8V";
always_on;
includes = <&rtc &wakeup_ctrl &gpio0>;
};
power_domain pd_core {
voltage = "0.9V";
power_switch = "sw_core";
includes = <&cpu0 &cpu1 &l2_cache>;
};
power_domain pd_usb {
voltage = "1.2V";
power_switch = "sw_usb";
parent = &pd_always_on; // 依赖always-on域
};
嗯,这里要注意:Wakeup源必须位于Always-on域中。否则你设备都断电了,谁来检测唤醒信号?
5.2 Wakeup源与电源域的关系
这个关系其实很直接:
- Wakeup源所在的电源域不能断电。至少它的检测逻辑必须带电。
- 被唤醒的目标域可以断电。比如CPU Core域在休眠时完全断电,但Always-on域里的GPIO检测到按键后,再给Core域上电。
- 跨域唤醒需要电平转换。Always-on域可能是1.8V,Core域是0.9V,信号传递必须经过电平转换。
我在项目中遇到过一个问题:某个GPIO作为Wakeup源,但它在设备树里配置的电源域是Core域。结果系统休眠后Core域断电,这个GPIO根本检测不到按键。折腾了两天才发现是电源域配错了。
5.3 设备树中power-domains属性配置
设备树里怎么配?看这个例子:
// 定义电源域
power-domains {
pd_always_on: pd_always_on@0 {
compatible = "mediatek,power-domain";
reg = <0>;
#power-domain-cells = <0>;
domain-name = "always_on";
always-on;
};
pd_core: pd_core@1 {
compatible = "mediatek,power-domain";
reg = <1>;
#power-domain-cells = <0>;
domain-name = "core";
power-switch = &sw_core;
};
};
// 设备绑定电源域
&uart0 {
compatible = "mediatek,uart";
reg = <0x11002000 0x1000>;
interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_LOW>;
clocks = &<&uart_clk>;
power-domains = <&pd_always_on>; // UART在Always-on域
wakeup-source; // 标记为Wakeup源
};
&gpio_key {
compatible = "gpio-keys";
power-domains = <&pd_always_on>; // 按键必须在Always-on域
wakeup-source;
key-vol-up {
label = "Volume Up";
gpios = <&gpio0 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_VOLUMEUP>;
};
};
关键点:
power-domains属性指定设备属于哪个电源域wakeup-source属性标记该设备可以作为唤醒源- Always-on域的设备不需要
power-domains属性?错!必须显式指定,否则内核不知道它属于哪个域
// Wakeup源 - Always-on域这样review代码时一眼就能看出问题。
5.4 电源域配置的常见坑
我曾经踩过一个坑,分享给你:
某款平板电脑,休眠后无法用USB唤醒。查了很久,发现USB控制器在设备树里配了power-domains = &pd_usb,而pd_usb的父域是pd_core。休眠时Core域断电,USB域也跟着断了。USB的Wakeup信号根本传不到Always-on域。
解决办法:把USB的Wakeup检测逻辑放到Always-on域里,或者让USB域独立供电。
嗯,这里有个原则:Wakeup源的检测逻辑必须和它的供电域在同一个Always-on域中。如果做不到,至少保证检测逻辑的供电不依赖于休眠断电的域。
5.5 知识体系图
下面这张图展示了Wakeup源与电源域的关系:
从这张图可以看出:
- Wakeup源和唤醒检测逻辑都在Always-on域中
- 唤醒信号从Always-on域传到Core域
- 电源开关控制信号从Always-on域控制Core域的上电/下电
- 两个域之间需要电平转换
5.6 实际项目中的配置建议
最后,给你几个我在实际项目中总结的建议:
- 先画电源域拓扑图。别急着写代码,先搞清楚芯片里哪些域是Always-on,哪些可以断电。
- Wakeup源统一放在Always-on域。如果芯片不支持,至少保证检测逻辑在Always-on域。
- 设备树里显式配置power-domains。不要依赖默认值,默认值往往是错的。
- 验证时测试休眠唤醒。用
echo mem > /sys/power/state进入休眠,然后触发Wakeup源,看能不能正常唤醒。 - 检查内核日志。如果唤醒失败,
dmesg里通常会有电源域相关的错误信息。
好了,这一章就到这里。电源域的概念其实不难,难的是在实际项目中把每个设备的电源域都配对。多画图、多验证,慢慢就有感觉了。