驱动开发硬核特训 · 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

c 复制代码
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到一个电源域

dts 复制代码
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() 注册:

c 复制代码
struct generic_pm_domain **domains;
domains = devm_kzalloc(...);
of_genpd_add_provider_onecell(np, &data);
  • onecell_data包含域指针数组
  • 通过 index 查找域

✅ 这一步将设备树中定义的电源域注册到 GENPD 框架。


2. 设备绑定电源域

设备驱动通常在 probe() 时绑定:

c 复制代码
genpd = genpd_get_from_provider(dev);
pm_genpd_attach(dev, genpd, NULL);
  • 查找对应电源域
  • 调用 pm_genpd_attach() 绑定设备到域

✅ 绑定后,设备的 runtime PM操作(如 suspend/resume)会自动通知电源域。


3. 电源域开关逻辑

开域:

c 复制代码
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;
}

关域:

c 复制代码
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 电源域

📖 实例流程

  1. 设备树 :GPU节点绑定了gpu_pd电源域
  2. 平台驱动 :注册gpu_pd,并设置power_on/power_off接口
  3. 驱动probe时 :GPU设备调用pm_genpd_attach
  4. 运行时管理 :
    • GPU使用时,调用pm_runtime_get() → 域自动上电
    • GPU空闲时,调用pm_runtime_put() → 域自动断电
  5. 实际供电动作:通过PCA9450的某一路Buck输出电源开关控制

✅ 从高层逻辑到底层硬件,一气呵成!


九、小结与工程启示

主题 结论
Power-domain是框架吗? ✅ 是 GENPD 功能框架
可以归为子系统吗? ✅ 可以,属于电源管理子系统的一部分
管什么? 管理功能域的电源开关状态
怎么使用? 设备树描述 + 设备绑定 + runtime控制

✅ 学透 Power-domain 框架,你就掌握了 Linux 系统级电源控制的关键!


🔥 最后总结一张图(记忆版)

复制代码
[设备树 power-domains] → [GENPD 框架注册电源域] → [设备绑定域] → [runtime 调度开关] → [PMIC控制硬件电源]

📺 视频教程请关注 B 站:"嵌入式Jerry"


相关推荐
wuminyu4 小时前
JVM规范学习总结:解释器与JIT编译器如何处理JVM字节码
java·linux·c语言·jvm·c++
小徐不徐说4 小时前
序列化与反序列化:把 C++ 对象可靠地保存下来
开发语言·数据库·c++·php
ragnwang5 小时前
Notes: Python pybind11 import C++ module
开发语言·c++·python
Wang's Blog5 小时前
Java 项目实战: 交友项目 - 搜索附近的功能概述和分析
java·开发语言·交友
骑着蜗牛撵大象3275 小时前
大模型 Agent 的沙箱护栏:gVisor 隔离、出口白名单与审计闭环
java·开发语言·jvm·安全·agent沙箱·gvisor·microvm
IMPYLH5 小时前
Linux 的时间为什么会被拨回去
linux·运维·服务器
Dxy12393102166 小时前
JS DES 加密详解
开发语言·javascript·arcgis
充值内卷6 小时前
我给桌面加了个鱼缸:C++ 写后端,WebView2 里养一座 Three.js 小岛
开发语言·javascript·c++
云和数据.ChenGuang6 小时前
深入解析 Python 的 dir():从用法到 CPython 源码实现
开发语言·人工智能·python·langchain
叼烟扛炮7 小时前
[Git 实战] 学习笔记:从生成 SSH 密钥到解决 TortoiseGit 推送报错全指南
linux·运维·笔记·git·学习