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