驱动开发硬核特训 · Day 22(下篇): # 深入理解 Power-domain 框架:概念、功能与完整代码剖析
一、Power-domain 框架基础概念
✏️ 什么是 Power-domain?
在 Linux 内核中,Power-domain(电源域) 是指一组硬件模块的逻辑集合,这些模块可以被统一控制电源状态(上电、断电)。
Linux 内核通过 Generic Power Domain Framework(GENPD) 来统一管理所有 Power-domain 的创建、绑定与控制。
📚 标准定义总结:
Power-domain 是对硬件供电关系的逻辑抽象,GENPD框架负责统一管理不同电源域的开关操作。
✅ 注意:
- Power-domain 是一种逻辑划分
- GENPD 是实现这一功能的具体框架
二、为什么需要 Power-domain?
随着 SoC 集成度越来越高,比如 CPU、GPU、VPU、ISP、Camera Controller 都集成在一起,需要按功能模块独立开关电源以节能。
所以:
- 如果模块没在使用,应当及时断电
- 不同模块有不同的电源依赖关系
- 需要统一调度开关,保证系统稳定
这就是 Power-domain 和 GENPD 框架存在的意义。
三、Power-domain 的核心功能
核心功能 | 详细描述 |
---|---|
统一开关电源域 | 通过标准接口 pm_genpd_power_on() / pm_genpd_power_off() |
自动状态管理 | 动态检测设备使用情况,空闲时关闭电源 |
支持子设备层次绑定 | 一个电源域下可以管理多个子设备 |
与 Runtime PM 框架协同 | 设备运行时自动 suspend/resume 控制电源域 |
与系统挂起唤醒流程集成 | 支持 suspend/resume 流程统一管理域状态 |
✅ 小结:Power-domain 是系统电源管理的中层调度器,连接上层电源策略和底层电源硬件。
四、Power-domain 框架核心结构
🔎 关键数据结构:struct generic_pm_domain
struct generic_pm_domain {const char *name;struct dev_pm_domain domain;struct list_head gpd_list_node;int (*power_on)(struct generic_pm_domain *genpd);int (*power_off)(struct generic_pm_domain *genpd);struct list_head master_links;struct list_head slave_links;unsigned int device_count;unsigned int state;...
};
主要字段解释:
字段 | 含义 |
---|---|
name | 电源域名字 |
domain | 内嵌的标准 dev_pm_domain 结构 |
power_on/power_off | 域上电/断电的回调函数 |
device_count | 挂在域上的设备数 |
master_links/slave_links | 电源域之间的依赖关系 |
✅ generic_pm_domain
是 GENPD 框架管理 Power-domain 的核心对象。
五、Power-domain 框架工作流程
🔥 整体调用链流程
设备树 power-domains 属性绑定↓
平台总线解析设备并注册↓
GENPD框架注册电源域↓
设备通过 pm_genpd_attach() 绑定电源域↓
设备 runtime suspend/resume 调用 pm_runtime_put()/get()↓
GENPD框架根据设备状态开关电源域↓
执行 power_on()/power_off() 函数,操作底层硬件
✅ 小结:设备和电源域绑定后,电源域的开关完全由GENPD框架统一调度。
六、设备树绑定配置
✏️ 示例:绑定GPU到一个电源域
gpu: gpu@0 {compatible = "fsl,imx8mq-gpu";power-domains = <&gpu_pd>;
};gpu_pd: power-domain@1 {compatible = "fsl,imx8mq-gpu-pd";#power-domain-cells = <0>;
};
解释:
gpu
节点的power-domains = <&gpu_pd>
,表示 GPU设备属于gpu_pd
这个电源域管理。gpu_pd
节点定义了域的属性,通常需要配合一个平台特定的 driver 来注册 domain。
✅ 设备树是设备和电源域绑定关系的入口。
七、真实代码剖析
1. 注册电源域
调用 of_genpd_add_provider_onecell()
注册:
struct generic_pm_domain **domains;
domains = devm_kzalloc(...);
of_genpd_add_provider_onecell(np, &data);
onecell_data
包含域指针数组- 通过 index 查找域
✅ 这一步将设备树中定义的电源域注册到 GENPD 框架。
2. 设备绑定电源域
设备驱动通常在 probe() 时绑定:
genpd = genpd_get_from_provider(dev);
pm_genpd_attach(dev, genpd, NULL);
- 查找对应电源域
- 调用
pm_genpd_attach()
绑定设备到域
✅ 绑定后,设备的 runtime PM操作(如 suspend/resume)会自动通知电源域。
3. 电源域开关逻辑
开域:
int pm_genpd_power_on(struct generic_pm_domain *genpd)
{if (genpd->state == GENPD_STATE_ON)return 0;ret = genpd->power_on(genpd);genpd->state = GENPD_STATE_ON;
}
关域:
int pm_genpd_power_off(struct generic_pm_domain *genpd)
{if (genpd->state == GENPD_STATE_OFF)return 0;ret = genpd->power_off(genpd);genpd->state = GENPD_STATE_OFF;
}
✅ 实际的供电动作由 power_on()
和 power_off()
函数完成,比如:
- 通过调用 regulator enable/disable
- 通过 i2c 命令控制 PMIC
八、典型实例分析:PCA9450 管理 GPU 电源域
📖 实例流程
- 设备树:GPU节点绑定了
gpu_pd
电源域 - 平台驱动:注册
gpu_pd
,并设置power_on/power_off接口 - 驱动probe时:GPU设备调用
pm_genpd_attach
- 运行时管理:
- GPU使用时,调用
pm_runtime_get()
→ 域自动上电 - GPU空闲时,调用
pm_runtime_put()
→ 域自动断电
- GPU使用时,调用
- 实际供电动作:通过PCA9450的某一路Buck输出电源开关控制
✅ 从高层逻辑到底层硬件,一气呵成!
九、小结与工程启示
主题 | 结论 |
---|---|
Power-domain是框架吗? | ✅ 是 GENPD 功能框架 |
可以归为子系统吗? | ✅ 可以,属于电源管理子系统的一部分 |
管什么? | 管理功能域的电源开关状态 |
怎么使用? | 设备树描述 + 设备绑定 + runtime控制 |
✅ 学透 Power-domain 框架,你就掌握了 Linux 系统级电源控制的关键!
🔥 最后总结一张图(记忆版)
[设备树 power-domains] → [GENPD 框架注册电源域] → [设备绑定域] → [runtime 调度开关] → [PMIC控制硬件电源]
📺 视频教程请关注 B 站:“嵌入式Jerry”