Linux电源管理(14)_PM OPP Interface

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.rst ):

通常,一个 SoC(System on Chip,芯片上的系统)包含多个可变的电压域。每个域由一个设备指针表示。与 OPP(Operating Performance Points,运行性能点)的关系可以如下表示:

  SoC
   |- device 1
   |	|- opp 1 (availability, freq, voltage)
   |	|- opp 2 ..
   ...	...
   |	`- opp n ..
   |- device 2
   ...
   `- device m

OPP 库维护一个内部列表,SoC 框架会填充该列表,并由各种上述描述的函数访问。然而,表示实际 OPP 和域的结构是 OPP 库本身的内部结构,以允许适当的抽象可在系统间重复使用。
/*
 * Internal data structure organization with the OPP layer library is as
 * follows:
 * opp_tables (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 opp_table structure while each opp
 * is represented by the opp structure.
 */

注释:这段注释描述了 OPP 层库的内部数据结构组织方式,包括 OPP 表(opp_tables)作为根,每个设备表示一个电压域,而每个 OPP 结构表示一个 OPP。

/**
 * struct dev_pm_opp - Generic OPP description structure
 * @node:	opp table node. The nodes are maintained throughout the lifetime
 *		of boot. It is expected only an optimal set of OPPs are
 *		added to the library by the SoC framework.
 *		IMPORTANT: the opp nodes should be maintained in increasing
 *		order.
 * @kref:	for reference count of the OPP.
 * @available:	true/false - marks if this OPP as available or not
 * @dynamic:	not-created from static DT entries.
 * @turbo:	true if turbo (boost) OPP
 * @suspend:	true if suspend OPP
 * @removed:	flag indicating that OPP's reference is dropped by OPP core.
 * @pstate: Device's power domain's performance state.
 * @rates:	Frequencies in hertz
 * @level:	Performance level
 * @supplies:	Power supplies voltage/current values
 * @bandwidth:	Interconnect bandwidth values
 * @clock_latency_ns: Latency (in nanoseconds) of switching to this OPP's
 *		frequency from any other OPP's frequency.
 * @required_opps: List of OPPs that are required by this OPP.
 * @opp_table:	points back to the opp_table struct this opp belongs to
 * @np:		OPP's device node.
 * @dentry:	debugfs dentry pointer (per opp)
 *
 * This structure stores the OPP information for a given device.
 */
struct dev_pm_opp {
	struct list_head node;
	struct kref kref;

	bool available;
	bool dynamic;
	bool turbo;
	bool suspend;
	bool removed;
	unsigned int pstate;
	unsigned long *rates;
	unsigned int level;

	struct dev_pm_opp_supply *supplies;
	struct dev_pm_opp_icc_bw *bandwidth;

	unsigned long clock_latency_ns;

	struct dev_pm_opp **required_opps;
	struct opp_table *opp_table;

	struct device_node *np;

#ifdef CONFIG_DEBUG_FS
	struct dentry *dentry;
	const char *of_name;
#endif
};
struct dev_pm_opp 是一个通用的 OPP 描述结构,用于存储给定设备的 OPP 信息。
node: OPP 表节点,这些节点在整个引导过程中被维护,预期只有 SoC 框架添加了一组最优的 OPP 到库中。重要的是 OPP 节点应按递增顺序维护。
kref: OPP 的引用计数。
available: 表示此 OPP 是否可用的布尔值。
dynamic: 表示 OPP 是否是通过动态方式创建的,而不是从静态设备树(DT)条目中创建的。
turbo: 如果是 Turbo(提升)OPP,则为 true。
suspend: 如果是挂起 OPP,则为 true。
removed: 表示 OPP 的引用是否被 OPP 核心移除的标志。
pstate: 设备的电源域性能状态。
rates: 频率值的数组(以赫兹为单位)。
level: 性能级别。
supplies: 电源供应的电压/电流值。
bandwidth: 互连带宽值。
clock_latency_ns: 切换到此 OPP 频率时与任何其他 OPP 频率的延迟(以纳秒为单位)。
required_opps: 此 OPP 所需的 OPP 列表。
opp_table: 指向包含此 OPP 的 opp_table 结构的指针。
np: OPP 的设备节点。
dentry: 调试文件系统的 dentry 指针(每个 OPP)。
of_name: 如果配置了调试文件系统,则是 OPP 的设备树名称。

该结构的主要目的是存储 OPP 的相关信息,以便进行电源管理和性能优化。

3. 接口说明

OPP library的source code位于drivers/opp/core.c中,header位于include/linux/pm_opp.h中,提供的接口包括

/**
 * dev_pm_opp_add() - 从表定义中添加一个 OPP 表
 * @dev:	进行此操作的设备
 * @freq:	此 OPP 的频率(赫兹)
 * @u_volt:	此 OPP 的电压(微伏)
 *
 * 此函数将 OPP 定义添加到 OPP 表中并返回状态。默认情况下,此 OPP 可用,并且可以使用 dev_pm_opp_enable/disable 函数进行控制。
 *
 * 返回值:
 * 0		成功时,或
 *		重复的 OPP(freq 和 volt 都相同)且 opp->available
 * -EEXIST	freq 相同但 volt 不同,或
 *		重复的 OPP(freq 和 volt 都相同)但 !opp->available
 * -ENOMEM	内存分配失败
 */
int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
{
	struct opp_table *opp_table;
	int ret;

	opp_table = _add_opp_table(dev, true);
	if (IS_ERR(opp_table))
		return PTR_ERR(opp_table);

	/* 为动态 OPP 修正调节器计数 */
	opp_table->regulator_count = 1;

	ret = _opp_add_v1(opp_table, dev, freq, u_volt, true);
	if (ret)
		dev_pm_opp_put_opp_table(opp_table);

	return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
/**
 * dev_pm_opp_enable() - 启用特定的 OPP
 * @dev:	进行此操作的设备
 * @freq:	要启用的 OPP 频率
 *
 * 启用提供的 OPP。如果操作有效,则返回 0,否则返回相应的错误值。此函数用于在使用 dev_pm_opp_disable 临时将 OPP 设置为不可用后,使其再次可用。
 *
 * 返回值:-EINVAL 表示指针错误,-ENOMEM 表示复制操作没有足够内存,返回 0 表示未进行修改或修改成功。
 */
int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
	return _opp_set_availability(dev, freq, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_enable);

/**
 * dev_pm_opp_disable() - 禁用特定的 OPP
 * @dev:	进行此操作的设备
 * @freq:	要禁用的 OPP 频率
 *
 * 禁用提供的 OPP。如果操作有效,则返回 0,否则返回相应的错误值。此函数用于由用户进行临时控制,使该 OPP 在适当的情况下不可用,直到通过 dev_pm_opp_enable 调用再次启用。
 *
 * 返回值:-EINVAL 表示指针错误,-ENOMEM 表示复制操作没有足够内存,返回 0 表示未进行修改或修改成功。
 */
int dev_pm_opp_disable(struct device *dev, unsigned long freq)
{
	return _opp_set_availability(dev, freq, false);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);

具体请查看drivers/opp目录下code。

dts中定义cpu frequency如下所示:

	cpu0_opp_table: opp-table-0 {
		compatible = "operating-points-v2";
		opp-shared;

		opp-600000000 {
			opp-hz = /bits/ 64 <600000000>;
			opp-microvolt = <950000 950000 1350000>;
			clock-latency-ns = <40000>;
			opp-suspend;
		};
		opp-816000000 {
			opp-hz = /bits/ 64 <816000000>;
			opp-microvolt = <1050000 1050000 1350000>;
			clock-latency-ns = <40000>;
		};
		opp-1008000000 {
			opp-hz = /bits/ 64 <1008000000>;
			opp-microvolt = <1175000 1175000 1350000>;
			clock-latency-ns = <40000>;
		};
		opp-1200000000 {
			opp-hz = /bits/ 64 <1200000000>;
			opp-microvolt = <1300000 1300000 1350000>;
			clock-latency-ns = <40000>;
		};
		opp-1296000000 {
			opp-hz = /bits/ 64 <1296000000>;
			opp-microvolt = <1350000 1350000 1350000>;
			clock-latency-ns = <40000>;
		};
	};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值