xref: /linux/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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