Linux电源管理(15)_PM OPP Interface

作者:wowo 发布于:2015-6-4 21:54 分类:电源管理子系统

1. 前言

本文是分析cpufreq framework之前的一篇前置文章,用于介绍Linux电源管理中的Operating Performance Point (OPP)接口。

OPP是一个单纯的软件library,用于归纳、管理各个硬件模块的、可工作的{频率}/ {电压}组合。它不涉及任何硬件,也没有复杂的逻辑,再加上Kernel document(Documentation/power/opp.txt )描述的非常清晰,因此本文只是简单的从功能和API两个方便介绍OPP,不再分析其source code及内部实现逻辑。

2. 功能说明

2.1 什么是OPP

“Documentation/power/opp.txt ”中解释OPP的原话(我翻译了一下)是:

当前复杂的SoCs都包括多个协同工作的子模块。根据具体的应用场景,很多子模块(蜗蜗注:典型的例子是CPU)并不需要一直工作在最高的频率上。因此SoC中的子模块划分为不同的domains,允许一些domains在较低的电压/频率下工作,而另一些在较高的电压/频率下工作。

domain中的设备支持的所有频率和电压的组合,称作Operating Performance Points,简称为OPPs。

注1:为什么一定是频率和电压的组合?因为频率高低决定器件的工作性能,降低性能的目的是节省功耗。但频率对功耗的影响是有限的,而电压对功耗的影响却相当可观。那频率和电压有什么关系呢?通常情况下,当频率降低之后,器件的工作电压也是可以降低的(回忆一下数字电路)。因此不同的“频率/电压”组合,就组成了器件在性能和功耗之间的跷跷板,我们需要做的,就是根据实际场景,选择一个合适的组合。

2.2 使用场景

对具备多个OPP的设备而言,相关的使用场景包括:

1)需要一个三维数组,保存所有的OPPs。

2)可以方便的更改OPP条目。

3)当需要改变设备的OPP时,可以方便的查询设备支持哪些OPP。

4)可以通过一定的条件查询OPP信息,例如以频率值查询、以电压值查询、以频率或者电压范围查询等等。

5)其它需求。

其实蛮简单的,但考虑到这些需求对所有设备(应该也不是很多)都是相同,kernel就抽象出来一个library--就是OPP library,实现上述功能。具体可参考后续的描述。

2.3 实现思路

试下OPP library的主要思路,就是以设备为单位,管理OPP信息。如下(摘录自Documentation/power/opp.txt ):


* Internal data structure organization with the OPP layer library is as
* follows: 
* dev_opp_list (root) 
*      |- device 1 (represents voltage domain 1) 
*      |       |- opp 1 (availability, freq, voltage) 
*      |       |- opp 2 .. 
*      ...     ... 
*      |       `- opp n .. 
*      |- device 2 (represents the next voltage domain) 
*      ... 
*      `- device m (represents mth voltage domain) 
* device 1, 2.. are represented by dev_opp structure while each opp 
* is represented by the opp structure. 
*/

按理说,可以在设备指针(struct device)中,添加一个字段,用于保存该设备的OPP列表。但OPP人微言轻,无法打入设备模型的内部,只好自己处理了。就是上面的结构:

在OPP内部(drivers/base/power/opp.c)维护一个list,用于保存每个设备的OPP信息(由struct device_opp抽象),每个设备下面,维护了所有的OPP列表(由struct dev_pm_opp结构抽象)。所有的OPP操作,都会从root list开始遍历,直到找到合适的地方为止。

struct device_opp和struct dev_pm_opp只在OPP library的内部使用,不会把细节呈现给调用者,因为本文不会过多涉及OPP library的内部实现(比较简单),所以后面就不再描述这些结构了。

3. 接口说明

OPP library的source code位于drivers/base/power/opp.c中,header位于include/linux/pm_opp.h中,提供的接口包括(本文基于linux-3.18-rc4,其它版本的文件名或者接口名可能会有些不同):

   1: int dev_pm_opp_add(struct device *dev, unsigned long freq,
   2:                    unsigned long u_volt);

向指定的设备添加一个频率/电压组合,OPP library会在内部处理好所有事情。这里频率和电压的单位分别是Hz和uV,后面都是这个单位。

   1: int dev_pm_opp_enable(struct device *dev, unsigned long freq);
   2:  
   3: int dev_pm_opp_disable(struct device *dev, unsigned long freq);

虽然设备支持某些OPP,但driver有可能觉得比较危险,不想使用,则可以调用dev_pm_opp_disable接口,禁止该OPP。这是后面很多查询结构(除了dev_pm_opp_find_freq_exact)都无法查到该OPP。

相反,dev_pm_opp_enable用于使能指定的OPP。

注:调用dev_pm_opp_add添加进去的OPP,默认是enable的。

   1: int dev_pm_opp_get_opp_count(struct device *dev);
   2:  
   3: struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
   4:                                               unsigned long freq,
   5:                                               bool available);
   6:  
   7: struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
   8:                                               unsigned long *freq);
   9:  
  10: struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
  11:                                              unsigned long *freq);

OPP的查询接口,返回相应的dev_pm_opp指针(当作一个句柄使用),包括:

dev_pm_opp_find_freq_floor,查询小于或者等于指定freq的OPP,在返回OPP的同时,从freq指针中返回实际的freq值;

dev_pm_opp_find_freq_ceil,查询大于或者等于指定freq的OPP,在返回OPP的同时,从freq指针中返回实际的freq值;

dev_pm_opp_find_freq_exact,精确查找指定freq的OPP,同时通过available变量,可以控制是否查找处于disable状态的OPP。上面两个查找接口,是不查找处于disable状态的OPP的。

   1: unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp);
   2:  
   3: unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp);

从指定的OPP句柄中,获得频率或者电压值。

   1: #if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
   2: int of_init_opp_table(struct device *dev);
   3: #else
   4: static inline int of_init_opp_table(struct device *dev)
   5: {
   6:         return -EINVAL;
   7: }
   8: #endif

从DTS中,解析并初始化一个设备的opp table。DTS的格式如下(参考arch/arm/boot/dts/omap34xx.dtsi):

cpus {
        cpu@0 {
                /* OMAP343x/OMAP35xx variants OPP1-5 */
                operating-points = <
                        /* kHz    uV */
                        125000   975000
                        250000  1075000
                        500000  1200000
                        550000  1270000
                        600000  1350000
                >;
                clock-latency = <300000>; /* From legacy driver */
        };
};

以“operating-points”为名称,指定频率和电压组合,单位分别为kHz和uV。具体解析过程不再描述。

 

原创文章,转发请注明出处。蜗窝科技www.wowotech.net

标签: Linux PM Power opp

评论:

jackzhous
2022-04-28 10:30
时间有点久,不知道博主还能不能回复我;初学者,有个疑问,按照大学学单片机时候的理解,电源管理这些待机、睡眠最终在硬件上的体现是往硬件提供的寄存器写值,或者往芯片某个引脚拉高、拉低电平,从而硬件就变为待机、睡眠等状态,是这样理解吗?如果是在kernel代码里面哪里有代码可以体现呢?
lamb
2022-07-04 17:59
@jackzhous:kernel待机、睡眠过程看这篇入门,系统睡眠的入口在这里
http://www.wowotech.net/pm_subsystem/autosleep.html
xyq07797
2016-07-19 15:10
wowo,请教一下,如果我们想针对不同的硬件(比如cpu),分配不同的opp,这该怎么实现呢?
wowo
2016-07-19 21:41
@xyq07797:不同的DTS配置不就行了吗?
xyq07797
2016-07-20 13:16
@wowo:你的意思是不同的DTS文件吧?但是比如大部分是一样的,就operating-points不一样呢?
wowo
2016-07-20 14:27
@xyq07797:这也没有关系,使用不同的dts(dtsi)区分就行了。
xyq07797
2016-07-26 17:07
@wowo:wowo,你有接触过kernel4.4的opp吗?
wowo
2016-07-26 18:50
@xyq07797:没有。说实话,我没有用过OPP,也没有看到过这方面的例子。
SleepDeXiang
2015-06-13 14:41
正好去年搞过cpufreq、cpuidle、clk等,这个貌似还没pinctrl抽象,哈哈
wowo
2015-06-13 21:11
@SleepDeXiang:确实如此,我觉得pinctrl在kernel这么子系统里面,算是比较抽象的了。从另一个角度看,pinctrl的设计可能不是很好(纯个人意见~~)……
cy
2015-06-13 11:43
关于cpufrequency管理,我最近也在看,这里有一个系列讲解cpufrenquncy还不错:
http://blog.csdn.net/droidphone/article/details/9532999
wowo
2015-06-13 21:10
@cy:多谢推荐~~~

发表评论:

Copyright @ 2013-2015 蜗窝科技 All rights reserved. Powered by emlog