← Documents Documentation/power/opp.rst GitHub 원문 ↗

Linux 6.18.37 · Power

Operating Performance Points (OPP) Library

SoC domain별 frequency·voltage OPP 목록을 등록하고 availability를 동적으로 제어하며, opaque OPP pointer로 검색·조회·순회하는 library API와 자료 구조를 설명합니다.

Source pathDocumentation/power/opp.rst
Source versionLinux v6.18.37
TranslationDUJINLABS 전문 번역 + 해설

요약·해설과 원문, 전문 번역을 서로 분리했습니다. API 이름, symbol, source path는 원문 표기를 사용합니다.

1. 요약·해설

원문의 핵심 논리와 kernel programming 관점의 보충 설명입니다. 아래의 전문 번역과는 별도로 작성했습니다.

요약·해설

opp.rst:1-381

OPP library는 device pointer를 domain identifier로 사용해 안전한 frequency·voltage pair를 관리합니다. Search 결과의 reference를 반드시 `dev_pm_opp_put()`으로 해제하고, thermal 정책은 enable·disable 뒤 count와 cpufreq table을 갱신해야 합니다.

2. 영어 원문 전체

번역 기준이 된 Linux v6.18.37 원문입니다. 줄 번호는 이 버전의 파일 좌표입니다.

원문 전체 펼치기
1 ==========================================
2 Operating Performance Points (OPP) Library
3 ==========================================
4
5 (C) 2009-2010 Nishanth Menon <[email protected]>, Texas Instruments Incorporated
6
7 .. Contents
8
9 1. Introduction
10 2. Initial OPP List Registration
11 3. OPP Search Functions
12 4. OPP Availability Control Functions
13 5. OPP Data Retrieval Functions
14 6. Data Structures
15
16 1. Introduction
17 ===============
18
19 1.1 What is an Operating Performance Point (OPP)?
20 -------------------------------------------------
21
22 Complex SoCs of today consists of a multiple sub-modules working in conjunction.
23 In an operational system executing varied use cases, not all modules in the SoC
24 need to function at their highest performing frequency all the time. To
25 facilitate this, sub-modules in a SoC are grouped into domains, allowing some
26 domains to run at lower voltage and frequency while other domains run at
27 voltage/frequency pairs that are higher.
28
29 The set of discrete tuples consisting of frequency and voltage pairs that
30 the device will support per domain are called Operating Performance Points or
31 OPPs.
32
33 As an example:
34
35 Let us consider an MPU device which supports the following:
36 {300MHz at minimum voltage of 1V}, {800MHz at minimum voltage of 1.2V},
37 {1GHz at minimum voltage of 1.3V}
38
39 We can represent these as three OPPs as the following {Hz, uV} tuples:
40
41 - {300000000, 1000000}
42 - {800000000, 1200000}
43 - {1000000000, 1300000}
44
45 1.2 Operating Performance Points Library
46 ----------------------------------------
47
48 OPP library provides a set of helper functions to organize and query the OPP
49 information. The library is located in drivers/opp/ directory and the header
50 is located in include/linux/pm_opp.h. OPP library can be enabled by enabling
51 CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
52 Instrument's OMAP framework allows to optionally boot at a certain OPP without
53 needing cpufreq.
54
55 Typical usage of the OPP library is as follows::
56
57 (users) -> registers a set of default OPPs -> (library)
58 SoC framework -> modifies on required cases certain OPPs -> OPP layer
59 -> queries to search/retrieve information ->
60
61 OPP layer expects each domain to be represented by a unique device pointer. SoC
62 framework registers a set of initial OPPs per device with the OPP layer. This
63 list is expected to be an optimally small number typically around 5 per device.
64 This initial list contains a set of OPPs that the framework expects to be safely
65 enabled by default in the system.
66
67 Note on OPP Availability
68 ^^^^^^^^^^^^^^^^^^^^^^^^
69
70 As the system proceeds to operate, SoC framework may choose to make certain
71 OPPs available or not available on each device based on various external
72 factors. Example usage: Thermal management or other exceptional situations where
73 SoC framework might choose to disable a higher frequency OPP to safely continue
74 operations until that OPP could be re-enabled if possible.
75
76 OPP library facilitates this concept in its implementation. The following
77 operational functions operate only on available opps:
78 dev_pm_opp_find_freq_{ceil, floor}, dev_pm_opp_get_voltage, dev_pm_opp_get_freq,
79 dev_pm_opp_get_opp_count.
80
81 dev_pm_opp_find_freq_exact is meant to be used to find the opp pointer
82 which can then be used for dev_pm_opp_enable/disable functions to make an
83 opp available as required.
84
85 WARNING: Users of OPP library should refresh their availability count using
86 get_opp_count if dev_pm_opp_enable/disable functions are invoked for a
87 device, the exact mechanism to trigger these or the notification mechanism
88 to other dependent subsystems such as cpufreq are left to the discretion of
89 the SoC specific framework which uses the OPP library. Similar care needs
90 to be taken care to refresh the cpufreq table in cases of these operations.
91
92 2. Initial OPP List Registration
93 ================================
94 The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
95 device. It is expected that the SoC framework will register the OPP entries
96 optimally- typical numbers range to be less than 5. The list generated by
97 registering the OPPs is maintained by OPP library throughout the device
98 operation. The SoC framework can subsequently control the availability of the
99 OPPs dynamically using the dev_pm_opp_enable / disable functions.
100
101 dev_pm_opp_add
102 Add a new OPP for a specific domain represented by the device pointer.
103 The OPP is defined using the frequency and voltage. Once added, the OPP
104 is assumed to be available and control of its availability can be done
105 with the dev_pm_opp_enable/disable functions. OPP library
106 internally stores and manages this information in the dev_pm_opp struct.
107 This function may be used by SoC framework to define a optimal list
108 as per the demands of SoC usage environment.
109
110 WARNING:
111 Do not use this function in interrupt context.
112
113 Example::
114
115 soc_pm_init()
116 {
117 /* Do things */
118 r = dev_pm_opp_add(mpu_dev, 1000000, 900000);
119 if (!r) {
120 pr_err("%s: unable to register mpu opp(%d)\n", r);
121 goto no_cpufreq;
122 }
123 /* Do cpufreq things */
124 no_cpufreq:
125 /* Do remaining things */
126 }
127
128 3. OPP Search Functions
129 =======================
130 High level framework such as cpufreq operates on frequencies. To map the
131 frequency back to the corresponding OPP, OPP library provides handy functions
132 to search the OPP list that OPP library internally manages. These search
133 functions return the matching pointer representing the opp if a match is
134 found, else returns error. These errors are expected to be handled by standard
135 error checks such as IS_ERR() and appropriate actions taken by the caller.
136
137 Callers of these functions shall call dev_pm_opp_put() after they have used the
138 OPP. Otherwise the memory for the OPP will never get freed and result in
139 memleak.
140
141 dev_pm_opp_find_freq_exact
142 Search for an OPP based on an *exact* frequency and
143 availability. This function is especially useful to enable an OPP which
144 is not available by default.
145 Example: In a case when SoC framework detects a situation where a
146 higher frequency could be made available, it can use this function to
147 find the OPP prior to call the dev_pm_opp_enable to actually make
148 it available::
149
150 opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
151 dev_pm_opp_put(opp);
152 /* dont operate on the pointer.. just do a sanity check.. */
153 if (IS_ERR(opp)) {
154 pr_err("frequency not disabled!\n");
155 /* trigger appropriate actions.. */
156 } else {
157 dev_pm_opp_enable(dev,1000000000);
158 }
159
160 NOTE:
161 This is the only search function that operates on OPPs which are
162 not available.
163
164 dev_pm_opp_find_freq_floor
165 Search for an available OPP which is *at most* the
166 provided frequency. This function is useful while searching for a lesser
167 match OR operating on OPP information in the order of decreasing
168 frequency.
169 Example: To find the highest opp for a device::
170
171 freq = ULONG_MAX;
172 opp = dev_pm_opp_find_freq_floor(dev, &freq);
173 dev_pm_opp_put(opp);
174
175 dev_pm_opp_find_freq_ceil
176 Search for an available OPP which is *at least* the
177 provided frequency. This function is useful while searching for a
178 higher match OR operating on OPP information in the order of increasing
179 frequency.
180 Example 1: To find the lowest opp for a device::
181
182 freq = 0;
183 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
184 dev_pm_opp_put(opp);
185
186 Example 2: A simplified implementation of a SoC cpufreq_driver->target::
187
188 soc_cpufreq_target(..)
189 {
190 /* Do stuff like policy checks etc. */
191 /* Find the best frequency match for the req */
192 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
193 dev_pm_opp_put(opp);
194 if (!IS_ERR(opp))
195 soc_switch_to_freq_voltage(freq);
196 else
197 /* do something when we can't satisfy the req */
198 /* do other stuff */
199 }
200
201 4. OPP Availability Control Functions
202 =====================================
203 A default OPP list registered with the OPP library may not cater to all possible
204 situation. The OPP library provides a set of functions to modify the
205 availability of a OPP within the OPP list. This allows SoC frameworks to have
206 fine grained dynamic control of which sets of OPPs are operationally available.
207 These functions are intended to *temporarily* remove an OPP in conditions such
208 as thermal considerations (e.g. don't use OPPx until the temperature drops).
209
210 WARNING:
211 Do not use these functions in interrupt context.
212
213 dev_pm_opp_enable
214 Make a OPP available for operation.
215 Example: Lets say that 1GHz OPP is to be made available only if the
216 SoC temperature is lower than a certain threshold. The SoC framework
217 implementation might choose to do something as follows::
218
219 if (cur_temp < temp_low_thresh) {
220 /* Enable 1GHz if it was disabled */
221 opp = dev_pm_opp_find_freq_exact(dev, 1000000000, false);
222 dev_pm_opp_put(opp);
223 /* just error check */
224 if (!IS_ERR(opp))
225 ret = dev_pm_opp_enable(dev, 1000000000);
226 else
227 goto try_something_else;
228 }
229
230 dev_pm_opp_disable
231 Make an OPP to be not available for operation
232 Example: Lets say that 1GHz OPP is to be disabled if the temperature
233 exceeds a threshold value. The SoC framework implementation might
234 choose to do something as follows::
235
236 if (cur_temp > temp_high_thresh) {
237 /* Disable 1GHz if it was enabled */
238 opp = dev_pm_opp_find_freq_exact(dev, 1000000000, true);
239 dev_pm_opp_put(opp);
240 /* just error check */
241 if (!IS_ERR(opp))
242 ret = dev_pm_opp_disable(dev, 1000000000);
243 else
244 goto try_something_else;
245 }
246
247 5. OPP Data Retrieval Functions
248 ===============================
249 Since OPP library abstracts away the OPP information, a set of functions to pull
250 information from the dev_pm_opp structure is necessary. Once an OPP pointer is
251 retrieved using the search functions, the following functions can be used by SoC
252 framework to retrieve the information represented inside the OPP layer.
253
254 dev_pm_opp_get_voltage
255 Retrieve the voltage represented by the opp pointer.
256 Example: At a cpufreq transition to a different frequency, SoC
257 framework requires to set the voltage represented by the OPP using
258 the regulator framework to the Power Management chip providing the
259 voltage::
260
261 soc_switch_to_freq_voltage(freq)
262 {
263 /* do things */
264 opp = dev_pm_opp_find_freq_ceil(dev, &freq);
265 v = dev_pm_opp_get_voltage(opp);
266 dev_pm_opp_put(opp);
267 if (v)
268 regulator_set_voltage(.., v);
269 /* do other things */
270 }
271
272 dev_pm_opp_get_freq
273 Retrieve the freq represented by the opp pointer.
274 Example: Lets say the SoC framework uses a couple of helper functions
275 we could pass opp pointers instead of doing additional parameters to
276 handle quiet a bit of data parameters::
277
278 soc_cpufreq_target(..)
279 {
280 /* do things.. */
281 max_freq = ULONG_MAX;
282 max_opp = dev_pm_opp_find_freq_floor(dev,&max_freq);
283 requested_opp = dev_pm_opp_find_freq_ceil(dev,&freq);
284 if (!IS_ERR(max_opp) && !IS_ERR(requested_opp))
285 r = soc_test_validity(max_opp, requested_opp);
286 dev_pm_opp_put(max_opp);
287 dev_pm_opp_put(requested_opp);
288 /* do other things */
289 }
290 soc_test_validity(..)
291 {
292 if(dev_pm_opp_get_voltage(max_opp) < dev_pm_opp_get_voltage(requested_opp))
293 return -EINVAL;
294 if(dev_pm_opp_get_freq(max_opp) < dev_pm_opp_get_freq(requested_opp))
295 return -EINVAL;
296 /* do things.. */
297 }
298
299 dev_pm_opp_get_opp_count
300 Retrieve the number of available opps for a device
301 Example: Lets say a co-processor in the SoC needs to know the available
302 frequencies in a table, the main processor can notify as following::
303
304 soc_notify_coproc_available_frequencies()
305 {
306 /* Do things */
307 num_available = dev_pm_opp_get_opp_count(dev);
308 speeds = kcalloc(num_available, sizeof(u32), GFP_KERNEL);
309 /* populate the table in increasing order */
310 freq = 0;
311 while (!IS_ERR(opp = dev_pm_opp_find_freq_ceil(dev, &freq))) {
312 speeds[i] = freq;
313 freq++;
314 i++;
315 dev_pm_opp_put(opp);
316 }
317
318 soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available);
319 /* Do other things */
320 }
321
322 6. Data Structures
323 ==================
324 Typically an SoC contains multiple voltage domains which are variable. Each
325 domain is represented by a device pointer. The relationship to OPP can be
326 represented as follows::
327
328 SoC
329 |- device 1
330 | |- opp 1 (availability, freq, voltage)
331 | |- opp 2 ..
332 ... ...
333 | `- opp n ..
334 |- device 2
335 ...
336 `- device m
337
338 OPP library maintains a internal list that the SoC framework populates and
339 accessed by various functions as described above. However, the structures
340 representing the actual OPPs and domains are internal to the OPP library itself
341 to allow for suitable abstraction reusable across systems.
342
343 struct dev_pm_opp
344 The internal data structure of OPP library which is used to
345 represent an OPP. In addition to the freq, voltage, availability
346 information, it also contains internal book keeping information required
347 for the OPP library to operate on. Pointer to this structure is
348 provided back to the users such as SoC framework to be used as a
349 identifier for OPP in the interactions with OPP layer.
350
351 WARNING:
352 The struct dev_pm_opp pointer should not be parsed or modified by the
353 users. The defaults of for an instance is populated by
354 dev_pm_opp_add, but the availability of the OPP can be modified
355 by dev_pm_opp_enable/disable functions.
356
357 struct device
358 This is used to identify a domain to the OPP layer. The
359 nature of the device and its implementation is left to the user of
360 OPP library such as the SoC framework.
361
362 Overall, in a simplistic view, the data structure operations is represented as
363 following::
364
365 Initialization / modification:
366 +-----+ /- dev_pm_opp_enable
367 dev_pm_opp_add --> | opp | <-------
368 | +-----+ \- dev_pm_opp_disable
369 \-------> domain_info(device)
370
371 Search functions:
372 /-- dev_pm_opp_find_freq_ceil ---\ +-----+
373 domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
374 \-- dev_pm_opp_find_freq_floor ---/ +-----+
375
376 Retrieval functions:
377 +-----+ /- dev_pm_opp_get_voltage
378 | opp | <---
379 +-----+ \- dev_pm_opp_get_freq
380
381 domain_info <- dev_pm_opp_get_opp_count
382

3. 한국어 전문 번역

영어 원문의 문단 순서와 의미를 유지한 전체 번역입니다. 코드, 함수명, symbol과 URL은 원문 표기를 유지합니다.

OPP의 정의와 library

1-54

현대의 복잡한 SoC는 여러 sub-module이 함께 동작합니다. 다양한 use case를 실행할 때 모든 module이 늘 최고 frequency로 동작할 필요는 없습니다. 그래서 sub-module을 domain으로 묶어 어떤 domain은 낮은 voltage·frequency에서, 다른 domain은 더 높은 voltage·frequency pair에서 실행할 수 있게 합니다.

Domain별로 device가 지원하는 이산적인 frequency·voltage tuple 집합을 Operating Performance Point, 즉 OPP라고 합니다.

예를 들어 MPU가 최소 1V에서 300MHz, 최소 1.2V에서 800MHz, 최소 1.3V에서 1GHz를 지원한다면 세 OPP를 `{Hz, uV}` tuple로 표현할 수 있습니다.

MPU OPP 예
OPPFrequency (Hz)Voltage (uV)
13000000001000000
28000000001200000
310000000001300000

각 frequency를 안정적으로 동작시키는 최소 voltage를 tuple로 기록합니다.

OPP library는 OPP 정보를 구성하고 조회하는 helper function 집합입니다. 구현은 `drivers/opp/`, header는 `include/linux/pm_opp.h`에 있으며 power management menuconfig의 `CONFIG_PM_OPP`로 enable합니다.

Texas Instruments OMAP framework 같은 일부 SoC는 cpufreq 없이도 특정 OPP로 boot할 수 있습니다.

Domain별 성능 선택
SoCdomain Alow voltage / frequency
SoCdomain Bhigh voltage / frequency
frequency + minimum voltagediscrete OPP tuple

Workload에 필요한 domain만 높은 OPP로 올려 성능과 소비 전력을 조절합니다.

==========================================
Operating Performance Points (OPP) Library
==========================================

(C) 2009-2010 Nishanth Menon <[email protected]>, 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.
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.

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.

As an example:

Let us consider an MPU device which supports the following:
{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:

- {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 can be enabled by enabling
CONFIG_PM_OPP from power management menuconfig menu. Certain SoCs such as Texas
Instrument's OMAP framework allows to optionally boot at a certain OPP without
needing cpufreq.

일반 사용 흐름과 availability

55-91

일반적인 사용 흐름에서 SoC framework는 기본 OPP 집합을 library에 등록하고, 필요한 상황에 일부 OPP를 수정하며, OPP layer에 정보를 검색·조회합니다.

OPP library 사용 흐름
SoC frameworkregister default OPPsOPP layer
SoC frameworkmodify selected OPPsOPP layer
SoC frameworksearch / retrieveOPP layer

SoC framework가 domain별 기본 목록을 등록하고 runtime 정책에 따라 availability를 바꿉니다.

OPP layer는 각 domain을 고유한 device pointer 하나로 표현한다고 가정합니다. SoC framework는 device마다 초기 OPP 집합을 등록하며, 일반적으로 device당 약 5개인 최적으로 작은 목록을 권장합니다. 초기 목록에는 system에서 기본적으로 안전하게 enable할 수 있는 OPP를 넣습니다.

동작 중에는 thermal management 같은 외부 조건에 따라 특정 OPP를 available 또는 unavailable로 바꿀 수 있습니다. 예를 들어 온도가 내려갈 때까지 높은 frequency OPP를 disable하여 안전하게 계속 동작하게 할 수 있습니다.

`dev_pm_opp_find_freq_ceil`, `dev_pm_opp_find_freq_floor`, `dev_pm_opp_get_voltage`, `dev_pm_opp_get_freq`, `dev_pm_opp_get_opp_count`는 available OPP만 대상으로 동작합니다.

`dev_pm_opp_find_freq_exact`는 unavailable OPP도 찾을 수 있는 유일한 search function이며, 얻은 pointer를 `dev_pm_opp_enable()` 또는 `dev_pm_opp_disable()`에 대응하는 판단에 사용할 수 있습니다.

OPP availability를 바꾼 뒤 사용자는 `get_opp_count`로 available count를 갱신해야 합니다. cpufreq 같은 의존 subsystem에 알리는 방식은 SoC-specific framework가 결정하며, 이 동작 뒤 cpufreq table도 새로 고쳐야 합니다.

Availability 영향
API 종류Unavailable OPP 검색주의
ceil / floor / get_* / count불가현재 operational set만 반영
find_freq_exact가능Availability 인자로 상태 지정
enable / disable 이후해당 없음Count와 cpufreq table 갱신 필요

일반 query는 available OPP만 보지만 exact search는 원하는 availability를 명시합니다.

Typical usage of the OPP library is as follows::

 (users)        -> registers a set of default OPPs                -> (library)
 SoC framework        -> modifies on required cases certain OPPs        -> OPP layer
                -> queries to search/retrieve information        ->

OPP layer expects each domain to be represented by a unique device pointer. SoC
framework registers a set of initial OPPs per device with the OPP layer. This
list is expected to be an optimally small number typically around 5 per device.
This initial list contains a set of OPPs that the framework expects to be safely
enabled by default in the system.

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. 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.

OPP library facilitates this concept in its implementation. The following
operational functions operate only on available opps:
dev_pm_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.

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. Similar care needs
to be taken care to refresh the cpufreq table in cases of these operations.

초기 OPP 목록 등록

92-127

SoC 구현은 device별로 `dev_pm_opp_add()`를 반복 호출해 OPP를 등록합니다. 일반적인 OPP 수는 5개 미만이 되도록 최적화합니다. 생성된 목록은 device가 동작하는 동안 OPP library가 유지하고, 이후 `dev_pm_opp_enable()`과 `dev_pm_opp_disable()`로 availability를 동적으로 제어할 수 있습니다.

`dev_pm_opp_add`는 device pointer가 나타내는 domain에 frequency와 voltage로 정의한 새 OPP를 추가합니다. 추가 직후에는 available로 간주하며 내부 `struct dev_pm_opp`에 저장·관리됩니다.

SoC framework는 실제 사용 환경의 요구에 맞는 최적 목록을 정의할 수 있습니다. 이 함수는 interrupt context에서 사용하면 안 됩니다.

예제 `soc_pm_init()`은 `dev_pm_opp_add(mpu_dev, 1000000, 900000)`을 호출하고 결과에 따라 cpufreq setup 또는 나머지 초기화로 진행합니다. 원문 code와 control flow는 아래 source block에 그대로 보존합니다.

dev_pm_opp_add()
입력의미
device pointer고유 performance domain
frequencyOPP의 동작 frequency
voltage해당 frequency의 voltage
초기 상태available

초기 등록 시점에 domain, frequency, voltage를 연결합니다.

초기 등록
SoC initdev_pm_opp_add() repeatedstruct dev_pm_opp listenable / disable at runtime

작은 기본 목록을 만들고 runtime 정책이 availability만 바꿉니다.

2. Initial OPP List Registration
================================
The SoC implementation calls dev_pm_opp_add function iteratively to add OPPs per
device. It is expected that the SoC framework will register the OPP entries
optimally- typical numbers range to be less than 5. The list generated by
registering the OPPs is maintained by OPP library throughout the device
operation. The SoC framework can subsequently control the availability of the
OPPs dynamically using the dev_pm_opp_enable / disable functions.

dev_pm_opp_add
        Add a new OPP for a specific domain represented by the device pointer.
        The OPP is defined using the frequency and voltage. 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 dev_pm_opp struct.
        This function may be used by SoC framework to define a optimal list
        as per the demands of SoC usage environment.

        WARNING:
                Do not use this function in interrupt context.

        Example::

         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", r);
                        goto no_cpufreq;
                }
                /* Do cpufreq things */
         no_cpufreq:
                /* Do remaining things */
         }

Search 공통 규칙과 exact 검색

128-163

Cpufreq 같은 high-level framework는 frequency를 기준으로 동작합니다. OPP library는 frequency를 내부 OPP 목록의 항목으로 다시 매핑하는 search function을 제공합니다.

일치하는 OPP가 있으면 이를 나타내는 pointer를 반환하고, 없으면 error pointer를 반환합니다. Caller는 `IS_ERR()` 같은 표준 error check로 처리해야 합니다.

Search function으로 얻은 OPP를 다 쓴 뒤에는 반드시 `dev_pm_opp_put()`을 호출해야 합니다. 그렇지 않으면 OPP memory가 영원히 해제되지 않아 leak가 발생합니다.

`dev_pm_opp_find_freq_exact()`는 exact frequency와 요청한 availability가 일치하는 OPP를 찾습니다. 기본적으로 unavailable인 OPP를 다시 enable하려는 상황에 특히 유용합니다.

예제는 1GHz이면서 unavailable인 OPP를 찾고 error 여부를 확인한 뒤 `dev_pm_opp_enable(dev, 1000000000)`을 호출합니다. 이 함수만 unavailable OPP를 검색할 수 있습니다.

Exact search와 enable
dev_pm_opp_find_freq_exact(dev, 1GHz, false)IS_ERR() checkdev_pm_opp_enable(dev, 1GHz)refresh dependent tables

현재 비활성인 정확한 OPP가 존재하는지 확인한 뒤 availability를 전환합니다.

3. OPP Search Functions
=======================
High level framework such as cpufreq operates on frequencies. To map the
frequency back to the corresponding OPP, OPP library provides handy functions
to search the OPP list that OPP library internally manages. These search
functions return the matching pointer representing the opp if a match is
found, else returns error. These errors are expected to be handled by standard
error checks such as IS_ERR() and appropriate actions taken by the caller.

Callers of these functions shall call dev_pm_opp_put() after they have used the
OPP. Otherwise the memory for the OPP will never get freed and result in
memleak.

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

         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.

Floor·ceil 검색

164-200

`dev_pm_opp_find_freq_floor()`는 제공한 frequency 이하에서 가장 높은 available OPP를 찾습니다. 낮은 쪽 일치 항목을 찾거나 frequency 내림차순으로 OPP를 순회할 때 사용합니다.

Device의 최고 OPP를 찾으려면 `freq = ULONG_MAX`로 시작해 floor search를 호출합니다.

`dev_pm_opp_find_freq_ceil()`은 제공한 frequency 이상에서 가장 낮은 available OPP를 찾습니다. 높은 쪽 일치 항목을 찾거나 frequency 오름차순으로 순회할 때 사용합니다.

Device의 최저 OPP는 `freq = 0`에서 ceil search로 찾습니다. 단순화한 `cpufreq_driver->target` 예제는 요청 frequency를 ceil search에 넘기고 성공하면 `soc_switch_to_freq_voltage(freq)`로 frequency와 voltage를 전환합니다.

Frequency search
함수조건대표 초기값
find_freq_floorOPP frequency <= request 중 최댓값ULONG_MAX로 최고 OPP 검색
find_freq_ceilOPP frequency >= request 중 최솟값0으로 최저 OPP 검색
find_freq_exactFrequency와 availability 정확히 일치Unavailable OPP 관리

Floor와 ceil은 available OPP 집합에서 경계값을 선택합니다.

cpufreq target 선택
requested freqdev_pm_opp_find_freq_ceil()matching available OPPsoc_switch_to_freq_voltage(freq)

요청을 만족하는 최소 상위 OPP를 선택해 clock·voltage transition에 사용합니다.

dev_pm_opp_find_freq_floor
        Search for an available OPP which is *at most* the
        provided frequency. This function is useful while searching for a lesser
        match OR operating on OPP information in the order of decreasing
        frequency.
        Example: To find the highest opp for a device::

         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. This function is useful while searching for a
        higher match OR operating on OPP information in the order of increasing
        frequency.
        Example 1: To find the lowest opp for a device::

         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_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 */
         }

OPP availability 제어

201-246

기본 OPP 목록만으로 모든 상황을 처리할 수는 없습니다. OPP library는 목록 안의 OPP availability를 바꾸는 함수로 SoC framework가 operational OPP 집합을 세밀하게 동적 제어하게 합니다.

이 함수는 온도가 내려갈 때까지 특정 OPP를 사용하지 않는 경우처럼 OPP를 일시적으로 제거하려는 용도입니다. Interrupt context에서 사용하면 안 됩니다.

`dev_pm_opp_enable()`은 OPP를 operational하게 만듭니다. 예제는 현재 온도가 낮은 threshold 아래로 내려가면 1GHz unavailable OPP를 exact search로 찾고, 존재할 때 enable합니다.

`dev_pm_opp_disable()`은 OPP를 operational set에서 제외합니다. 예제는 온도가 높은 threshold를 넘으면 현재 available인 1GHz OPP를 exact search로 찾고 disable합니다.

Thermal hysteresis와 OPP
cur_temp < temp_low_threshfind exact 1GHz unavailabledev_pm_opp_enable()
cur_temp > temp_high_threshfind exact 1GHz availabledev_pm_opp_disable()

낮은 threshold에서 고성능 OPP를 복구하고 높은 threshold에서 다시 제한합니다.

Availability API
API결과Search availability
dev_pm_opp_enableUnavailable → availablefalse
dev_pm_opp_disableAvailable → unavailabletrue

두 함수 모두 device와 exact frequency로 OPP 상태를 바꿉니다.

4. OPP Availability Control Functions
=====================================
A default OPP list registered with the OPP library may not cater to all possible
situation. The OPP library provides a set of functions to modify the
availability of a OPP within the OPP list. This allows SoC frameworks to have
fine grained dynamic control of which sets of OPPs are operationally available.
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).

WARNING:
        Do not use these functions in interrupt context.

dev_pm_opp_enable
        Make a OPP available for operation.
        Example: Lets say that 1GHz OPP is to be made available only if the
        SoC temperature is lower than a certain threshold. The SoC framework
        implementation might choose to do something as follows::

         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
        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::

         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;
         }

Voltage·frequency 조회

247-298

OPP library가 내부 정보를 abstraction하므로 `struct dev_pm_opp` pointer에서 값을 읽는 accessor가 필요합니다. Search로 OPP pointer를 얻은 뒤 SoC framework는 다음 함수를 사용합니다.

`dev_pm_opp_get_voltage()`는 OPP의 voltage를 반환합니다. Cpufreq transition 예제는 ceil search로 OPP를 찾고 voltage를 얻은 뒤 regulator framework의 `regulator_set_voltage(.., v)`로 Power Management chip의 전압을 설정합니다.

`dev_pm_opp_get_freq()`는 OPP의 frequency를 반환합니다. Helper 사이에 여러 개별 parameter를 넘기는 대신 OPP pointer를 전달하고 필요한 frequency·voltage를 accessor로 읽을 수 있습니다.

예제 `soc_cpufreq_target()`은 최고 OPP와 요청 OPP를 찾아 `soc_test_validity()`에 넘깁니다. Validation 함수는 요청 OPP의 voltage나 frequency가 최고 OPP보다 크면 `-EINVAL`을 반환합니다. 각 pointer는 사용 후 `dev_pm_opp_put()`으로 놓습니다.

OPP accessor
API반환값대표 사용처
dev_pm_opp_get_voltageuV voltageregulator_set_voltage()
dev_pm_opp_get_freqHz frequencyClock/cpufreq validation
dev_pm_opp_putReference 해제모든 search 결과 사용 후

Opaque pointer를 직접 해석하지 않고 공식 accessor로 값을 읽습니다.

Frequency·voltage transition
dev_pm_opp_find_freq_ceil()dev_pm_opp_get_voltage()regulator_set_voltage()switch frequencydev_pm_opp_put()

선택한 OPP의 voltage를 regulator에 적용하고 대응 frequency로 전환합니다.

5. OPP Data Retrieval Functions
===============================
Since OPP library abstracts away the OPP information, a set of functions to pull
information from the dev_pm_opp structure is necessary. 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.

dev_pm_opp_get_voltage
        Retrieve the voltage represented by the 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::

         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.
        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_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.. */
         }

Available OPP 수와 순회

299-321

`dev_pm_opp_get_opp_count()`는 device에서 현재 available인 OPP 수를 반환합니다.

예제에서는 SoC co-processor에 available frequency table을 알려 주기 위해 count만큼 `u32` 배열을 할당합니다. `freq = 0`에서 시작해 `dev_pm_opp_find_freq_ceil()`이 error를 반환할 때까지 오름차순으로 OPP를 찾고 각 frequency를 배열에 저장합니다.

각 iteration에서 `freq++`로 다음 OPP보다 큰 검색 시작점을 만들고, 얻은 OPP는 `dev_pm_opp_put()`으로 놓습니다. 완성한 table은 `soc_notify_coproc(AVAILABLE_FREQs, speeds, num_available)`로 전달합니다.

Available frequency table 생성
dev_pm_opp_get_opp_count()kcalloc()freq = 0repeat find_freq_ceil()append freq + dev_pm_opp_put()notify co-processor

Count로 memory를 확보한 뒤 ceil search를 반복해 오름차순 table을 만듭니다.

dev_pm_opp_get_opp_count
        Retrieve the number of available opps for a device
        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_notify_coproc_available_frequencies()
         {
                /* Do things */
                num_available = dev_pm_opp_get_opp_count(dev);
                speeds = kcalloc(num_available, sizeof(u32), 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 */
         }

Domain과 내부 구조체

322-361

일반적인 SoC에는 voltage를 바꿀 수 있는 domain이 여러 개 있고 각 domain을 device pointer로 나타냅니다. 각 device 아래에는 availability, frequency, voltage를 가진 OPP가 여러 개 있습니다.

SoC·device·OPP 계층
SoCdevice 1OPP 1: availability / freq / voltage
SoCdevice 1OPP 2 ... OPP n
SoCdevice 2 ... device meach domain's OPP list

원문의 tree diagram을 domain 관계로 다시 구성했습니다.

OPP library는 SoC framework가 채운 내부 목록을 관리하고 앞서 설명한 함수들이 접근하게 합니다. 실제 OPP와 domain을 나타내는 구조체는 여러 system에서 재사용 가능한 abstraction을 위해 library 내부에 숨깁니다.

`struct dev_pm_opp`는 하나의 OPP를 나타내는 내부 구조체입니다. Frequency, voltage, availability뿐 아니라 library 동작에 필요한 bookkeeping 정보를 포함합니다. SoC framework 같은 사용자는 이 pointer를 OPP layer와 상호 작용할 identifier로 받습니다.

사용자는 `struct dev_pm_opp` pointer를 직접 parse하거나 수정하면 안 됩니다. 기본 항목은 `dev_pm_opp_add()`가 채우고 availability는 enable/disable API로만 바꿉니다.

`struct device`는 OPP layer에서 domain을 식별합니다. 실제 device의 성격과 구현은 SoC framework 같은 library 사용자에게 맡깁니다.

주요 object
Object역할사용자 제약
struct deviceDomain identifierSoC가 구현 의미 결정
struct dev_pm_oppOPP identifier + 내부 상태직접 parse·수정 금지
OPP internal listDomain별 OPP lifetime 관리API로만 접근

Public interaction은 opaque OPP pointer와 device domain identifier를 사용합니다.

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 1
   |        |- opp 1 (availability, freq, voltage)
   |        |- opp 2 ..
   ...        ...
   |        `- opp n ..
   |- device 2
   ...
   `- device m

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.

struct dev_pm_opp
        The internal data structure of OPP library which is used to
        represent an OPP. In addition to the freq, voltage, availability
        information, it also contains internal book keeping information required
        for the OPP library to operate on.  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.

        WARNING:
          The struct dev_pm_opp pointer should not be parsed or modified by the
          users. 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.

struct device
        This is used to identify a domain to the OPP layer. The
        nature of the device and its implementation is left to the user of
        OPP library such as the SoC framework.

등록·검색·조회 관계도

362-381

원문의 마지막 ASCII 그림은 initialization/modification, search, retrieval 세 종류의 API가 `domain_info(device)`와 `opp` object를 중심으로 연결되는 방식을 보여 줍니다.

초기화와 수정
dev_pm_opp_adddomain_info(device)opp
dev_pm_opp_enableopp availability
dev_pm_opp_disableopp availability

OPP를 domain에 추가한 뒤 enable·disable로 operational set을 바꿉니다.

검색
domain_info(device)dev_pm_opp_find_freq_ceilopp
domain_info(device)dev_pm_opp_find_freq_exactopp
domain_info(device)dev_pm_opp_find_freq_flooropp

Device domain과 frequency 조건으로 opaque OPP pointer를 얻습니다.

조회
oppdev_pm_opp_get_voltage
oppdev_pm_opp_get_freq
domain_infodev_pm_opp_get_opp_count

OPP pointer에서는 voltage·frequency를, domain에서는 available count를 읽습니다.

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

  Initialization / modification:
              +-----+        /- dev_pm_opp_enable
  dev_pm_opp_add --> | opp | <-------
    |         +-----+        \- dev_pm_opp_disable
    \-------> domain_info(device)

  Search functions:
               /-- dev_pm_opp_find_freq_ceil  ---\   +-----+
  domain_info<---- dev_pm_opp_find_freq_exact -----> | opp |
               \-- dev_pm_opp_find_freq_floor ---/   +-----+

  Retrieval functions:
  +-----+     /- dev_pm_opp_get_voltage
  | opp | <---
  +-----+     \- dev_pm_opp_get_freq

  domain_info <- dev_pm_opp_get_opp_count