电源管理入门-18 Power Domain管理
SoC中通常有很多IP按逻辑可以把几个相关功能的IP划为一个电源域。一个电源域内的IP通常按相同的方式由同一个硬件模块PMIC供电电压一样并且电源管理例如休眠唤醒一致。为什么有设备电源管理还需要power domain划分对每个设备电源管理太细化了会造成额外的开销。通常几个设备可以一块进行管理更加的方便例如一个子系统要么全工作要么全关闭不会子系统内的某个设备单独工作。这时候为了简化管理工作就需要划分出来一个domain。SOC上众多电源域组成了一个电源域树他们之间存在着相互的约束关系子电源域打开前需要父电源域打开父电源域下所有子电源域关闭父电源域才能关闭。Domain这个词一般在权限管理中经常遇到用于隔离Domain内共进退。虽然电源域的好处多多却不是越多越好因为划分电源域是需要成本的需要在PMU中使用模拟电路完成包括金钱成本和空间成本。因此大多数系统会根据功能设置有限的几个电源域例如CPU core1、2、3…GPUNANDDDRUSBDisplayCodec等等。这种设计引出一个问题存在多个模块共用一个电源域的情况。因而要求在对模块power on/off的时候考虑power共用的情况只要一个模块工作就要power on直到所有模块停止工作才能power off。1. 框架介绍Kernel的PM domain framework位于drivers/base/power/domain.c中提供了管理和使用系统power domain的统一方法对底层power domain硬件的操作对power domain hw的开启操作包括开钟、上电、解复位、解除电源隔离等操作的功能封装对power domain hw的关闭操作包括关钟、断电、复位、做电源隔离等操作的功能封装内部逻辑实现通过dts描述power domain框架的设备节点并描述每个power domain节点。提供出一个power domain framework的设备节点及每个power domain子设备的节点并指定power-domain-ccell 1这样可以通过power domain framework的设备及power domain的编号查找具体的power domain实现dts解析逻辑获取power domain的配置信息并通过初始化函数对每个power domain进行初始化所有的power domain统一的放在一个全局链表中将power domain下所有的设备放到其下的一个设备链表中为runtime pm、系统休眠唤醒等框架注册相应的回调函数并实现具体的回调函数对应的power domain的开关函数上层使用power domain的上游驱动、框架及debug fslinux系统的runtime power manager 框架通过提供runtime_pm_get_xxx/runtime_pm_put_xxx类接口给其他的drivers对设备的开、关做引用计数当引用计数从1-0时会进一步调到power domain注册的runtime_suspend回调回调函数里会先调用设备的runtime_suspend回调然后判断power domain下的设备链表中所有的设备是否已经suspend若已经suspend才真正关闭power domain。当引用计数从0-1时会先调用到power domain使用的runtime_resume回调回调函数里会先调用power domain的开启操作然后调用设备注册的runtime_resume回调函数系统休眠唤醒在suspend_noirq/resume_noirq时会进行power domain的关闭与开启的操作使用power domain的上游驱动power domain内部ip的驱动。比如dsp子系统power domain下面有多个dsp核每个dsp核对应一个power domain。这样每个dsp核设备驱动都要关联到对应的dsp核power domain上通过dsp核设备的dts里power-domains的属性引用power domain framework的节点引用及具体power domain的编号将dsp核设备与相应的power domain关联起来使用power domain的框架runtime pm/系统休眠唤醒power domain也提供了一些debug fs文件节点供用户debug使用主要就是/sys/kernel/debug/pm_genpd/目录及power domain名字目录下的一些文件节点pm_genpd_summary打印所有的power domain、状态及下面所挂的设备状态power_domain名字目录/current_statepower domain当前的状态power_domain名字目录/sub_domainspower domain当前的子power domain有哪些power_domain名字目录/idle_statespower domain对应的所有idle状态及其off状态的时间power_domain名字目录/active_statespower domain处于on状态的时间power_domain名字目录/total_idle_timepower domain所有idle状态的off时间总和power_domain名字目录/devicespower domain下所挂的所有devices相关数据结构image.png初始化流程以scmi power domain的驱动框架为例image.png2. 如何使用power domain在dts中定义一个power domain节点同时在驱动中注册该power domain即可//DTS中定义power domain节点这里以内核文档提供的例程 parent: power-controller12340000{compatiblefoo,power-controller;reg0x12340000 0x1000;#power-domain-cells 1; //这里表明parent节点是一个power domain也就是内核文档所形容的providerparent管理它下面挂接着的其它模块为它们提供电源};child: power-controller12341000{compatiblefoo,power-controller;reg0x12341000 0x1000;power-domainsparent0;//这里表明child节点是parent下面的一个模块它使用parent提供的电源#power-domain-cells 1;};从上面的dts语法中可以看出一个系统的电源域从dts中可以很容易就看出来#power-domain-cells声明该节点是一个power domainpower-domains xxx x表明该节点属于xxx电源域那么系统中某个电源域下面有多少个模块就从dts中看有多少个节点引用了该电源域即可。3. providerint pm_genpd_init(struct generic_pm_domain *genpd, struct dev_power_governor *gov, bool is_off)//初始化一个 generic_pm_domain 实例 //下面两个接口都可以用来向内核注册一个power domian int of_genpd_add_provider_onecell(struct device_node *np, struct genpd_onecell_data *data)int of_genpd_add_provider_simple(struct device_node *np, struct generic_pm_domain *genpd)pm_genpd_init这个函数从注释可以看出它初始化了一个power domain实例从入口参数结合具体的实现代码可以很容易得到 structgeneric_pm_domain结构体就对应着一个power domain实例。struct generic_pm_domain{struct dev_pm_domain domain;/* PM domain operations */ const char *name;atomic_t sd_count;/* Number of subdomains with poweron*/ enum gpd_status status;/* Current state of the domain */ unsigned int device_count;/* Number of devices */ unsigned int suspended_count;/* Systemsuspenddevice counter */ unsigned int prepared_count;/* Suspend counter of prepared devices */ int(*power_off)(struct generic_pm_domain *domain);//驱动只要实现该函数即可 int(*power_on)(struct generic_pm_domain *domain);//驱动只要实现该函数即可真正需要驱动去赋值的成员只有两个那就是int (*power_off)(struct generic_pm_domain *domain); 与int (*power_on)(struct generic_pm_domain *domain);其它的power domain framework已经帮我们做好了这里我们也可以猜到一个电源域的打开与关闭最终是通过驱动注册的这两个函数操作的当驱动得到一个power domain实例后便可以调用of_genpd_add_provider_simple函数向内核注册一个power domain了来进入该函数看看做了哪些事情看不太懂但是从入口参数看传进去了驱动实现的struct generic_pm_domain和power domain的node节点。后续这两个参数应该会有作用。4. ConsumerCousumer可能是一个驱动程序或者sysfs在驱动probe函数中调用dev_pm_domain_attachretdev_pm_domain_attach(_dev,true);//将设备与电源域进行耦合驱动在probe的时候会调用dev_pm_domain_attach函数检查设备是否属于power domain设备如果是则获取设备的power domain信息从哪里获取信息就是从前面power domain驱动调用of_genpd_add_provider_simple函数注册进来的信息。调用genpd_add_device函数将设备添加到该power domain中主要完成一些struct generic_pm_domain成员的赋值操作。最后最重要的就是调用dev_pm_domain_set该函数设置了struct device中的struct dev_pm_domain成员该成员被赋值为struct generic_pm_domain中的struct dev_pm_domain成员。参考http://news.eeworld.com.cn/mp/rrgeek/a144963.jspxhttps://zhuanlan.zhihu.com/p/578780233后记power domain在底层的处理通常需要PPU硬件的参与管理可以控制这个电源域的时钟、电压、供电等属性从而达到对电源和功耗的管理。干啥都能干干啥啥不是专业入门劝退堪称程序员杂家”。欢迎各位有自己公众号的留言申请转载多谢后续会继续更新纯干货分析欢迎分享给朋友欢迎点赞、收藏、在看、划线和评论交流公众号“那路谈OS与SoC嵌入式软件”欢迎关注个人文章汇总https://thatway1989.github.io
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2500057.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!