1/*
2 * Copyright 2021 Advanced Micro Devices, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
21 */
22
23#include "amdgpu.h"
24#include "amdgpu_i2c.h"
25#include "amdgpu_atombios.h"
26#include "atom.h"
27#include "amd_pcie.h"
28#include "legacy_dpm.h"
29#include "amdgpu_dpm_internal.h"
30#include "amdgpu_display.h"
31
32#define amdgpu_dpm_pre_set_power_state(adev) \
33 ((adev)->powerplay.pp_funcs->pre_set_power_state((adev)->powerplay.pp_handle))
34
35#define amdgpu_dpm_post_set_power_state(adev) \
36 ((adev)->powerplay.pp_funcs->post_set_power_state((adev)->powerplay.pp_handle))
37
38#define amdgpu_dpm_display_configuration_changed(adev) \
39 ((adev)->powerplay.pp_funcs->display_configuration_changed((adev)->powerplay.pp_handle))
40
41#define amdgpu_dpm_print_power_state(adev, ps) \
42 ((adev)->powerplay.pp_funcs->print_power_state((adev)->powerplay.pp_handle, (ps)))
43
44#define amdgpu_dpm_vblank_too_short(adev) \
45 ((adev)->powerplay.pp_funcs->vblank_too_short((adev)->powerplay.pp_handle))
46
47#define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \
48 ((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal)))
49
50void amdgpu_dpm_print_class_info(u32 class, u32 class2)
51{
52 const char *s;
53
54 switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
55 case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
56 default:
57 s = "none";
58 break;
59 case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
60 s = "battery";
61 break;
62 case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
63 s = "balanced";
64 break;
65 case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
66 s = "performance";
67 break;
68 }
69 printk("\tui class: %s\n", s);
70 printk("\tinternal class:");
71 if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
72 (class2 == 0))
73 pr_cont(" none");
74 else {
75 if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
76 pr_cont(" boot");
77 if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
78 pr_cont(" thermal");
79 if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
80 pr_cont(" limited_pwr");
81 if (class & ATOM_PPLIB_CLASSIFICATION_REST)
82 pr_cont(" rest");
83 if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
84 pr_cont(" forced");
85 if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
86 pr_cont(" 3d_perf");
87 if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
88 pr_cont(" ovrdrv");
89 if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
90 pr_cont(" uvd");
91 if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
92 pr_cont(" 3d_low");
93 if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
94 pr_cont(" acpi");
95 if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
96 pr_cont(" uvd_hd2");
97 if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
98 pr_cont(" uvd_hd");
99 if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
100 pr_cont(" uvd_sd");
101 if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
102 pr_cont(" limited_pwr2");
103 if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
104 pr_cont(" ulv");
105 if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
106 pr_cont(" uvd_mvc");
107 }
108 pr_cont("\n");
109}
110
111void amdgpu_dpm_print_cap_info(u32 caps)
112{
113 printk("\tcaps:");
114 if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
115 pr_cont(" single_disp");
116 if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
117 pr_cont(" video");
118 if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
119 pr_cont(" no_dc");
120 pr_cont("\n");
121}
122
123void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
124 struct amdgpu_ps *rps)
125{
126 printk("\tstatus:");
127 if (rps == adev->pm.dpm.current_ps)
128 pr_cont(" c");
129 if (rps == adev->pm.dpm.requested_ps)
130 pr_cont(" r");
131 if (rps == adev->pm.dpm.boot_ps)
132 pr_cont(" b");
133 pr_cont("\n");
134}
135
136void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
137{
138 int i;
139
140 if (adev->powerplay.pp_funcs->print_power_state == NULL)
141 return;
142
143 for (i = 0; i < adev->pm.dpm.num_ps; i++)
144 amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
145
146}
147
148union power_info {
149 struct _ATOM_POWERPLAY_INFO info;
150 struct _ATOM_POWERPLAY_INFO_V2 info_2;
151 struct _ATOM_POWERPLAY_INFO_V3 info_3;
152 struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
153 struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
154 struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
155 struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
156 struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
157};
158
159int amdgpu_get_platform_caps(struct amdgpu_device *adev)
160{
161 struct amdgpu_mode_info *mode_info = &adev->mode_info;
162 union power_info *power_info;
163 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
164 u16 data_offset;
165 u8 frev, crev;
166
167 if (!amdgpu_atom_parse_data_header(ctx: mode_info->atom_context, index, NULL,
168 frev: &frev, crev: &crev, data_start: &data_offset))
169 return -EINVAL;
170 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
171
172 adev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
173 adev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
174 adev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
175
176 return 0;
177}
178
179union fan_info {
180 struct _ATOM_PPLIB_FANTABLE fan;
181 struct _ATOM_PPLIB_FANTABLE2 fan2;
182 struct _ATOM_PPLIB_FANTABLE3 fan3;
183};
184
185static int amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table *amdgpu_table,
186 ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
187{
188 u32 size = atom_table->ucNumEntries *
189 sizeof(struct amdgpu_clock_voltage_dependency_entry);
190 int i;
191 ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry;
192
193 amdgpu_table->entries = kzalloc(size, GFP_KERNEL);
194 if (!amdgpu_table->entries)
195 return -ENOMEM;
196
197 entry = &atom_table->entries[0];
198 for (i = 0; i < atom_table->ucNumEntries; i++) {
199 amdgpu_table->entries[i].clk = le16_to_cpu(entry->usClockLow) |
200 (entry->ucClockHigh << 16);
201 amdgpu_table->entries[i].v = le16_to_cpu(entry->usVoltage);
202 entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *)
203 ((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record));
204 }
205 amdgpu_table->count = atom_table->ucNumEntries;
206
207 return 0;
208}
209
210/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
211#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
212#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
213#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
214#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
215#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
216#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
217#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
218#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
219
220int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
221{
222 struct amdgpu_mode_info *mode_info = &adev->mode_info;
223 union power_info *power_info;
224 union fan_info *fan_info;
225 ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
226 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
227 u16 data_offset;
228 u8 frev, crev;
229 int ret, i;
230
231 if (!amdgpu_atom_parse_data_header(ctx: mode_info->atom_context, index, NULL,
232 frev: &frev, crev: &crev, data_start: &data_offset))
233 return -EINVAL;
234 power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
235
236 /* fan table */
237 if (le16_to_cpu(power_info->pplib.usTableSize) >=
238 sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
239 if (power_info->pplib3.usFanTableOffset) {
240 fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset +
241 le16_to_cpu(power_info->pplib3.usFanTableOffset));
242 adev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
243 adev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
244 adev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
245 adev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
246 adev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
247 adev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
248 adev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
249 if (fan_info->fan.ucFanTableFormat >= 2)
250 adev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
251 else
252 adev->pm.dpm.fan.t_max = 10900;
253 adev->pm.dpm.fan.cycle_delay = 100000;
254 if (fan_info->fan.ucFanTableFormat >= 3) {
255 adev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
256 adev->pm.dpm.fan.default_max_fan_pwm =
257 le16_to_cpu(fan_info->fan3.usFanPWMMax);
258 adev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
259 adev->pm.dpm.fan.fan_output_sensitivity =
260 le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
261 }
262 adev->pm.dpm.fan.ucode_fan_control = true;
263 }
264 }
265
266 /* clock dependancy tables, shedding tables */
267 if (le16_to_cpu(power_info->pplib.usTableSize) >=
268 sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) {
269 if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
270 dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
271 (mode_info->atom_context->bios + data_offset +
272 le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
273 ret = amdgpu_parse_clk_voltage_dep_table(amdgpu_table: &adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
274 atom_table: dep_table);
275 if (ret)
276 return ret;
277 }
278 if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
279 dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
280 (mode_info->atom_context->bios + data_offset +
281 le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
282 ret = amdgpu_parse_clk_voltage_dep_table(amdgpu_table: &adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
283 atom_table: dep_table);
284 if (ret)
285 return ret;
286 }
287 if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
288 dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
289 (mode_info->atom_context->bios + data_offset +
290 le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
291 ret = amdgpu_parse_clk_voltage_dep_table(amdgpu_table: &adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
292 atom_table: dep_table);
293 if (ret)
294 return ret;
295 }
296 if (power_info->pplib4.usMvddDependencyOnMCLKOffset) {
297 dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
298 (mode_info->atom_context->bios + data_offset +
299 le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset));
300 ret = amdgpu_parse_clk_voltage_dep_table(amdgpu_table: &adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
301 atom_table: dep_table);
302 if (ret)
303 return ret;
304 }
305 if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
306 ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
307 (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
308 (mode_info->atom_context->bios + data_offset +
309 le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
310 if (clk_v->ucNumEntries) {
311 adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
312 le16_to_cpu(clk_v->entries[0].usSclkLow) |
313 (clk_v->entries[0].ucSclkHigh << 16);
314 adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
315 le16_to_cpu(clk_v->entries[0].usMclkLow) |
316 (clk_v->entries[0].ucMclkHigh << 16);
317 adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
318 le16_to_cpu(clk_v->entries[0].usVddc);
319 adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
320 le16_to_cpu(clk_v->entries[0].usVddci);
321 }
322 }
323 if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) {
324 ATOM_PPLIB_PhaseSheddingLimits_Table *psl =
325 (ATOM_PPLIB_PhaseSheddingLimits_Table *)
326 (mode_info->atom_context->bios + data_offset +
327 le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset));
328 ATOM_PPLIB_PhaseSheddingLimits_Record *entry;
329
330 adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
331 kcalloc(n: psl->ucNumEntries,
332 size: sizeof(struct amdgpu_phase_shedding_limits_entry),
333 GFP_KERNEL);
334 if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
335 return -ENOMEM;
336
337 entry = &psl->entries[0];
338 for (i = 0; i < psl->ucNumEntries; i++) {
339 adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk =
340 le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16);
341 adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk =
342 le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16);
343 adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage =
344 le16_to_cpu(entry->usVoltage);
345 entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *)
346 ((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record));
347 }
348 adev->pm.dpm.dyn_state.phase_shedding_limits_table.count =
349 psl->ucNumEntries;
350 }
351 }
352
353 /* cac data */
354 if (le16_to_cpu(power_info->pplib.usTableSize) >=
355 sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) {
356 adev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
357 adev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
358 adev->pm.dpm.near_tdp_limit_adjusted = adev->pm.dpm.near_tdp_limit;
359 adev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
360 if (adev->pm.dpm.tdp_od_limit)
361 adev->pm.dpm.power_control = true;
362 else
363 adev->pm.dpm.power_control = false;
364 adev->pm.dpm.tdp_adjustment = 0;
365 adev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
366 adev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
367 adev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope);
368 if (power_info->pplib5.usCACLeakageTableOffset) {
369 ATOM_PPLIB_CAC_Leakage_Table *cac_table =
370 (ATOM_PPLIB_CAC_Leakage_Table *)
371 (mode_info->atom_context->bios + data_offset +
372 le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
373 ATOM_PPLIB_CAC_Leakage_Record *entry;
374 u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table);
375 adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
376 if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries)
377 return -ENOMEM;
378 entry = &cac_table->entries[0];
379 for (i = 0; i < cac_table->ucNumEntries; i++) {
380 if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
381 adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 =
382 le16_to_cpu(entry->usVddc1);
383 adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 =
384 le16_to_cpu(entry->usVddc2);
385 adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 =
386 le16_to_cpu(entry->usVddc3);
387 } else {
388 adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
389 le16_to_cpu(entry->usVddc);
390 adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
391 le32_to_cpu(entry->ulLeakageValue);
392 }
393 entry = (ATOM_PPLIB_CAC_Leakage_Record *)
394 ((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record));
395 }
396 adev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
397 }
398 }
399
400 /* ext tables */
401 if (le16_to_cpu(power_info->pplib.usTableSize) >=
402 sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
403 ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *)
404 (mode_info->atom_context->bios + data_offset +
405 le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset));
406 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) &&
407 ext_hdr->usVCETableOffset) {
408 VCEClockInfoArray *array = (VCEClockInfoArray *)
409 (mode_info->atom_context->bios + data_offset +
410 le16_to_cpu(ext_hdr->usVCETableOffset) + 1);
411 ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits =
412 (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
413 (mode_info->atom_context->bios + data_offset +
414 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
415 1 + array->ucNumEntries * sizeof(VCEClockInfo));
416 ATOM_PPLIB_VCE_State_Table *states =
417 (ATOM_PPLIB_VCE_State_Table *)
418 (mode_info->atom_context->bios + data_offset +
419 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
420 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) +
421 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));
422 ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry;
423 ATOM_PPLIB_VCE_State_Record *state_entry;
424 VCEClockInfo *vce_clk;
425 u32 size = limits->numEntries *
426 sizeof(struct amdgpu_vce_clock_voltage_dependency_entry);
427 adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries =
428 kzalloc(size, GFP_KERNEL);
429 if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries)
430 return -ENOMEM;
431 adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =
432 limits->numEntries;
433 entry = &limits->entries[0];
434 state_entry = &states->entries[0];
435 for (i = 0; i < limits->numEntries; i++) {
436 vce_clk = (VCEClockInfo *)
437 ((u8 *)&array->entries[0] +
438 (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
439 adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk =
440 le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
441 adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk =
442 le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
443 adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v =
444 le16_to_cpu(entry->usVoltage);
445 entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)
446 ((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));
447 }
448 adev->pm.dpm.num_of_vce_states =
449 states->numEntries > AMD_MAX_VCE_LEVELS ?
450 AMD_MAX_VCE_LEVELS : states->numEntries;
451 for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) {
452 vce_clk = (VCEClockInfo *)
453 ((u8 *)&array->entries[0] +
454 (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
455 adev->pm.dpm.vce_states[i].evclk =
456 le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
457 adev->pm.dpm.vce_states[i].ecclk =
458 le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
459 adev->pm.dpm.vce_states[i].clk_idx =
460 state_entry->ucClockInfoIndex & 0x3f;
461 adev->pm.dpm.vce_states[i].pstate =
462 (state_entry->ucClockInfoIndex & 0xc0) >> 6;
463 state_entry = (ATOM_PPLIB_VCE_State_Record *)
464 ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record));
465 }
466 }
467 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&
468 ext_hdr->usUVDTableOffset) {
469 UVDClockInfoArray *array = (UVDClockInfoArray *)
470 (mode_info->atom_context->bios + data_offset +
471 le16_to_cpu(ext_hdr->usUVDTableOffset) + 1);
472 ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits =
473 (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
474 (mode_info->atom_context->bios + data_offset +
475 le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 +
476 1 + (array->ucNumEntries * sizeof (UVDClockInfo)));
477 ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry;
478 u32 size = limits->numEntries *
479 sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry);
480 adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries =
481 kzalloc(size, GFP_KERNEL);
482 if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries)
483 return -ENOMEM;
484 adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count =
485 limits->numEntries;
486 entry = &limits->entries[0];
487 for (i = 0; i < limits->numEntries; i++) {
488 UVDClockInfo *uvd_clk = (UVDClockInfo *)
489 ((u8 *)&array->entries[0] +
490 (entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo)));
491 adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk =
492 le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16);
493 adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk =
494 le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16);
495 adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v =
496 le16_to_cpu(entry->usVoltage);
497 entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *)
498 ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record));
499 }
500 }
501 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) &&
502 ext_hdr->usSAMUTableOffset) {
503 ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits =
504 (ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
505 (mode_info->atom_context->bios + data_offset +
506 le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1);
507 ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry;
508 u32 size = limits->numEntries *
509 sizeof(struct amdgpu_clock_voltage_dependency_entry);
510 adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries =
511 kzalloc(size, GFP_KERNEL);
512 if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries)
513 return -ENOMEM;
514 adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count =
515 limits->numEntries;
516 entry = &limits->entries[0];
517 for (i = 0; i < limits->numEntries; i++) {
518 adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk =
519 le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16);
520 adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v =
521 le16_to_cpu(entry->usVoltage);
522 entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *)
523 ((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record));
524 }
525 }
526 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) &&
527 ext_hdr->usPPMTableOffset) {
528 ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *)
529 (mode_info->atom_context->bios + data_offset +
530 le16_to_cpu(ext_hdr->usPPMTableOffset));
531 adev->pm.dpm.dyn_state.ppm_table =
532 kzalloc(size: sizeof(struct amdgpu_ppm_table), GFP_KERNEL);
533 if (!adev->pm.dpm.dyn_state.ppm_table)
534 return -ENOMEM;
535 adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
536 adev->pm.dpm.dyn_state.ppm_table->cpu_core_number =
537 le16_to_cpu(ppm->usCpuCoreNumber);
538 adev->pm.dpm.dyn_state.ppm_table->platform_tdp =
539 le32_to_cpu(ppm->ulPlatformTDP);
540 adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp =
541 le32_to_cpu(ppm->ulSmallACPlatformTDP);
542 adev->pm.dpm.dyn_state.ppm_table->platform_tdc =
543 le32_to_cpu(ppm->ulPlatformTDC);
544 adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc =
545 le32_to_cpu(ppm->ulSmallACPlatformTDC);
546 adev->pm.dpm.dyn_state.ppm_table->apu_tdp =
547 le32_to_cpu(ppm->ulApuTDP);
548 adev->pm.dpm.dyn_state.ppm_table->dgpu_tdp =
549 le32_to_cpu(ppm->ulDGpuTDP);
550 adev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power =
551 le32_to_cpu(ppm->ulDGpuUlvPower);
552 adev->pm.dpm.dyn_state.ppm_table->tj_max =
553 le32_to_cpu(ppm->ulTjmax);
554 }
555 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) &&
556 ext_hdr->usACPTableOffset) {
557 ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits =
558 (ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
559 (mode_info->atom_context->bios + data_offset +
560 le16_to_cpu(ext_hdr->usACPTableOffset) + 1);
561 ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry;
562 u32 size = limits->numEntries *
563 sizeof(struct amdgpu_clock_voltage_dependency_entry);
564 adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries =
565 kzalloc(size, GFP_KERNEL);
566 if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries)
567 return -ENOMEM;
568 adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count =
569 limits->numEntries;
570 entry = &limits->entries[0];
571 for (i = 0; i < limits->numEntries; i++) {
572 adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk =
573 le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16);
574 adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v =
575 le16_to_cpu(entry->usVoltage);
576 entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *)
577 ((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record));
578 }
579 }
580 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) &&
581 ext_hdr->usPowerTuneTableOffset) {
582 u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset +
583 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
584 ATOM_PowerTune_Table *pt;
585 adev->pm.dpm.dyn_state.cac_tdp_table =
586 kzalloc(size: sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL);
587 if (!adev->pm.dpm.dyn_state.cac_tdp_table)
588 return -ENOMEM;
589 if (rev > 0) {
590 ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *)
591 (mode_info->atom_context->bios + data_offset +
592 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
593 adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
594 ppt->usMaximumPowerDeliveryLimit;
595 pt = &ppt->power_tune_table;
596 } else {
597 ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
598 (mode_info->atom_context->bios + data_offset +
599 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
600 adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255;
601 pt = &ppt->power_tune_table;
602 }
603 adev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP);
604 adev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp =
605 le16_to_cpu(pt->usConfigurableTDP);
606 adev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC);
607 adev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit =
608 le16_to_cpu(pt->usBatteryPowerLimit);
609 adev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit =
610 le16_to_cpu(pt->usSmallPowerLimit);
611 adev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage =
612 le16_to_cpu(pt->usLowCACLeakage);
613 adev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage =
614 le16_to_cpu(pt->usHighCACLeakage);
615 }
616 if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) &&
617 ext_hdr->usSclkVddgfxTableOffset) {
618 dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
619 (mode_info->atom_context->bios + data_offset +
620 le16_to_cpu(ext_hdr->usSclkVddgfxTableOffset));
621 ret = amdgpu_parse_clk_voltage_dep_table(
622 amdgpu_table: &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk,
623 atom_table: dep_table);
624 if (ret)
625 return ret;
626 }
627 }
628
629 return 0;
630}
631
632void amdgpu_free_extended_power_table(struct amdgpu_device *adev)
633{
634 struct amdgpu_dpm_dynamic_state *dyn_state = &adev->pm.dpm.dyn_state;
635
636 kfree(objp: dyn_state->vddc_dependency_on_sclk.entries);
637 kfree(objp: dyn_state->vddci_dependency_on_mclk.entries);
638 kfree(objp: dyn_state->vddc_dependency_on_mclk.entries);
639 kfree(objp: dyn_state->mvdd_dependency_on_mclk.entries);
640 kfree(objp: dyn_state->cac_leakage_table.entries);
641 kfree(objp: dyn_state->phase_shedding_limits_table.entries);
642 kfree(objp: dyn_state->ppm_table);
643 kfree(objp: dyn_state->cac_tdp_table);
644 kfree(objp: dyn_state->vce_clock_voltage_dependency_table.entries);
645 kfree(objp: dyn_state->uvd_clock_voltage_dependency_table.entries);
646 kfree(objp: dyn_state->samu_clock_voltage_dependency_table.entries);
647 kfree(objp: dyn_state->acp_clock_voltage_dependency_table.entries);
648 kfree(objp: dyn_state->vddgfx_dependency_on_sclk.entries);
649}
650
651static const char *pp_lib_thermal_controller_names[] = {
652 "NONE",
653 "lm63",
654 "adm1032",
655 "adm1030",
656 "max6649",
657 "lm64",
658 "f75375",
659 "RV6xx",
660 "RV770",
661 "adt7473",
662 "NONE",
663 "External GPIO",
664 "Evergreen",
665 "emc2103",
666 "Sumo",
667 "Northern Islands",
668 "Southern Islands",
669 "lm96163",
670 "Sea Islands",
671 "Kaveri/Kabini",
672};
673
674void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
675{
676 struct amdgpu_mode_info *mode_info = &adev->mode_info;
677 ATOM_PPLIB_POWERPLAYTABLE *power_table;
678 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
679 ATOM_PPLIB_THERMALCONTROLLER *controller;
680 struct amdgpu_i2c_bus_rec i2c_bus;
681 u16 data_offset;
682 u8 frev, crev;
683
684 if (!amdgpu_atom_parse_data_header(ctx: mode_info->atom_context, index, NULL,
685 frev: &frev, crev: &crev, data_start: &data_offset))
686 return;
687 power_table = (ATOM_PPLIB_POWERPLAYTABLE *)
688 (mode_info->atom_context->bios + data_offset);
689 controller = &power_table->sThermalController;
690
691 /* add the i2c bus for thermal/fan chip */
692 if (controller->ucType > 0) {
693 if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
694 adev->pm.no_fan = true;
695 adev->pm.fan_pulses_per_revolution =
696 controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
697 if (adev->pm.fan_pulses_per_revolution) {
698 adev->pm.fan_min_rpm = controller->ucFanMinRPM;
699 adev->pm.fan_max_rpm = controller->ucFanMaxRPM;
700 }
701 if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
702 DRM_INFO("Internal thermal controller %s fan control\n",
703 (controller->ucFanParameters &
704 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
705 adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
706 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
707 DRM_INFO("Internal thermal controller %s fan control\n",
708 (controller->ucFanParameters &
709 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
710 adev->pm.int_thermal_type = THERMAL_TYPE_RV770;
711 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
712 DRM_INFO("Internal thermal controller %s fan control\n",
713 (controller->ucFanParameters &
714 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
715 adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
716 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
717 DRM_INFO("Internal thermal controller %s fan control\n",
718 (controller->ucFanParameters &
719 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
720 adev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
721 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
722 DRM_INFO("Internal thermal controller %s fan control\n",
723 (controller->ucFanParameters &
724 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
725 adev->pm.int_thermal_type = THERMAL_TYPE_NI;
726 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
727 DRM_INFO("Internal thermal controller %s fan control\n",
728 (controller->ucFanParameters &
729 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
730 adev->pm.int_thermal_type = THERMAL_TYPE_SI;
731 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
732 DRM_INFO("Internal thermal controller %s fan control\n",
733 (controller->ucFanParameters &
734 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
735 adev->pm.int_thermal_type = THERMAL_TYPE_CI;
736 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
737 DRM_INFO("Internal thermal controller %s fan control\n",
738 (controller->ucFanParameters &
739 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
740 adev->pm.int_thermal_type = THERMAL_TYPE_KV;
741 } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
742 DRM_INFO("External GPIO thermal controller %s fan control\n",
743 (controller->ucFanParameters &
744 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
745 adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
746 } else if (controller->ucType ==
747 ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
748 DRM_INFO("ADT7473 with internal thermal controller %s fan control\n",
749 (controller->ucFanParameters &
750 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
751 adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
752 } else if (controller->ucType ==
753 ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
754 DRM_INFO("EMC2103 with internal thermal controller %s fan control\n",
755 (controller->ucFanParameters &
756 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
757 adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
758 } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
759 DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
760 pp_lib_thermal_controller_names[controller->ucType],
761 controller->ucI2cAddress >> 1,
762 (controller->ucFanParameters &
763 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
764 adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL;
765 i2c_bus = amdgpu_atombios_lookup_i2c_gpio(adev, id: controller->ucI2cLine);
766 adev->pm.i2c_bus = amdgpu_i2c_lookup(adev, i2c_bus: &i2c_bus);
767 if (adev->pm.i2c_bus) {
768 struct i2c_board_info info = { };
769 const char *name = pp_lib_thermal_controller_names[controller->ucType];
770 info.addr = controller->ucI2cAddress >> 1;
771 strscpy(info.type, name, sizeof(info.type));
772 i2c_new_client_device(adap: &adev->pm.i2c_bus->adapter, info: &info);
773 }
774 } else {
775 DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
776 controller->ucType,
777 controller->ucI2cAddress >> 1,
778 (controller->ucFanParameters &
779 ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
780 }
781 }
782}
783
784struct amd_vce_state* amdgpu_get_vce_clock_state(void *handle, u32 idx)
785{
786 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
787
788 if (idx < adev->pm.dpm.num_of_vce_states)
789 return &adev->pm.dpm.vce_states[idx];
790
791 return NULL;
792}
793
794static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
795 enum amd_pm_state_type dpm_state)
796{
797 int i;
798 struct amdgpu_ps *ps;
799 u32 ui_class;
800 bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ?
801 true : false;
802
803 /* check if the vblank period is too short to adjust the mclk */
804 if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
805 if (amdgpu_dpm_vblank_too_short(adev))
806 single_display = false;
807 }
808
809 /* certain older asics have a separare 3D performance state,
810 * so try that first if the user selected performance
811 */
812 if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
813 dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
814 /* balanced states don't exist at the moment */
815 if (dpm_state == POWER_STATE_TYPE_BALANCED)
816 dpm_state = POWER_STATE_TYPE_PERFORMANCE;
817
818restart_search:
819 /* Pick the best power state based on current conditions */
820 for (i = 0; i < adev->pm.dpm.num_ps; i++) {
821 ps = &adev->pm.dpm.ps[i];
822 ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
823 switch (dpm_state) {
824 /* user states */
825 case POWER_STATE_TYPE_BATTERY:
826 if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
827 if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
828 if (single_display)
829 return ps;
830 } else
831 return ps;
832 }
833 break;
834 case POWER_STATE_TYPE_BALANCED:
835 if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BALANCED) {
836 if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
837 if (single_display)
838 return ps;
839 } else
840 return ps;
841 }
842 break;
843 case POWER_STATE_TYPE_PERFORMANCE:
844 if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
845 if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
846 if (single_display)
847 return ps;
848 } else
849 return ps;
850 }
851 break;
852 /* internal states */
853 case POWER_STATE_TYPE_INTERNAL_UVD:
854 if (adev->pm.dpm.uvd_ps)
855 return adev->pm.dpm.uvd_ps;
856 else
857 break;
858 case POWER_STATE_TYPE_INTERNAL_UVD_SD:
859 if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
860 return ps;
861 break;
862 case POWER_STATE_TYPE_INTERNAL_UVD_HD:
863 if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
864 return ps;
865 break;
866 case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
867 if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
868 return ps;
869 break;
870 case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
871 if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
872 return ps;
873 break;
874 case POWER_STATE_TYPE_INTERNAL_BOOT:
875 return adev->pm.dpm.boot_ps;
876 case POWER_STATE_TYPE_INTERNAL_THERMAL:
877 if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
878 return ps;
879 break;
880 case POWER_STATE_TYPE_INTERNAL_ACPI:
881 if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
882 return ps;
883 break;
884 case POWER_STATE_TYPE_INTERNAL_ULV:
885 if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
886 return ps;
887 break;
888 case POWER_STATE_TYPE_INTERNAL_3DPERF:
889 if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
890 return ps;
891 break;
892 default:
893 break;
894 }
895 }
896 /* use a fallback state if we didn't match */
897 switch (dpm_state) {
898 case POWER_STATE_TYPE_INTERNAL_UVD_SD:
899 dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
900 goto restart_search;
901 case POWER_STATE_TYPE_INTERNAL_UVD_HD:
902 case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
903 case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
904 if (adev->pm.dpm.uvd_ps) {
905 return adev->pm.dpm.uvd_ps;
906 } else {
907 dpm_state = POWER_STATE_TYPE_PERFORMANCE;
908 goto restart_search;
909 }
910 case POWER_STATE_TYPE_INTERNAL_THERMAL:
911 dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
912 goto restart_search;
913 case POWER_STATE_TYPE_INTERNAL_ACPI:
914 dpm_state = POWER_STATE_TYPE_BATTERY;
915 goto restart_search;
916 case POWER_STATE_TYPE_BATTERY:
917 case POWER_STATE_TYPE_BALANCED:
918 case POWER_STATE_TYPE_INTERNAL_3DPERF:
919 dpm_state = POWER_STATE_TYPE_PERFORMANCE;
920 goto restart_search;
921 default:
922 break;
923 }
924
925 return NULL;
926}
927
928static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
929{
930 const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
931 struct amdgpu_ps *ps;
932 enum amd_pm_state_type dpm_state;
933 int ret;
934 bool equal = false;
935
936 /* if dpm init failed */
937 if (!adev->pm.dpm_enabled)
938 return 0;
939
940 if (adev->pm.dpm.user_state != adev->pm.dpm.state) {
941 /* add other state override checks here */
942 if ((!adev->pm.dpm.thermal_active) &&
943 (!adev->pm.dpm.uvd_active))
944 adev->pm.dpm.state = adev->pm.dpm.user_state;
945 }
946 dpm_state = adev->pm.dpm.state;
947
948 ps = amdgpu_dpm_pick_power_state(adev, dpm_state);
949 if (ps)
950 adev->pm.dpm.requested_ps = ps;
951 else
952 return -EINVAL;
953
954 if (amdgpu_dpm == 1 && pp_funcs->print_power_state) {
955 printk("switching from power state:\n");
956 amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
957 printk("switching to power state:\n");
958 amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
959 }
960
961 /* update whether vce is active */
962 ps->vce_active = adev->pm.dpm.vce_active;
963 if (pp_funcs->display_configuration_changed)
964 amdgpu_dpm_display_configuration_changed(adev);
965
966 ret = amdgpu_dpm_pre_set_power_state(adev);
967 if (ret)
968 return ret;
969
970 if (pp_funcs->check_state_equal) {
971 if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal))
972 equal = false;
973 }
974
975 if (equal)
976 return 0;
977
978 if (pp_funcs->set_power_state)
979 pp_funcs->set_power_state(adev->powerplay.pp_handle);
980
981 amdgpu_dpm_post_set_power_state(adev);
982
983 adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
984 adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
985
986 if (pp_funcs->force_performance_level) {
987 if (adev->pm.dpm.thermal_active) {
988 enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
989 /* force low perf level for thermal */
990 pp_funcs->force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
991 /* save the user's level */
992 adev->pm.dpm.forced_level = level;
993 } else {
994 /* otherwise, user selected level */
995 pp_funcs->force_performance_level(adev, adev->pm.dpm.forced_level);
996 }
997 }
998
999 return 0;
1000}
1001
1002void amdgpu_legacy_dpm_compute_clocks(void *handle)
1003{
1004 struct amdgpu_device *adev = (struct amdgpu_device *)handle;
1005
1006 amdgpu_dpm_get_active_displays(adev);
1007
1008 amdgpu_dpm_change_power_state_locked(adev);
1009}
1010
1011void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
1012{
1013 struct amdgpu_device *adev =
1014 container_of(work, struct amdgpu_device,
1015 pm.dpm.thermal.work);
1016 const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
1017 /* switch to the thermal state */
1018 enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
1019 int temp, size = sizeof(temp);
1020
1021 if (!adev->pm.dpm_enabled)
1022 return;
1023
1024 if (!pp_funcs->read_sensor(adev->powerplay.pp_handle,
1025 AMDGPU_PP_SENSOR_GPU_TEMP,
1026 (void *)&temp,
1027 &size)) {
1028 if (temp < adev->pm.dpm.thermal.min_temp)
1029 /* switch back the user state */
1030 dpm_state = adev->pm.dpm.user_state;
1031 } else {
1032 if (adev->pm.dpm.thermal.high_to_low)
1033 /* switch back the user state */
1034 dpm_state = adev->pm.dpm.user_state;
1035 }
1036
1037 if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
1038 adev->pm.dpm.thermal_active = true;
1039 else
1040 adev->pm.dpm.thermal_active = false;
1041
1042 adev->pm.dpm.state = dpm_state;
1043
1044 amdgpu_legacy_dpm_compute_clocks(handle: adev->powerplay.pp_handle);
1045}
1046

source code of linux/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c