首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >PM OPP Interface

PM OPP Interface

作者头像
233333
发布2023-04-30 16:01:55
3210
发布2023-04-30 16:01:55
举报

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。具体解析过程不再描述。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-04-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 前言
  • 2. 功能说明
    • 2.1 什么是OPP
      • 2.2 使用场景
        • 2.3 实现思路
        • 3. 接口说明
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档