Operating Performance Points (OPP) Library

もともと、Linux Kernelのソースコードの一部なので、GPLv2扱いになる（はずの認識）。

> https://www.kernel.org/doc/html/latest/index.html
> 
> Licensing documentation
> 
> The following describes the license of the Linux kernel source code (GPLv2), how to properly mark the license of individual files in the source tree, as well as links to the full license text.
> 
> https://www.kernel.org/doc/html/latest/process/license-rules.html#kernel-licensing

https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/plain/Documentation/power/opp.rst

# Operating Performance Points (OPP) Library

(C) 2009-2010 Nishanth Menon <nm@ti.com>, Texas Instruments Incorporated

Contents

1. Introduction
2. Initial OPP List Registration
3. OPP Search Functions
4. OPP Availability Control Functions
5. OPP Data Retrieval Functions
6.  Data Structures


# 1. Introduction

## 1.1 What is an Operating Performance Point (OPP)?

> Complex SoCs of today consists of a multiple sub-modules working in conjunction.

現在の複雑なSoCは、連携して動作する複数のサブモジュールから構成されています。

> In an operational system executing varied use cases, not all modules in the SoC need to function at their highest performing frequency all the time. To facilitate this, sub-modules in a SoC are grouped into domains, allowing some domains to run at lower voltage and frequency while other domains run at voltage/frequency pairs that are higher.

様々なユースケースで利用されるoperational systemでは、SoC内のすべてのモジュールが時間に最高性能の周波数で機能する必要はありません。これを容易にするために、SoCに含まれるサブモジュールはドメインにグループ分けされ、一部のドメインはより低い電圧・周波数で実行でき、他のドメインはより高い電圧/周波数の組み合わせで動かすことができます。

> The set of discrete tuples consisting of frequency and voltage pairs that the device will support per domain are called Operating Performance Points or OPPs.

それぞれのデバイスでサポートすることができる周波数と電圧のペアで構成される個別のタプルの集合は、Operating Perfomance PointsあるいはOPPsと呼ばれます。

As an example:

> Let us consider an MPU device which supports the following:

MPU deviceが下記をサポートしている場合、

 {300MHz at minimum voltage of 1V}, 
 {800MHz at minimum voltage of 1.2V},
 {1GHz at minimum voltage of 1.3V}

> We can represent these as three OPPs as the following {Hz, uV} tuples:

これらは下記の{Hz, uV} タプルとして３つのOppsとして表現できる。

 - {300000000, 1000000}
 - {800000000, 1200000}
 - {1000000000, 1300000}

## 1.2 Operating Performance Points Library

> OPP library provides a set of helper functions to organize and query the OPP information. The library is located in drivers/opp/ directory and the header is located in include/linux/pm_opp.h. 

OPP libraryは、OPP情報を整理および参照するためのヘルパー関数の集合を提供します。ライブラリは drivers/opp ディレクトリに、ヘッダは include/linux/pm_opp.hに配置されています。

> OPP library can be enabled by enabling CONFIG_PM_OPP from power management menuconfig menu. OPP library depends on CONFIG_PM as certain SoCs such as Texas Instrument's OMAP framework allows to optionally boot at a certain OPP without needing cpufreq.

OPP libraryは、power management menuconfig メニューから、CONFIG_PM_OPPを有効かすることで有効にできます。OPP libraryは、CONFIG_PMを必要とします。 Texas InstrumentのOMAP frameworkなどの特定のSocでは、cpufreqを必要とせずに特定のOPPでオプション起動できるようになっています。

> Typical usage of the OPP library is as follows::

OPP libraryの一般的な使い方は以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/3eb76315-5c31-748f-73f9-ff2407ee84db.png)

> OPP layer expects each domain to be represented by a unique device pointer. 

OPP layerでは、それぞれのドメインがユニークなdevice pointerによって表現されることを想定しています。

> SoC framework registers a set of initial OPPs per device with the OPP layer. 

SoC frameworkは、OPP layerによってデバイス毎の初期のOPPのセットを登録します。

> This list is expected to be an optimally small number typically around 5 per device.

このリストは、デバイス毎に一般的には5程度の小さい値になると予想されます。

> This initial list contains a set of OPPs that the framework expects to be safely enabled by default in the system.

この初期リストには、フレームワークが安全に有効化できる、システムにとっての、デフォルト値を期待している一連のOPPが含まれています。

## Note on OPP Availability

> As the system proceeds to operate, SoC framework may choose to make certain OPPs available or not available on each device based on various external factors.

システムが稼働し続けると、SoC frameworkは、様々な外的要因によって、特定のOPPを各デバイスで使用可能になったり、不可能になｔったりします。 

> Example usage: Thermal management or other exceptional situations where SoC framework might choose to disable a higher frequency OPP to safely continue operations until that OPP could be re-enabled if possible.

使用例：温度管理またはその他の例外的な状況であって、SoC frameworkは高い周波数のOPPを無効化することで、可能な限り再度OPPが有効化できるまでの間、安全に動作し続けるように選択する。

> OPP library facilitates this concept in its implementation. The following operational functions operate only on available opps:

OPP library　は実装においてこのコンセプトを推進します。下記の関数は利用可能なoppsに対してのみ実行される関数です。

 opp_find_freq_{ceil, floor}, 
 dev_pm_opp_get_voltage, 
 dev_pm_opp_get_freq, 
 dev_pm_opp_get_opp_count

> dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer which can then be used for dev_pm_opp_enable/disable functions to make an opp available as required.

dev_pm_opp_find_freq_exactは、必要に応じてoppを使用可能にするためにdev_pm_opp_enable / disable関数で使用できるoppポインターを見つけるために使用されることを意図しています。

> WARNING: Users of OPP library should refresh their availability count using get_opp_count if dev_pm_opp_enable/disable functions are invoked for a device, the exact mechanism to trigger these or the notification mechanism to other dependent subsystems such as cpufreq are left to the discretion of the SoC specific framework which uses the OPP library. 

警告：OPP libraryはデバイスに対して、dev_pm_opp_enable/disable関数が呼び出されると、get_opp_countを用いて有効なカウントを更新する必要があります。トリガーとなる厳密なメカニズムあるいは他の必要とするサブシステムへ通知するメカニズムは、cpufreqのようなOPP libraryを用いたSoC徳嵩のframeworkの判断にゆだねられます。

> Similar care needs to be taken care to refresh the cpufreq table in cases of these operations.

これらを操作する場合に、cpufreqテーブルを更新する場合には、同様の注意が必要です。

# 2. Initial OPP List Registration

> The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per device. 

SoC実装では、それぞれのデバイス毎にOPPを追加するために、dev_pm_opp_add関数を繰り返し呼び出します。

> It is expected that the SoC framework will register the OPP entries optimally- typical numbers range to be less than 5. 

SoC frameworkは、一般的には5を越えない範囲で最適なOPP entryを登録することを期待されています。

> The list generated by registering the OPPs is maintained by OPP library throughout the device operation. 

OPPの登録によって生成されたリストはデバイス制御を介してOPP libraryによって維持されます。

> The SoC framework can subsequently control the availability of the OPPs dynamically using the dev_pm_opp_enable / disable functions.

SoCフレームワークは、続いてdev_pm_opp_enable/disable functionを用いて動的にOPPの有効性を制御できます。

## dev_pm_opp_add

> Add a new OPP for a specific domain represented by the device pointer. 

デバイスポインタによって表現される特有のドメインに、新しいOPPを追加します。

> The OPP is defined using the frequency and voltage. 

OPPは、周波数と電圧で定義されます。

> Once added, the OPP is assumed to be available and control of its availability can be done with the dev_pm_opp_enable/disable functions. OPP library internally stores and manages this information in the opp struct.

一度追加されたら、OPPは使用可能であるとみなし、dev_pm_opp_enable/disable functionを用いてその有効性が制御されます。OPP libraryは内部でopp構造体によってこの情報を保持し、管理します。

This function may be used by SoC framework to define a optimal list as per the demands of SoC usage environment.

この関数は、SoC frameworkによって、SoC利用環境の要求に基づいて最適なリストを定義するために用いられます。

WARNING:
> Do not use this function in interrupt context.

この関数は割り込みコンテキスト内では使ってはいけない。

Example::

```c
 soc_pm_init()
 {
	/* Do things */
	r = dev_pm_opp_add(mpu_dev, 1000000, 900000);
	if (!r) {
		pr_err("%s: unable to register mpu opp(%d)\n", );
		goto no_cpufreq;
	}
	/* Do cpufreq things */
no_cpufreq:
	/* Do remaining things */
 }
```

# 3. OPP Search Functions

> High level framework such as cpufreq operates on frequencies. 

周波数におけるcpufreq制御のようなhigh level framework.

> To map the frequency back to the corresponding OPP, OPP library provides handy functions to search the OPP list that OPP library internally manages.

周波数を関連するOPPとの関連付けをマッピングするために、OPP libraryはOPP libraryが内部管理しているOPP listを検索するための、使いやすい関数を提供します。

> These search functions return the matching pointer representing the opp if a match is found, else returns error. 

これらの検索関数は、マッチングが見つかった場合に、マッチングしたoppを表現するポインターを、そうでない場合にはエラーを返します。

> These errors are expected to be handled by standard error checks such as IS_ERR() and appropriate actions taken by the caller.

これらのエラーは、IS_ERR()等の標準エラーチェックと、呼び出し元が行う適切なアクションで処理されることが期待されています。

> Callers of these functions shall call dev_pm_opp_put() after they have used the OPP.

これらの関数の呼び出し元は、OPPを用いた後は、dev_pm_opp_put()を呼び出さなければなりません。

> Otherwise the memory for the OPP will never get freed and result in memleak.

そうでない場合にはOPPはfreeできずに、メモリリークを引き起こす結果になります。

## dev_pm_opp_find_freq_exact

> Search for an OPP based on an *exact* frequency and availability. This function is especially useful to enable an OPP which is not available by default.

"厳密な"周波数に基づいて有効なOPPを検索する。この関数は特に、デフォルトで有効になっていないOPPを有効化するときに特に役立つ。
	
Example: 

>In a case when SoC framework detects a situation where a higher frequency could be made available, it can use this function to find the OPP prior to call the dev_pm_opp_enable to actually make it available::

SoC frameworkが、より高い周波数を有効にできる状況であると判断した場合、dev_pm_opp_enableを呼びだして実際に利用可能にする前に、この関数をしようとしてOPPを見つけることができます。

```c

	 opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
	 dev_pm_opp_put(opp);
	 /* dont operate on the pointer.. just do a sanity check.. */
	 if (IS_ERR(opp)) {
		pr_err("frequency not disabled!\n");
		/* trigger appropriate actions.. */
	 } else {
		dev_pm_opp_enable(dev,1000000000);
	 }
```

NOTE:

> This is the only search function that operates on OPPs which are  not available.

これは有効ではないOPPsで動作する唯一の検索機能です。

## dev_pm_opp_find_freq_floor

> Search for an available OPP which is *at most* the 	provided frequency. 

与えられた周波数"よりも小さい最大の”の、有効なOPPを検索する。

> This function is useful while searching for a lesser match OR operating on OPP information in the order of decreasing frequency.

この関数は、より低い周波数を検索する場合、あるいは、周波数の高い順番にOPP情報を処理する場合に便利です。

Example: 

> To find the highest opp for a device::

デバイスにとって最も高い周波数を検索する。

```c
	 freq = ULONG_MAX;
	 opp = dev_pm_opp_find_freq_floor(dev, &freq);
	 dev_pm_opp_put(opp);
```

## dev_pm_opp_find_freq_ceil

> Search for an available OPP which is *at least* the 	provided frequency. 

与えられた周波数"よりも大きい最小”の、有効なOPPを検索する。

> This function is useful while searching for a higher match OR operating on OPP information in the order of increasing frequency.

この関数は、より高い周波数を検索する場合、あるいは、周波数の低い順番にOPP情報を処理する場合に便利です。


Example 1: 

> To find the lowest opp for a device::

デバイスでの最小のOPPを検索する

```c

	 freq = 0;
	 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
	 dev_pm_opp_put(opp);
```

Example 2: 

A simplified implementation of a SoC cpufreq_driver->target::

SoC cpufreq_driver->targetの単純な実装

```c
	 soc_cpufreq_target(..)
	 {
		/* Do stuff like policy checks etc. */
		/* Find the best frequency match for the req */
		opp = dev_pm_opp_find_freq_ceil(dev, &freq);
		dev_pm_opp_put(opp);
		if (!IS_ERR(opp))
			soc_switch_to_freq_voltage(freq);
		else
			/* do something when we can't satisfy the req */
		/* do other stuff */
	 }
```

# 4. OPP Availability Control Functions

> A default OPP list registered with the OPP library may not cater to all possible situation. 

OPP Libraryにデフォルトで登録されているOPP listだけでは、すべての状況に対応できるわけではありません。

> The OPP library provides a set of functions to modify the
availability of a OPP within the OPP list. 

OPP libraryは、OPP list内のOPPの有効性を変更するための関数セットを提供します。

> This allows SoC frameworks to have fine grained dynamic control of which sets of OPPs are operationally available.

これにより、SoC frameworkは、OPPのどのセットが操作上有効であるかをきめ細かく制御できます。

> These functions are intended to *temporarily* remove an OPP in conditions such as thermal considerations (e.g. don't use OPPx until the temperature drops).

これらの関数は、例えば、温度条件に基づいて"一時的に" OPPを削除することを目的としています。（温度が下がるまでの間、OPPxを利用できなくする）。

WARNING:

> Do not use these functions in interrupt context.

これらの関数は割り込みコンテクストから呼び出さないでください。

## dev_pm_opp_enable

> Make a OPP available for operation.

OPPを処理可能とする。

Example: 

> Lets say that 1GHz OPP is to be made available only if the SoC temperature is lower than a certain threshold. 

SoCの温度が規定の閾値よりも低くなったので、1GHzのOPPを有効化するとします。

> The SoC framework implementation might choose to do something as follows::

SoC frameworkの実装は、下記のようになります。

```c
	 if (cur_temp < temp_low_thresh) {
		/* Enable 1GHz if it was disabled */
		opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
		dev_pm_opp_put(opp);
		/* just error check */
		if (!IS_ERR(opp))
			ret = dev_pm_opp_enable(dev, 1000000000);
		else
			goto try_something_else;
	 }
```

## dev_pm_opp_disable

> Make an OPP to be not available for operation 

OPPを処理不可能とする。

Example: 

> Lets say that 1GHz OPP is to be disabled if the temperature exceeds a threshold value. The SoC framework implementation might choose to do something as follows::

SoCの温度が規定の閾値よりも高くなったので、1GHzのOPPを無効化するとします。SoC frameworkの実装は、下記のようになります。

```c
	 if (cur_temp > temp_high_thresh) {
		/* Disable 1GHz if it was enabled */
		opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
		dev_pm_opp_put(opp);
		/* just error check */
		if (!IS_ERR(opp))
			ret = dev_pm_opp_disable(dev, 1000000000);
		else
			goto try_something_else;
	 }
```

# 5. OPP Data Retrieval Functions

> Since OPP library abstracts away the OPP information, a set of functions to pull information from the OPP structure is necessary. 

OPP libraryがOPP情報を抽象化するために、OPP構造体から情報を引き出すための一連の関数が必要です。

> Once an OPP pointer is retrieved using the search functions, the following functions can be used by SoC framework to retrieve the information represented inside the OPP layer.

OPP pointerが検索関数によって取得されたら、下記の関数によってSoC frameworkは関連する情報をOPP layerから取得します。

## dev_pm_opp_get_voltage

> Retrieve the voltage represented by the opp pointer.

opp pointerで表現される電圧を取得する。

Example: 

> At a cpufreq transition to a different frequency, SoC
 framework requires to set the voltage represented by the OPP using the regulator framework to the Power Management chip providing the voltage::

cpufreq が異なる周波数を移動する場合、SoC frameworkは、OPPによって表現されている電圧を、Power Management chipに与える電圧としてregular frameworkを用いて設定しなければならない。

```c
	 soc_switch_to_freq_voltage(freq)
	 {
		/* do things */
		opp = dev_pm_opp_find_freq_ceil(dev, &freq);
		v = dev_pm_opp_get_voltage(opp);
		dev_pm_opp_put(opp);
		if (v)
			regulator_set_voltage(.., v);
		/* do other things */
	 }
```

## dev_pm_opp_get_freq

> Retrieve the freq represented by the opp pointer.

opp pointerで表現される周波数を取得する。

Example: 

> Lets say the SoC framework uses a couple of helper functions we could pass opp pointers instead of doing additional parameters to handle quiet a bit of data parameters::

SoC frameworkがいくつかのヘルパー関数を用いることで、追加のパラメータを実行する代わりに、opp pointerを介して少しのデータパラメータを静かに処理する事ができます。

```c
	 soc_cpufreq_target(..)
	 {
		/* do things.. */
		 max_freq = ULONG_MAX;
		 max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
		 requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
		 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
			r = soc_test_validity(max_opp, requested_opp);
		 dev_pm_opp_put(max_opp);
		 dev_pm_opp_put(requested_opp);
		/* do other things */
	 }
	 soc_test_validity(..)
	 {
		 if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp))
			 return -EINVAL;
		 if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp))
			 return -EINVAL;
		/* do things.. */
	 }
```

## dev_pm_opp_get_opp_count

> Retrieve the number of available opps for a device 

デバイスで有効なoppの数を取得する。

Example: 

> Lets say a co-processor in the SoC needs to know the available frequencies in a table, the main processor can notify as following::

SoC内のco processorが、有効な周波数のテーブルを知りたい場合、main processorは以下のように通知する。

```c
	 soc_notify_coproc_available_frequencies()
	 {
		/* Do things */
		num_available = dev_pm_opp_get_opp_count(dev);
		speeds = kzalloc(sizeof(u32) * num_available, GFP_KERNEL);
		/* populate the table in increasing order */
		freq = 0;
		while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
			speeds[i] = freq;
			freq++;
			i++;
			dev_pm_opp_put(opp);
		}

		soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
		/* Do other things */
	 }
```

# 6. Data Structures

> Typically an SoC contains multiple voltage domains which are variable. Each domain is represented by a device pointer. The relationship to OPP can be represented as follows::

通常、Socには複数の可変な電圧ドメインが含まれています。それぞれのドメインは、device pointerによって表現されます。OPPとの関連については以下のように表現できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/4af3713b-76db-a58c-5740-c54f0d679318.png)

> OPP library maintains a internal list that the SoC framework populates and accessed by various functions as described above. However, the structures representing the actual OPPs and domains are internal to the OPP library itself to allow for suitable abstraction reusable across systems.

OPP libraryは、SoC framworkが入力し、上記のような処理をアクセスするために内部リストを維持します。ただし、実際のOPPとドメインを表現する構造体は、OPP library自身の内部にあり、システム間で再利用可能な適切な抽象化がなされます。

## struct dev_pm_opp

> The internal data structure of OPP library which is used to  represent an OPP. 

OPPを表現するために利用される、OPP library内部のデータ構造。

> In addition to the freq, voltage, availability information, it also contains internal book keeping information required 	for the OPP library to operate on. 

周波数、電圧、有効情報に加えてさらに、OPP libraryが処理した内部の簿記情報も含まれる。

Pointer to this structure is provided back to the users such as SoC framework to be used as a identifier for OPP in the interactions with OPP layer.

この構造のポインタは、soC frameworkのようなユーザーに、OPP layerの反復の中でOPPのイテレータとして提供されるものである。

WARNING:

> The struct dev_pm_opp pointer should not be parsed or modified by the users. 

dev_pm_opp 構造体のpointerは、ユーザーによってパースしたら変更したりしないでください。

> The defaults of for an instance is populated by  dev_pm_opp_add, but the availability of the OPP can be modified  by dev_pm_opp_enable/disable functions.

インスタンスのデフォルトは、dev_pm_opp_addによって入力される。そして、dev_pm_opp_enable/disable関数によって、OPPの有効性は変化することができる。

## struct device

> This is used to identify a domain to the OPP layer. 

これは、OPP layrtでドメインの識別に用いられる。

> The nature of the device and its implementation is left to the user of OPP library such as the SoC framework.

デバイスの性質とその実装は、SoC framwworkなどのOPPライブラリのユーザーに委ねられます。

Overall, in a simplistic view, the data structure operations is represented as following::

全体的に、単純化したビューでは、データ構造操作は以下のように表現されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/89434/ed5a909d-60f6-8cc8-6619-503346a18f67.png)