1837d542aSEvan Quan /*
2837d542aSEvan Quan * Copyright 2021 Advanced Micro Devices, Inc.
3837d542aSEvan Quan *
4837d542aSEvan Quan * Permission is hereby granted, free of charge, to any person obtaining a
5837d542aSEvan Quan * copy of this software and associated documentation files (the "Software"),
6837d542aSEvan Quan * to deal in the Software without restriction, including without limitation
7837d542aSEvan Quan * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8837d542aSEvan Quan * and/or sell copies of the Software, and to permit persons to whom the
9837d542aSEvan Quan * Software is furnished to do so, subject to the following conditions:
10837d542aSEvan Quan *
11837d542aSEvan Quan * The above copyright notice and this permission notice shall be included in
12837d542aSEvan Quan * all copies or substantial portions of the Software.
13837d542aSEvan Quan *
14837d542aSEvan Quan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15837d542aSEvan Quan * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16837d542aSEvan Quan * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17837d542aSEvan Quan * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18837d542aSEvan Quan * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19837d542aSEvan Quan * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20837d542aSEvan Quan * OTHER DEALINGS IN THE SOFTWARE.
21837d542aSEvan Quan */
22837d542aSEvan Quan
23837d542aSEvan Quan #include "amdgpu.h"
24837d542aSEvan Quan #include "amdgpu_i2c.h"
25837d542aSEvan Quan #include "amdgpu_atombios.h"
26837d542aSEvan Quan #include "atom.h"
27837d542aSEvan Quan #include "amd_pcie.h"
28837d542aSEvan Quan #include "legacy_dpm.h"
29837d542aSEvan Quan #include "amdgpu_dpm_internal.h"
30837d542aSEvan Quan #include "amdgpu_display.h"
31837d542aSEvan Quan
32837d542aSEvan Quan #define amdgpu_dpm_pre_set_power_state(adev) \
33837d542aSEvan Quan ((adev)->powerplay.pp_funcs->pre_set_power_state((adev)->powerplay.pp_handle))
34837d542aSEvan Quan
35837d542aSEvan Quan #define amdgpu_dpm_post_set_power_state(adev) \
36837d542aSEvan Quan ((adev)->powerplay.pp_funcs->post_set_power_state((adev)->powerplay.pp_handle))
37837d542aSEvan Quan
38837d542aSEvan Quan #define amdgpu_dpm_display_configuration_changed(adev) \
39837d542aSEvan Quan ((adev)->powerplay.pp_funcs->display_configuration_changed((adev)->powerplay.pp_handle))
40837d542aSEvan Quan
41837d542aSEvan Quan #define amdgpu_dpm_print_power_state(adev, ps) \
42837d542aSEvan Quan ((adev)->powerplay.pp_funcs->print_power_state((adev)->powerplay.pp_handle, (ps)))
43837d542aSEvan Quan
44837d542aSEvan Quan #define amdgpu_dpm_vblank_too_short(adev) \
45837d542aSEvan Quan ((adev)->powerplay.pp_funcs->vblank_too_short((adev)->powerplay.pp_handle))
46837d542aSEvan Quan
47837d542aSEvan Quan #define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \
48837d542aSEvan Quan ((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal)))
49837d542aSEvan Quan
amdgpu_dpm_print_class_info(u32 class,u32 class2)50837d542aSEvan Quan void amdgpu_dpm_print_class_info(u32 class, u32 class2)
51837d542aSEvan Quan {
52837d542aSEvan Quan const char *s;
53837d542aSEvan Quan
54837d542aSEvan Quan switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
55837d542aSEvan Quan case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
56837d542aSEvan Quan default:
57837d542aSEvan Quan s = "none";
58837d542aSEvan Quan break;
59837d542aSEvan Quan case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
60837d542aSEvan Quan s = "battery";
61837d542aSEvan Quan break;
62837d542aSEvan Quan case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
63837d542aSEvan Quan s = "balanced";
64837d542aSEvan Quan break;
65837d542aSEvan Quan case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
66837d542aSEvan Quan s = "performance";
67837d542aSEvan Quan break;
68837d542aSEvan Quan }
69837d542aSEvan Quan printk("\tui class: %s\n", s);
70837d542aSEvan Quan printk("\tinternal class:");
71837d542aSEvan Quan if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
72837d542aSEvan Quan (class2 == 0))
73837d542aSEvan Quan pr_cont(" none");
74837d542aSEvan Quan else {
75837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_BOOT)
76837d542aSEvan Quan pr_cont(" boot");
77837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
78837d542aSEvan Quan pr_cont(" thermal");
79837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
80837d542aSEvan Quan pr_cont(" limited_pwr");
81837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_REST)
82837d542aSEvan Quan pr_cont(" rest");
83837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_FORCED)
84837d542aSEvan Quan pr_cont(" forced");
85837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
86837d542aSEvan Quan pr_cont(" 3d_perf");
87837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
88837d542aSEvan Quan pr_cont(" ovrdrv");
89837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
90837d542aSEvan Quan pr_cont(" uvd");
91837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_3DLOW)
92837d542aSEvan Quan pr_cont(" 3d_low");
93837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_ACPI)
94837d542aSEvan Quan pr_cont(" acpi");
95837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
96837d542aSEvan Quan pr_cont(" uvd_hd2");
97837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
98837d542aSEvan Quan pr_cont(" uvd_hd");
99837d542aSEvan Quan if (class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
100837d542aSEvan Quan pr_cont(" uvd_sd");
101837d542aSEvan Quan if (class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
102837d542aSEvan Quan pr_cont(" limited_pwr2");
103837d542aSEvan Quan if (class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
104837d542aSEvan Quan pr_cont(" ulv");
105837d542aSEvan Quan if (class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
106837d542aSEvan Quan pr_cont(" uvd_mvc");
107837d542aSEvan Quan }
108837d542aSEvan Quan pr_cont("\n");
109837d542aSEvan Quan }
110837d542aSEvan Quan
amdgpu_dpm_print_cap_info(u32 caps)111837d542aSEvan Quan void amdgpu_dpm_print_cap_info(u32 caps)
112837d542aSEvan Quan {
113837d542aSEvan Quan printk("\tcaps:");
114837d542aSEvan Quan if (caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY)
115837d542aSEvan Quan pr_cont(" single_disp");
116837d542aSEvan Quan if (caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK)
117837d542aSEvan Quan pr_cont(" video");
118837d542aSEvan Quan if (caps & ATOM_PPLIB_DISALLOW_ON_DC)
119837d542aSEvan Quan pr_cont(" no_dc");
120837d542aSEvan Quan pr_cont("\n");
121837d542aSEvan Quan }
122837d542aSEvan Quan
amdgpu_dpm_print_ps_status(struct amdgpu_device * adev,struct amdgpu_ps * rps)123837d542aSEvan Quan void amdgpu_dpm_print_ps_status(struct amdgpu_device *adev,
124837d542aSEvan Quan struct amdgpu_ps *rps)
125837d542aSEvan Quan {
126837d542aSEvan Quan printk("\tstatus:");
127837d542aSEvan Quan if (rps == adev->pm.dpm.current_ps)
128837d542aSEvan Quan pr_cont(" c");
129837d542aSEvan Quan if (rps == adev->pm.dpm.requested_ps)
130837d542aSEvan Quan pr_cont(" r");
131837d542aSEvan Quan if (rps == adev->pm.dpm.boot_ps)
132837d542aSEvan Quan pr_cont(" b");
133837d542aSEvan Quan pr_cont("\n");
134837d542aSEvan Quan }
135837d542aSEvan Quan
amdgpu_pm_print_power_states(struct amdgpu_device * adev)136837d542aSEvan Quan void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
137837d542aSEvan Quan {
138837d542aSEvan Quan int i;
139837d542aSEvan Quan
140837d542aSEvan Quan if (adev->powerplay.pp_funcs->print_power_state == NULL)
141837d542aSEvan Quan return;
142837d542aSEvan Quan
143837d542aSEvan Quan for (i = 0; i < adev->pm.dpm.num_ps; i++)
144837d542aSEvan Quan amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
145837d542aSEvan Quan
146837d542aSEvan Quan }
147837d542aSEvan Quan
148837d542aSEvan Quan union power_info {
149837d542aSEvan Quan struct _ATOM_POWERPLAY_INFO info;
150837d542aSEvan Quan struct _ATOM_POWERPLAY_INFO_V2 info_2;
151837d542aSEvan Quan struct _ATOM_POWERPLAY_INFO_V3 info_3;
152837d542aSEvan Quan struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
153837d542aSEvan Quan struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
154837d542aSEvan Quan struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
155837d542aSEvan Quan struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
156837d542aSEvan Quan struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
157837d542aSEvan Quan };
158837d542aSEvan Quan
amdgpu_get_platform_caps(struct amdgpu_device * adev)159837d542aSEvan Quan int amdgpu_get_platform_caps(struct amdgpu_device *adev)
160837d542aSEvan Quan {
161837d542aSEvan Quan struct amdgpu_mode_info *mode_info = &adev->mode_info;
162837d542aSEvan Quan union power_info *power_info;
163837d542aSEvan Quan int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
164837d542aSEvan Quan u16 data_offset;
165837d542aSEvan Quan u8 frev, crev;
166837d542aSEvan Quan
167837d542aSEvan Quan if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
168837d542aSEvan Quan &frev, &crev, &data_offset))
169837d542aSEvan Quan return -EINVAL;
170837d542aSEvan Quan power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
171837d542aSEvan Quan
172837d542aSEvan Quan adev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
173837d542aSEvan Quan adev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
174837d542aSEvan Quan adev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
175837d542aSEvan Quan
176837d542aSEvan Quan return 0;
177837d542aSEvan Quan }
178837d542aSEvan Quan
179837d542aSEvan Quan union fan_info {
180837d542aSEvan Quan struct _ATOM_PPLIB_FANTABLE fan;
181837d542aSEvan Quan struct _ATOM_PPLIB_FANTABLE2 fan2;
182837d542aSEvan Quan struct _ATOM_PPLIB_FANTABLE3 fan3;
183837d542aSEvan Quan };
184837d542aSEvan Quan
amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table * amdgpu_table,ATOM_PPLIB_Clock_Voltage_Dependency_Table * atom_table)185837d542aSEvan Quan static int amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table *amdgpu_table,
186837d542aSEvan Quan ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
187837d542aSEvan Quan {
188837d542aSEvan Quan u32 size = atom_table->ucNumEntries *
189837d542aSEvan Quan sizeof(struct amdgpu_clock_voltage_dependency_entry);
190837d542aSEvan Quan int i;
191837d542aSEvan Quan ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry;
192837d542aSEvan Quan
193837d542aSEvan Quan amdgpu_table->entries = kzalloc(size, GFP_KERNEL);
194837d542aSEvan Quan if (!amdgpu_table->entries)
195837d542aSEvan Quan return -ENOMEM;
196837d542aSEvan Quan
197837d542aSEvan Quan entry = &atom_table->entries[0];
198837d542aSEvan Quan for (i = 0; i < atom_table->ucNumEntries; i++) {
199837d542aSEvan Quan amdgpu_table->entries[i].clk = le16_to_cpu(entry->usClockLow) |
200837d542aSEvan Quan (entry->ucClockHigh << 16);
201837d542aSEvan Quan amdgpu_table->entries[i].v = le16_to_cpu(entry->usVoltage);
202837d542aSEvan Quan entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *)
203837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record));
204837d542aSEvan Quan }
205837d542aSEvan Quan amdgpu_table->count = atom_table->ucNumEntries;
206837d542aSEvan Quan
207837d542aSEvan Quan return 0;
208837d542aSEvan Quan }
209837d542aSEvan Quan
210837d542aSEvan Quan /* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
211837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
212837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
213837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
214837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
215837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
216837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
217837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
218837d542aSEvan Quan #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
219837d542aSEvan Quan
amdgpu_parse_extended_power_table(struct amdgpu_device * adev)220837d542aSEvan Quan int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
221837d542aSEvan Quan {
222837d542aSEvan Quan struct amdgpu_mode_info *mode_info = &adev->mode_info;
223837d542aSEvan Quan union power_info *power_info;
224837d542aSEvan Quan union fan_info *fan_info;
225837d542aSEvan Quan ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
226837d542aSEvan Quan int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
227837d542aSEvan Quan u16 data_offset;
228837d542aSEvan Quan u8 frev, crev;
229837d542aSEvan Quan int ret, i;
230837d542aSEvan Quan
231837d542aSEvan Quan if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
232837d542aSEvan Quan &frev, &crev, &data_offset))
233837d542aSEvan Quan return -EINVAL;
234837d542aSEvan Quan power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
235837d542aSEvan Quan
236837d542aSEvan Quan /* fan table */
237837d542aSEvan Quan if (le16_to_cpu(power_info->pplib.usTableSize) >=
238837d542aSEvan Quan sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
239837d542aSEvan Quan if (power_info->pplib3.usFanTableOffset) {
240837d542aSEvan Quan fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset +
241837d542aSEvan Quan le16_to_cpu(power_info->pplib3.usFanTableOffset));
242837d542aSEvan Quan adev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
243837d542aSEvan Quan adev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
244837d542aSEvan Quan adev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
245837d542aSEvan Quan adev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
246837d542aSEvan Quan adev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
247837d542aSEvan Quan adev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
248837d542aSEvan Quan adev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
249837d542aSEvan Quan if (fan_info->fan.ucFanTableFormat >= 2)
250837d542aSEvan Quan adev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
251837d542aSEvan Quan else
252837d542aSEvan Quan adev->pm.dpm.fan.t_max = 10900;
253837d542aSEvan Quan adev->pm.dpm.fan.cycle_delay = 100000;
254837d542aSEvan Quan if (fan_info->fan.ucFanTableFormat >= 3) {
255837d542aSEvan Quan adev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
256837d542aSEvan Quan adev->pm.dpm.fan.default_max_fan_pwm =
257837d542aSEvan Quan le16_to_cpu(fan_info->fan3.usFanPWMMax);
258837d542aSEvan Quan adev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
259837d542aSEvan Quan adev->pm.dpm.fan.fan_output_sensitivity =
260837d542aSEvan Quan le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
261837d542aSEvan Quan }
262837d542aSEvan Quan adev->pm.dpm.fan.ucode_fan_control = true;
263837d542aSEvan Quan }
264837d542aSEvan Quan }
265837d542aSEvan Quan
266837d542aSEvan Quan /* clock dependancy tables, shedding tables */
267837d542aSEvan Quan if (le16_to_cpu(power_info->pplib.usTableSize) >=
268837d542aSEvan Quan sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) {
269837d542aSEvan Quan if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
270837d542aSEvan Quan dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
271837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
272837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
273837d542aSEvan Quan ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
274837d542aSEvan Quan dep_table);
275*a6582701SZhipeng Lu if (ret)
276837d542aSEvan Quan return ret;
277837d542aSEvan Quan }
278837d542aSEvan Quan if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
279837d542aSEvan Quan dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
280837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
281837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
282837d542aSEvan Quan ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
283837d542aSEvan Quan dep_table);
284*a6582701SZhipeng Lu if (ret)
285837d542aSEvan Quan return ret;
286837d542aSEvan Quan }
287837d542aSEvan Quan if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
288837d542aSEvan Quan dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
289837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
290837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
291837d542aSEvan Quan ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
292837d542aSEvan Quan dep_table);
293*a6582701SZhipeng Lu if (ret)
294837d542aSEvan Quan return ret;
295837d542aSEvan Quan }
296837d542aSEvan Quan if (power_info->pplib4.usMvddDependencyOnMCLKOffset) {
297837d542aSEvan Quan dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
298837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
299837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset));
300837d542aSEvan Quan ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
301837d542aSEvan Quan dep_table);
302*a6582701SZhipeng Lu if (ret)
303837d542aSEvan Quan return ret;
304837d542aSEvan Quan }
305837d542aSEvan Quan if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
306837d542aSEvan Quan ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
307837d542aSEvan Quan (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
308837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
309837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
310837d542aSEvan Quan if (clk_v->ucNumEntries) {
311837d542aSEvan Quan adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
312837d542aSEvan Quan le16_to_cpu(clk_v->entries[0].usSclkLow) |
313837d542aSEvan Quan (clk_v->entries[0].ucSclkHigh << 16);
314837d542aSEvan Quan adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
315837d542aSEvan Quan le16_to_cpu(clk_v->entries[0].usMclkLow) |
316837d542aSEvan Quan (clk_v->entries[0].ucMclkHigh << 16);
317837d542aSEvan Quan adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
318837d542aSEvan Quan le16_to_cpu(clk_v->entries[0].usVddc);
319837d542aSEvan Quan adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
320837d542aSEvan Quan le16_to_cpu(clk_v->entries[0].usVddci);
321837d542aSEvan Quan }
322837d542aSEvan Quan }
323837d542aSEvan Quan if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) {
324837d542aSEvan Quan ATOM_PPLIB_PhaseSheddingLimits_Table *psl =
325837d542aSEvan Quan (ATOM_PPLIB_PhaseSheddingLimits_Table *)
326837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
327837d542aSEvan Quan le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset));
328837d542aSEvan Quan ATOM_PPLIB_PhaseSheddingLimits_Record *entry;
329837d542aSEvan Quan
330837d542aSEvan Quan adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
331837d542aSEvan Quan kcalloc(psl->ucNumEntries,
332837d542aSEvan Quan sizeof(struct amdgpu_phase_shedding_limits_entry),
333837d542aSEvan Quan GFP_KERNEL);
334*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
335837d542aSEvan Quan return -ENOMEM;
336837d542aSEvan Quan
337837d542aSEvan Quan entry = &psl->entries[0];
338837d542aSEvan Quan for (i = 0; i < psl->ucNumEntries; i++) {
339837d542aSEvan Quan adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk =
340837d542aSEvan Quan le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16);
341837d542aSEvan Quan adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk =
342837d542aSEvan Quan le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16);
343837d542aSEvan Quan adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage =
344837d542aSEvan Quan le16_to_cpu(entry->usVoltage);
345837d542aSEvan Quan entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *)
346837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record));
347837d542aSEvan Quan }
348837d542aSEvan Quan adev->pm.dpm.dyn_state.phase_shedding_limits_table.count =
349837d542aSEvan Quan psl->ucNumEntries;
350837d542aSEvan Quan }
351837d542aSEvan Quan }
352837d542aSEvan Quan
353837d542aSEvan Quan /* cac data */
354837d542aSEvan Quan if (le16_to_cpu(power_info->pplib.usTableSize) >=
355837d542aSEvan Quan sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) {
356837d542aSEvan Quan adev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
357837d542aSEvan Quan adev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
358837d542aSEvan Quan adev->pm.dpm.near_tdp_limit_adjusted = adev->pm.dpm.near_tdp_limit;
359837d542aSEvan Quan adev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
360837d542aSEvan Quan if (adev->pm.dpm.tdp_od_limit)
361837d542aSEvan Quan adev->pm.dpm.power_control = true;
362837d542aSEvan Quan else
363837d542aSEvan Quan adev->pm.dpm.power_control = false;
364837d542aSEvan Quan adev->pm.dpm.tdp_adjustment = 0;
365837d542aSEvan Quan adev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
366837d542aSEvan Quan adev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
367837d542aSEvan Quan adev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope);
368837d542aSEvan Quan if (power_info->pplib5.usCACLeakageTableOffset) {
369837d542aSEvan Quan ATOM_PPLIB_CAC_Leakage_Table *cac_table =
370837d542aSEvan Quan (ATOM_PPLIB_CAC_Leakage_Table *)
371837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
372837d542aSEvan Quan le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
373837d542aSEvan Quan ATOM_PPLIB_CAC_Leakage_Record *entry;
374837d542aSEvan Quan u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table);
375837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
376*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries)
377837d542aSEvan Quan return -ENOMEM;
378837d542aSEvan Quan entry = &cac_table->entries[0];
379837d542aSEvan Quan for (i = 0; i < cac_table->ucNumEntries; i++) {
380837d542aSEvan Quan if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
381837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 =
382837d542aSEvan Quan le16_to_cpu(entry->usVddc1);
383837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 =
384837d542aSEvan Quan le16_to_cpu(entry->usVddc2);
385837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 =
386837d542aSEvan Quan le16_to_cpu(entry->usVddc3);
387837d542aSEvan Quan } else {
388837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
389837d542aSEvan Quan le16_to_cpu(entry->usVddc);
390837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
391837d542aSEvan Quan le32_to_cpu(entry->ulLeakageValue);
392837d542aSEvan Quan }
393837d542aSEvan Quan entry = (ATOM_PPLIB_CAC_Leakage_Record *)
394837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record));
395837d542aSEvan Quan }
396837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
397837d542aSEvan Quan }
398837d542aSEvan Quan }
399837d542aSEvan Quan
400837d542aSEvan Quan /* ext tables */
401837d542aSEvan Quan if (le16_to_cpu(power_info->pplib.usTableSize) >=
402837d542aSEvan Quan sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
403837d542aSEvan Quan ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *)
404837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
405837d542aSEvan Quan le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset));
406837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) &&
407837d542aSEvan Quan ext_hdr->usVCETableOffset) {
408837d542aSEvan Quan VCEClockInfoArray *array = (VCEClockInfoArray *)
409837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
410837d542aSEvan Quan le16_to_cpu(ext_hdr->usVCETableOffset) + 1);
411837d542aSEvan Quan ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits =
412837d542aSEvan Quan (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
413837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
414837d542aSEvan Quan le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
415837d542aSEvan Quan 1 + array->ucNumEntries * sizeof(VCEClockInfo));
416837d542aSEvan Quan ATOM_PPLIB_VCE_State_Table *states =
417837d542aSEvan Quan (ATOM_PPLIB_VCE_State_Table *)
418837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
419837d542aSEvan Quan le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
420837d542aSEvan Quan 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) +
421837d542aSEvan Quan 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));
422837d542aSEvan Quan ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry;
423837d542aSEvan Quan ATOM_PPLIB_VCE_State_Record *state_entry;
424837d542aSEvan Quan VCEClockInfo *vce_clk;
425837d542aSEvan Quan u32 size = limits->numEntries *
426837d542aSEvan Quan sizeof(struct amdgpu_vce_clock_voltage_dependency_entry);
427837d542aSEvan Quan adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries =
428837d542aSEvan Quan kzalloc(size, GFP_KERNEL);
429*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries)
430837d542aSEvan Quan return -ENOMEM;
431837d542aSEvan Quan adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =
432837d542aSEvan Quan limits->numEntries;
433837d542aSEvan Quan entry = &limits->entries[0];
434837d542aSEvan Quan state_entry = &states->entries[0];
435837d542aSEvan Quan for (i = 0; i < limits->numEntries; i++) {
436837d542aSEvan Quan vce_clk = (VCEClockInfo *)
437837d542aSEvan Quan ((u8 *)&array->entries[0] +
438837d542aSEvan Quan (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
439837d542aSEvan Quan adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk =
440837d542aSEvan Quan le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
441837d542aSEvan Quan adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk =
442837d542aSEvan Quan le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
443837d542aSEvan Quan adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v =
444837d542aSEvan Quan le16_to_cpu(entry->usVoltage);
445837d542aSEvan Quan entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)
446837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));
447837d542aSEvan Quan }
448837d542aSEvan Quan adev->pm.dpm.num_of_vce_states =
449837d542aSEvan Quan states->numEntries > AMD_MAX_VCE_LEVELS ?
450837d542aSEvan Quan AMD_MAX_VCE_LEVELS : states->numEntries;
451837d542aSEvan Quan for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) {
452837d542aSEvan Quan vce_clk = (VCEClockInfo *)
453837d542aSEvan Quan ((u8 *)&array->entries[0] +
454837d542aSEvan Quan (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
455837d542aSEvan Quan adev->pm.dpm.vce_states[i].evclk =
456837d542aSEvan Quan le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
457837d542aSEvan Quan adev->pm.dpm.vce_states[i].ecclk =
458837d542aSEvan Quan le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
459837d542aSEvan Quan adev->pm.dpm.vce_states[i].clk_idx =
460837d542aSEvan Quan state_entry->ucClockInfoIndex & 0x3f;
461837d542aSEvan Quan adev->pm.dpm.vce_states[i].pstate =
462837d542aSEvan Quan (state_entry->ucClockInfoIndex & 0xc0) >> 6;
463837d542aSEvan Quan state_entry = (ATOM_PPLIB_VCE_State_Record *)
464837d542aSEvan Quan ((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record));
465837d542aSEvan Quan }
466837d542aSEvan Quan }
467837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&
468837d542aSEvan Quan ext_hdr->usUVDTableOffset) {
469837d542aSEvan Quan UVDClockInfoArray *array = (UVDClockInfoArray *)
470837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
471837d542aSEvan Quan le16_to_cpu(ext_hdr->usUVDTableOffset) + 1);
472837d542aSEvan Quan ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits =
473837d542aSEvan Quan (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
474837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
475837d542aSEvan Quan le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 +
476837d542aSEvan Quan 1 + (array->ucNumEntries * sizeof (UVDClockInfo)));
477837d542aSEvan Quan ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry;
478837d542aSEvan Quan u32 size = limits->numEntries *
479837d542aSEvan Quan sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry);
480837d542aSEvan Quan adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries =
481837d542aSEvan Quan kzalloc(size, GFP_KERNEL);
482*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries)
483837d542aSEvan Quan return -ENOMEM;
484837d542aSEvan Quan adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count =
485837d542aSEvan Quan limits->numEntries;
486837d542aSEvan Quan entry = &limits->entries[0];
487837d542aSEvan Quan for (i = 0; i < limits->numEntries; i++) {
488837d542aSEvan Quan UVDClockInfo *uvd_clk = (UVDClockInfo *)
489837d542aSEvan Quan ((u8 *)&array->entries[0] +
490837d542aSEvan Quan (entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo)));
491837d542aSEvan Quan adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk =
492837d542aSEvan Quan le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16);
493837d542aSEvan Quan adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk =
494837d542aSEvan Quan le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16);
495837d542aSEvan Quan adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v =
496837d542aSEvan Quan le16_to_cpu(entry->usVoltage);
497837d542aSEvan Quan entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *)
498837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record));
499837d542aSEvan Quan }
500837d542aSEvan Quan }
501837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) &&
502837d542aSEvan Quan ext_hdr->usSAMUTableOffset) {
503837d542aSEvan Quan ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits =
504837d542aSEvan Quan (ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
505837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
506837d542aSEvan Quan le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1);
507837d542aSEvan Quan ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry;
508837d542aSEvan Quan u32 size = limits->numEntries *
509837d542aSEvan Quan sizeof(struct amdgpu_clock_voltage_dependency_entry);
510837d542aSEvan Quan adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries =
511837d542aSEvan Quan kzalloc(size, GFP_KERNEL);
512*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries)
513837d542aSEvan Quan return -ENOMEM;
514837d542aSEvan Quan adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count =
515837d542aSEvan Quan limits->numEntries;
516837d542aSEvan Quan entry = &limits->entries[0];
517837d542aSEvan Quan for (i = 0; i < limits->numEntries; i++) {
518837d542aSEvan Quan adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk =
519837d542aSEvan Quan le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16);
520837d542aSEvan Quan adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v =
521837d542aSEvan Quan le16_to_cpu(entry->usVoltage);
522837d542aSEvan Quan entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *)
523837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record));
524837d542aSEvan Quan }
525837d542aSEvan Quan }
526837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) &&
527837d542aSEvan Quan ext_hdr->usPPMTableOffset) {
528837d542aSEvan Quan ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *)
529837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
530837d542aSEvan Quan le16_to_cpu(ext_hdr->usPPMTableOffset));
531837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table =
532837d542aSEvan Quan kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL);
533*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.ppm_table)
534837d542aSEvan Quan return -ENOMEM;
535837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
536837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->cpu_core_number =
537837d542aSEvan Quan le16_to_cpu(ppm->usCpuCoreNumber);
538837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->platform_tdp =
539837d542aSEvan Quan le32_to_cpu(ppm->ulPlatformTDP);
540837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp =
541837d542aSEvan Quan le32_to_cpu(ppm->ulSmallACPlatformTDP);
542837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->platform_tdc =
543837d542aSEvan Quan le32_to_cpu(ppm->ulPlatformTDC);
544837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc =
545837d542aSEvan Quan le32_to_cpu(ppm->ulSmallACPlatformTDC);
546837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->apu_tdp =
547837d542aSEvan Quan le32_to_cpu(ppm->ulApuTDP);
548837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->dgpu_tdp =
549837d542aSEvan Quan le32_to_cpu(ppm->ulDGpuTDP);
550837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power =
551837d542aSEvan Quan le32_to_cpu(ppm->ulDGpuUlvPower);
552837d542aSEvan Quan adev->pm.dpm.dyn_state.ppm_table->tj_max =
553837d542aSEvan Quan le32_to_cpu(ppm->ulTjmax);
554837d542aSEvan Quan }
555837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) &&
556837d542aSEvan Quan ext_hdr->usACPTableOffset) {
557837d542aSEvan Quan ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits =
558837d542aSEvan Quan (ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
559837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
560837d542aSEvan Quan le16_to_cpu(ext_hdr->usACPTableOffset) + 1);
561837d542aSEvan Quan ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry;
562837d542aSEvan Quan u32 size = limits->numEntries *
563837d542aSEvan Quan sizeof(struct amdgpu_clock_voltage_dependency_entry);
564837d542aSEvan Quan adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries =
565837d542aSEvan Quan kzalloc(size, GFP_KERNEL);
566*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries)
567837d542aSEvan Quan return -ENOMEM;
568837d542aSEvan Quan adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count =
569837d542aSEvan Quan limits->numEntries;
570837d542aSEvan Quan entry = &limits->entries[0];
571837d542aSEvan Quan for (i = 0; i < limits->numEntries; i++) {
572837d542aSEvan Quan adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk =
573837d542aSEvan Quan le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16);
574837d542aSEvan Quan adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v =
575837d542aSEvan Quan le16_to_cpu(entry->usVoltage);
576837d542aSEvan Quan entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *)
577837d542aSEvan Quan ((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record));
578837d542aSEvan Quan }
579837d542aSEvan Quan }
580837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) &&
581837d542aSEvan Quan ext_hdr->usPowerTuneTableOffset) {
582837d542aSEvan Quan u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset +
583837d542aSEvan Quan le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
584837d542aSEvan Quan ATOM_PowerTune_Table *pt;
585837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table =
586837d542aSEvan Quan kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL);
587*a6582701SZhipeng Lu if (!adev->pm.dpm.dyn_state.cac_tdp_table)
588837d542aSEvan Quan return -ENOMEM;
589837d542aSEvan Quan if (rev > 0) {
590837d542aSEvan Quan ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *)
591837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
592837d542aSEvan Quan le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
593837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
594837d542aSEvan Quan ppt->usMaximumPowerDeliveryLimit;
595837d542aSEvan Quan pt = &ppt->power_tune_table;
596837d542aSEvan Quan } else {
597837d542aSEvan Quan ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
598837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
599837d542aSEvan Quan le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
600837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255;
601837d542aSEvan Quan pt = &ppt->power_tune_table;
602837d542aSEvan Quan }
603837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP);
604837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp =
605837d542aSEvan Quan le16_to_cpu(pt->usConfigurableTDP);
606837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC);
607837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit =
608837d542aSEvan Quan le16_to_cpu(pt->usBatteryPowerLimit);
609837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit =
610837d542aSEvan Quan le16_to_cpu(pt->usSmallPowerLimit);
611837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage =
612837d542aSEvan Quan le16_to_cpu(pt->usLowCACLeakage);
613837d542aSEvan Quan adev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage =
614837d542aSEvan Quan le16_to_cpu(pt->usHighCACLeakage);
615837d542aSEvan Quan }
616837d542aSEvan Quan if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) &&
617837d542aSEvan Quan ext_hdr->usSclkVddgfxTableOffset) {
618837d542aSEvan Quan dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
619837d542aSEvan Quan (mode_info->atom_context->bios + data_offset +
620837d542aSEvan Quan le16_to_cpu(ext_hdr->usSclkVddgfxTableOffset));
621837d542aSEvan Quan ret = amdgpu_parse_clk_voltage_dep_table(
622837d542aSEvan Quan &adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk,
623837d542aSEvan Quan dep_table);
624*a6582701SZhipeng Lu if (ret)
625837d542aSEvan Quan return ret;
626837d542aSEvan Quan }
627837d542aSEvan Quan }
628837d542aSEvan Quan
629837d542aSEvan Quan return 0;
630837d542aSEvan Quan }
631837d542aSEvan Quan
amdgpu_free_extended_power_table(struct amdgpu_device * adev)632837d542aSEvan Quan void amdgpu_free_extended_power_table(struct amdgpu_device *adev)
633837d542aSEvan Quan {
634837d542aSEvan Quan struct amdgpu_dpm_dynamic_state *dyn_state = &adev->pm.dpm.dyn_state;
635837d542aSEvan Quan
636837d542aSEvan Quan kfree(dyn_state->vddc_dependency_on_sclk.entries);
637837d542aSEvan Quan kfree(dyn_state->vddci_dependency_on_mclk.entries);
638837d542aSEvan Quan kfree(dyn_state->vddc_dependency_on_mclk.entries);
639837d542aSEvan Quan kfree(dyn_state->mvdd_dependency_on_mclk.entries);
640837d542aSEvan Quan kfree(dyn_state->cac_leakage_table.entries);
641837d542aSEvan Quan kfree(dyn_state->phase_shedding_limits_table.entries);
642837d542aSEvan Quan kfree(dyn_state->ppm_table);
643837d542aSEvan Quan kfree(dyn_state->cac_tdp_table);
644837d542aSEvan Quan kfree(dyn_state->vce_clock_voltage_dependency_table.entries);
645837d542aSEvan Quan kfree(dyn_state->uvd_clock_voltage_dependency_table.entries);
646837d542aSEvan Quan kfree(dyn_state->samu_clock_voltage_dependency_table.entries);
647837d542aSEvan Quan kfree(dyn_state->acp_clock_voltage_dependency_table.entries);
648837d542aSEvan Quan kfree(dyn_state->vddgfx_dependency_on_sclk.entries);
649837d542aSEvan Quan }
650837d542aSEvan Quan
651837d542aSEvan Quan static const char *pp_lib_thermal_controller_names[] = {
652837d542aSEvan Quan "NONE",
653837d542aSEvan Quan "lm63",
654837d542aSEvan Quan "adm1032",
655837d542aSEvan Quan "adm1030",
656837d542aSEvan Quan "max6649",
657837d542aSEvan Quan "lm64",
658837d542aSEvan Quan "f75375",
659837d542aSEvan Quan "RV6xx",
660837d542aSEvan Quan "RV770",
661837d542aSEvan Quan "adt7473",
662837d542aSEvan Quan "NONE",
663837d542aSEvan Quan "External GPIO",
664837d542aSEvan Quan "Evergreen",
665837d542aSEvan Quan "emc2103",
666837d542aSEvan Quan "Sumo",
667837d542aSEvan Quan "Northern Islands",
668837d542aSEvan Quan "Southern Islands",
669837d542aSEvan Quan "lm96163",
670837d542aSEvan Quan "Sea Islands",
671837d542aSEvan Quan "Kaveri/Kabini",
672837d542aSEvan Quan };
673837d542aSEvan Quan
amdgpu_add_thermal_controller(struct amdgpu_device * adev)674837d542aSEvan Quan void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
675837d542aSEvan Quan {
676837d542aSEvan Quan struct amdgpu_mode_info *mode_info = &adev->mode_info;
677837d542aSEvan Quan ATOM_PPLIB_POWERPLAYTABLE *power_table;
678837d542aSEvan Quan int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
679837d542aSEvan Quan ATOM_PPLIB_THERMALCONTROLLER *controller;
680837d542aSEvan Quan struct amdgpu_i2c_bus_rec i2c_bus;
681837d542aSEvan Quan u16 data_offset;
682837d542aSEvan Quan u8 frev, crev;
683837d542aSEvan Quan
684837d542aSEvan Quan if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
685837d542aSEvan Quan &frev, &crev, &data_offset))
686837d542aSEvan Quan return;
687837d542aSEvan Quan power_table = (ATOM_PPLIB_POWERPLAYTABLE *)
688837d542aSEvan Quan (mode_info->atom_context->bios + data_offset);
689837d542aSEvan Quan controller = &power_table->sThermalController;
690837d542aSEvan Quan
691837d542aSEvan Quan /* add the i2c bus for thermal/fan chip */
692837d542aSEvan Quan if (controller->ucType > 0) {
693837d542aSEvan Quan if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
694837d542aSEvan Quan adev->pm.no_fan = true;
695837d542aSEvan Quan adev->pm.fan_pulses_per_revolution =
696837d542aSEvan Quan controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
697837d542aSEvan Quan if (adev->pm.fan_pulses_per_revolution) {
698837d542aSEvan Quan adev->pm.fan_min_rpm = controller->ucFanMinRPM;
699837d542aSEvan Quan adev->pm.fan_max_rpm = controller->ucFanMaxRPM;
700837d542aSEvan Quan }
701837d542aSEvan Quan if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
702837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
703837d542aSEvan Quan (controller->ucFanParameters &
704837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
705837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
706837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
707837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
708837d542aSEvan Quan (controller->ucFanParameters &
709837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
710837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_RV770;
711837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
712837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
713837d542aSEvan Quan (controller->ucFanParameters &
714837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
715837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
716837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
717837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
718837d542aSEvan Quan (controller->ucFanParameters &
719837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
720837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
721837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
722837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
723837d542aSEvan Quan (controller->ucFanParameters &
724837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
725837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_NI;
726837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
727837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
728837d542aSEvan Quan (controller->ucFanParameters &
729837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
730837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_SI;
731837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
732837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
733837d542aSEvan Quan (controller->ucFanParameters &
734837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
735837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_CI;
736837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
737837d542aSEvan Quan DRM_INFO("Internal thermal controller %s fan control\n",
738837d542aSEvan Quan (controller->ucFanParameters &
739837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
740837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_KV;
741837d542aSEvan Quan } else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
742837d542aSEvan Quan DRM_INFO("External GPIO thermal controller %s fan control\n",
743837d542aSEvan Quan (controller->ucFanParameters &
744837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
745837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
746837d542aSEvan Quan } else if (controller->ucType ==
747837d542aSEvan Quan ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
748837d542aSEvan Quan DRM_INFO("ADT7473 with internal thermal controller %s fan control\n",
749837d542aSEvan Quan (controller->ucFanParameters &
750837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
751837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
752837d542aSEvan Quan } else if (controller->ucType ==
753837d542aSEvan Quan ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
754837d542aSEvan Quan DRM_INFO("EMC2103 with internal thermal controller %s fan control\n",
755837d542aSEvan Quan (controller->ucFanParameters &
756837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
757837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
758837d542aSEvan Quan } else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
759837d542aSEvan Quan DRM_INFO("Possible %s thermal controller at 0x%02x %s fan control\n",
760837d542aSEvan Quan pp_lib_thermal_controller_names[controller->ucType],
761837d542aSEvan Quan controller->ucI2cAddress >> 1,
762837d542aSEvan Quan (controller->ucFanParameters &
763837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
764837d542aSEvan Quan adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL;
765837d542aSEvan Quan i2c_bus = amdgpu_atombios_lookup_i2c_gpio(adev, controller->ucI2cLine);
766837d542aSEvan Quan adev->pm.i2c_bus = amdgpu_i2c_lookup(adev, &i2c_bus);
767837d542aSEvan Quan if (adev->pm.i2c_bus) {
768837d542aSEvan Quan struct i2c_board_info info = { };
769837d542aSEvan Quan const char *name = pp_lib_thermal_controller_names[controller->ucType];
770837d542aSEvan Quan info.addr = controller->ucI2cAddress >> 1;
7717f09a3a0SAzeem Shaikh strscpy(info.type, name, sizeof(info.type));
772837d542aSEvan Quan i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info);
773837d542aSEvan Quan }
774837d542aSEvan Quan } else {
775837d542aSEvan Quan DRM_INFO("Unknown thermal controller type %d at 0x%02x %s fan control\n",
776837d542aSEvan Quan controller->ucType,
777837d542aSEvan Quan controller->ucI2cAddress >> 1,
778837d542aSEvan Quan (controller->ucFanParameters &
779837d542aSEvan Quan ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
780837d542aSEvan Quan }
781837d542aSEvan Quan }
782837d542aSEvan Quan }
783837d542aSEvan Quan
amdgpu_get_vce_clock_state(void * handle,u32 idx)784837d542aSEvan Quan struct amd_vce_state* amdgpu_get_vce_clock_state(void *handle, u32 idx)
785837d542aSEvan Quan {
786837d542aSEvan Quan struct amdgpu_device *adev = (struct amdgpu_device *)handle;
787837d542aSEvan Quan
788837d542aSEvan Quan if (idx < adev->pm.dpm.num_of_vce_states)
789837d542aSEvan Quan return &adev->pm.dpm.vce_states[idx];
790837d542aSEvan Quan
791837d542aSEvan Quan return NULL;
792837d542aSEvan Quan }
793837d542aSEvan Quan
amdgpu_dpm_pick_power_state(struct amdgpu_device * adev,enum amd_pm_state_type dpm_state)794837d542aSEvan Quan static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
795837d542aSEvan Quan enum amd_pm_state_type dpm_state)
796837d542aSEvan Quan {
797837d542aSEvan Quan int i;
798837d542aSEvan Quan struct amdgpu_ps *ps;
799837d542aSEvan Quan u32 ui_class;
800837d542aSEvan Quan bool single_display = (adev->pm.dpm.new_active_crtc_count < 2) ?
801837d542aSEvan Quan true : false;
802837d542aSEvan Quan
803837d542aSEvan Quan /* check if the vblank period is too short to adjust the mclk */
804837d542aSEvan Quan if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
805837d542aSEvan Quan if (amdgpu_dpm_vblank_too_short(adev))
806837d542aSEvan Quan single_display = false;
807837d542aSEvan Quan }
808837d542aSEvan Quan
809837d542aSEvan Quan /* certain older asics have a separare 3D performance state,
810837d542aSEvan Quan * so try that first if the user selected performance
811837d542aSEvan Quan */
812837d542aSEvan Quan if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
813837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
814837d542aSEvan Quan /* balanced states don't exist at the moment */
815837d542aSEvan Quan if (dpm_state == POWER_STATE_TYPE_BALANCED)
816837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_PERFORMANCE;
817837d542aSEvan Quan
818837d542aSEvan Quan restart_search:
819837d542aSEvan Quan /* Pick the best power state based on current conditions */
820837d542aSEvan Quan for (i = 0; i < adev->pm.dpm.num_ps; i++) {
821837d542aSEvan Quan ps = &adev->pm.dpm.ps[i];
822837d542aSEvan Quan ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
823837d542aSEvan Quan switch (dpm_state) {
824837d542aSEvan Quan /* user states */
825837d542aSEvan Quan case POWER_STATE_TYPE_BATTERY:
826837d542aSEvan Quan if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
827837d542aSEvan Quan if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
828837d542aSEvan Quan if (single_display)
829837d542aSEvan Quan return ps;
830837d542aSEvan Quan } else
831837d542aSEvan Quan return ps;
832837d542aSEvan Quan }
833837d542aSEvan Quan break;
834837d542aSEvan Quan case POWER_STATE_TYPE_PERFORMANCE:
835837d542aSEvan Quan if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
836837d542aSEvan Quan if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
837837d542aSEvan Quan if (single_display)
838837d542aSEvan Quan return ps;
839837d542aSEvan Quan } else
840837d542aSEvan Quan return ps;
841837d542aSEvan Quan }
842837d542aSEvan Quan break;
843837d542aSEvan Quan /* internal states */
844837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD:
845837d542aSEvan Quan if (adev->pm.dpm.uvd_ps)
846837d542aSEvan Quan return adev->pm.dpm.uvd_ps;
847837d542aSEvan Quan else
848837d542aSEvan Quan break;
849837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_SD:
850837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
851837d542aSEvan Quan return ps;
852837d542aSEvan Quan break;
853837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_HD:
854837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
855837d542aSEvan Quan return ps;
856837d542aSEvan Quan break;
857837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
858837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
859837d542aSEvan Quan return ps;
860837d542aSEvan Quan break;
861837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
862837d542aSEvan Quan if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
863837d542aSEvan Quan return ps;
864837d542aSEvan Quan break;
865837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_BOOT:
866837d542aSEvan Quan return adev->pm.dpm.boot_ps;
867837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_THERMAL:
868837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
869837d542aSEvan Quan return ps;
870837d542aSEvan Quan break;
871837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_ACPI:
872837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
873837d542aSEvan Quan return ps;
874837d542aSEvan Quan break;
875837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_ULV:
876837d542aSEvan Quan if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
877837d542aSEvan Quan return ps;
878837d542aSEvan Quan break;
879837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_3DPERF:
880837d542aSEvan Quan if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
881837d542aSEvan Quan return ps;
882837d542aSEvan Quan break;
883837d542aSEvan Quan default:
884837d542aSEvan Quan break;
885837d542aSEvan Quan }
886837d542aSEvan Quan }
887837d542aSEvan Quan /* use a fallback state if we didn't match */
888837d542aSEvan Quan switch (dpm_state) {
889837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_SD:
890837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
891837d542aSEvan Quan goto restart_search;
892837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_HD:
893837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
894837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
895837d542aSEvan Quan if (adev->pm.dpm.uvd_ps) {
896837d542aSEvan Quan return adev->pm.dpm.uvd_ps;
897837d542aSEvan Quan } else {
898837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_PERFORMANCE;
899837d542aSEvan Quan goto restart_search;
900837d542aSEvan Quan }
901837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_THERMAL:
902837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
903837d542aSEvan Quan goto restart_search;
904837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_ACPI:
905837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_BATTERY;
906837d542aSEvan Quan goto restart_search;
907837d542aSEvan Quan case POWER_STATE_TYPE_BATTERY:
908837d542aSEvan Quan case POWER_STATE_TYPE_BALANCED:
909837d542aSEvan Quan case POWER_STATE_TYPE_INTERNAL_3DPERF:
910837d542aSEvan Quan dpm_state = POWER_STATE_TYPE_PERFORMANCE;
911837d542aSEvan Quan goto restart_search;
912837d542aSEvan Quan default:
913837d542aSEvan Quan break;
914837d542aSEvan Quan }
915837d542aSEvan Quan
916837d542aSEvan Quan return NULL;
917837d542aSEvan Quan }
918837d542aSEvan Quan
amdgpu_dpm_change_power_state_locked(struct amdgpu_device * adev)919837d542aSEvan Quan static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
920837d542aSEvan Quan {
92161d7d0d5SEvan Quan const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
922837d542aSEvan Quan struct amdgpu_ps *ps;
923837d542aSEvan Quan enum amd_pm_state_type dpm_state;
924837d542aSEvan Quan int ret;
925837d542aSEvan Quan bool equal = false;
926837d542aSEvan Quan
927837d542aSEvan Quan /* if dpm init failed */
928837d542aSEvan Quan if (!adev->pm.dpm_enabled)
929837d542aSEvan Quan return 0;
930837d542aSEvan Quan
931837d542aSEvan Quan if (adev->pm.dpm.user_state != adev->pm.dpm.state) {
932837d542aSEvan Quan /* add other state override checks here */
933837d542aSEvan Quan if ((!adev->pm.dpm.thermal_active) &&
934837d542aSEvan Quan (!adev->pm.dpm.uvd_active))
935837d542aSEvan Quan adev->pm.dpm.state = adev->pm.dpm.user_state;
936837d542aSEvan Quan }
937837d542aSEvan Quan dpm_state = adev->pm.dpm.state;
938837d542aSEvan Quan
939837d542aSEvan Quan ps = amdgpu_dpm_pick_power_state(adev, dpm_state);
940837d542aSEvan Quan if (ps)
941837d542aSEvan Quan adev->pm.dpm.requested_ps = ps;
942837d542aSEvan Quan else
943837d542aSEvan Quan return -EINVAL;
944837d542aSEvan Quan
94561d7d0d5SEvan Quan if (amdgpu_dpm == 1 && pp_funcs->print_power_state) {
946837d542aSEvan Quan printk("switching from power state:\n");
947837d542aSEvan Quan amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
948837d542aSEvan Quan printk("switching to power state:\n");
949837d542aSEvan Quan amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
950837d542aSEvan Quan }
951837d542aSEvan Quan
952837d542aSEvan Quan /* update whether vce is active */
953837d542aSEvan Quan ps->vce_active = adev->pm.dpm.vce_active;
95461d7d0d5SEvan Quan if (pp_funcs->display_configuration_changed)
955837d542aSEvan Quan amdgpu_dpm_display_configuration_changed(adev);
956837d542aSEvan Quan
957837d542aSEvan Quan ret = amdgpu_dpm_pre_set_power_state(adev);
958837d542aSEvan Quan if (ret)
959837d542aSEvan Quan return ret;
960837d542aSEvan Quan
96161d7d0d5SEvan Quan if (pp_funcs->check_state_equal) {
962837d542aSEvan Quan if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal))
963837d542aSEvan Quan equal = false;
964837d542aSEvan Quan }
965837d542aSEvan Quan
966837d542aSEvan Quan if (equal)
967837d542aSEvan Quan return 0;
968837d542aSEvan Quan
96961d7d0d5SEvan Quan if (pp_funcs->set_power_state)
97061d7d0d5SEvan Quan pp_funcs->set_power_state(adev->powerplay.pp_handle);
971837d542aSEvan Quan
972837d542aSEvan Quan amdgpu_dpm_post_set_power_state(adev);
973837d542aSEvan Quan
974837d542aSEvan Quan adev->pm.dpm.current_active_crtcs = adev->pm.dpm.new_active_crtcs;
975837d542aSEvan Quan adev->pm.dpm.current_active_crtc_count = adev->pm.dpm.new_active_crtc_count;
976837d542aSEvan Quan
97761d7d0d5SEvan Quan if (pp_funcs->force_performance_level) {
978837d542aSEvan Quan if (adev->pm.dpm.thermal_active) {
979837d542aSEvan Quan enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
980837d542aSEvan Quan /* force low perf level for thermal */
98161d7d0d5SEvan Quan pp_funcs->force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
982837d542aSEvan Quan /* save the user's level */
983837d542aSEvan Quan adev->pm.dpm.forced_level = level;
984837d542aSEvan Quan } else {
985837d542aSEvan Quan /* otherwise, user selected level */
98661d7d0d5SEvan Quan pp_funcs->force_performance_level(adev, adev->pm.dpm.forced_level);
987837d542aSEvan Quan }
988837d542aSEvan Quan }
989837d542aSEvan Quan
990837d542aSEvan Quan return 0;
991837d542aSEvan Quan }
992837d542aSEvan Quan
amdgpu_legacy_dpm_compute_clocks(void * handle)993837d542aSEvan Quan void amdgpu_legacy_dpm_compute_clocks(void *handle)
994837d542aSEvan Quan {
995837d542aSEvan Quan struct amdgpu_device *adev = (struct amdgpu_device *)handle;
996837d542aSEvan Quan
997837d542aSEvan Quan amdgpu_dpm_get_active_displays(adev);
998837d542aSEvan Quan
999837d542aSEvan Quan amdgpu_dpm_change_power_state_locked(adev);
1000837d542aSEvan Quan }
1001837d542aSEvan Quan
amdgpu_dpm_thermal_work_handler(struct work_struct * work)1002837d542aSEvan Quan void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
1003837d542aSEvan Quan {
1004837d542aSEvan Quan struct amdgpu_device *adev =
1005837d542aSEvan Quan container_of(work, struct amdgpu_device,
1006837d542aSEvan Quan pm.dpm.thermal.work);
1007837d542aSEvan Quan const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
1008837d542aSEvan Quan /* switch to the thermal state */
1009837d542aSEvan Quan enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
1010837d542aSEvan Quan int temp, size = sizeof(temp);
1011837d542aSEvan Quan
1012837d542aSEvan Quan if (!adev->pm.dpm_enabled)
1013837d542aSEvan Quan return;
1014837d542aSEvan Quan
1015837d542aSEvan Quan if (!pp_funcs->read_sensor(adev->powerplay.pp_handle,
1016837d542aSEvan Quan AMDGPU_PP_SENSOR_GPU_TEMP,
1017837d542aSEvan Quan (void *)&temp,
1018837d542aSEvan Quan &size)) {
1019837d542aSEvan Quan if (temp < adev->pm.dpm.thermal.min_temp)
1020837d542aSEvan Quan /* switch back the user state */
1021837d542aSEvan Quan dpm_state = adev->pm.dpm.user_state;
1022837d542aSEvan Quan } else {
1023837d542aSEvan Quan if (adev->pm.dpm.thermal.high_to_low)
1024837d542aSEvan Quan /* switch back the user state */
1025837d542aSEvan Quan dpm_state = adev->pm.dpm.user_state;
1026837d542aSEvan Quan }
1027837d542aSEvan Quan
1028837d542aSEvan Quan if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
1029837d542aSEvan Quan adev->pm.dpm.thermal_active = true;
1030837d542aSEvan Quan else
1031837d542aSEvan Quan adev->pm.dpm.thermal_active = false;
1032837d542aSEvan Quan
1033837d542aSEvan Quan adev->pm.dpm.state = dpm_state;
1034837d542aSEvan Quan
1035837d542aSEvan Quan amdgpu_legacy_dpm_compute_clocks(adev->powerplay.pp_handle);
1036837d542aSEvan Quan }
1037