xref: /linux/drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_processpptables.c (revision 7f4f3b14e8079ecde096bd734af10e30d40c27b7)
1 /*
2  * Copyright 2018 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20  * OTHER DEALINGS IN THE SOFTWARE.
21  *
22  */
23 #include <linux/module.h>
24 #include <linux/slab.h>
25 
26 #include "smu11_driver_if.h"
27 #include "vega20_processpptables.h"
28 #include "ppatomfwctrl.h"
29 #include "atomfirmware.h"
30 #include "pp_debug.h"
31 #include "cgs_common.h"
32 #include "vega20_pptable.h"
33 
34 #define VEGA20_FAN_TARGET_TEMPERATURE_OVERRIDE 105
35 
36 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
37 		enum phm_platform_caps cap)
38 {
39 	if (enable)
40 		phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
41 	else
42 		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
43 }
44 
45 static const void *get_powerplay_table(struct pp_hwmgr *hwmgr)
46 {
47 	int index = GetIndexIntoMasterDataTable(powerplayinfo);
48 
49 	u16 size;
50 	u8 frev, crev;
51 	const void *table_address = hwmgr->soft_pp_table;
52 
53 	if (!table_address) {
54 		table_address = (ATOM_Vega20_POWERPLAYTABLE *)
55 				smu_atom_get_data_table(hwmgr->adev, index,
56 						&size, &frev, &crev);
57 
58 		hwmgr->soft_pp_table = table_address;
59 		hwmgr->soft_pp_table_size = size;
60 	}
61 
62 	return table_address;
63 }
64 
65 static int check_powerplay_tables(
66 		struct pp_hwmgr *hwmgr,
67 		const ATOM_Vega20_POWERPLAYTABLE *powerplay_table)
68 {
69 	PP_ASSERT_WITH_CODE((powerplay_table->sHeader.format_revision >=
70 		ATOM_VEGA20_TABLE_REVISION_VEGA20),
71 		"Unsupported PPTable format!", return -1);
72 	PP_ASSERT_WITH_CODE(powerplay_table->sHeader.structuresize > 0,
73 		"Invalid PowerPlay Table!", return -1);
74 
75 	if (powerplay_table->smcPPTable.Version != PPTABLE_V20_SMU_VERSION) {
76 		pr_info("Unmatch PPTable version: "
77 			"pptable from VBIOS is V%d while driver supported is V%d!",
78 			powerplay_table->smcPPTable.Version,
79 			PPTABLE_V20_SMU_VERSION);
80 		return -EINVAL;
81 	}
82 
83 	return 0;
84 }
85 
86 static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps)
87 {
88 	set_hw_cap(
89 		hwmgr,
90 		0 != (powerplay_caps & ATOM_VEGA20_PP_PLATFORM_CAP_POWERPLAY),
91 		PHM_PlatformCaps_PowerPlaySupport);
92 
93 	set_hw_cap(
94 		hwmgr,
95 		0 != (powerplay_caps & ATOM_VEGA20_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
96 		PHM_PlatformCaps_BiosPowerSourceControl);
97 
98 	set_hw_cap(
99 		hwmgr,
100 		0 != (powerplay_caps & ATOM_VEGA20_PP_PLATFORM_CAP_BACO),
101 		PHM_PlatformCaps_BACO);
102 
103 	set_hw_cap(
104 		hwmgr,
105 		0 != (powerplay_caps & ATOM_VEGA20_PP_PLATFORM_CAP_BAMACO),
106 		 PHM_PlatformCaps_BAMACO);
107 
108 	return 0;
109 }
110 
111 static int copy_overdrive_feature_capabilities_array(
112 		struct pp_hwmgr *hwmgr,
113 		uint8_t **pptable_info_array,
114 		const uint8_t *pptable_array,
115 		uint8_t od_feature_count)
116 {
117 	uint32_t array_size, i;
118 	uint8_t *table;
119 	bool od_supported = false;
120 
121 	array_size = sizeof(uint8_t) * od_feature_count;
122 	table = kzalloc(array_size, GFP_KERNEL);
123 	if (NULL == table)
124 		return -ENOMEM;
125 
126 	for (i = 0; i < od_feature_count; i++) {
127 		table[i] = le32_to_cpu(pptable_array[i]);
128 		if (table[i])
129 			od_supported = true;
130 	}
131 
132 	*pptable_info_array = table;
133 
134 	if (od_supported)
135 		phm_cap_set(hwmgr->platform_descriptor.platformCaps,
136 				PHM_PlatformCaps_ACOverdriveSupport);
137 
138 	return 0;
139 }
140 
141 static int append_vbios_pptable(struct pp_hwmgr *hwmgr, PPTable_t *ppsmc_pptable)
142 {
143 	struct atom_smc_dpm_info_v4_4 *smc_dpm_table;
144 	int index = GetIndexIntoMasterDataTable(smc_dpm_info);
145 	int i;
146 
147 	PP_ASSERT_WITH_CODE(
148 		smc_dpm_table = smu_atom_get_data_table(hwmgr->adev, index, NULL, NULL, NULL),
149 		"[appendVbiosPPTable] Failed to retrieve Smc Dpm Table from VBIOS!",
150 		return -1);
151 
152 	ppsmc_pptable->MaxVoltageStepGfx = smc_dpm_table->maxvoltagestepgfx;
153 	ppsmc_pptable->MaxVoltageStepSoc = smc_dpm_table->maxvoltagestepsoc;
154 
155 	ppsmc_pptable->VddGfxVrMapping = smc_dpm_table->vddgfxvrmapping;
156 	ppsmc_pptable->VddSocVrMapping = smc_dpm_table->vddsocvrmapping;
157 	ppsmc_pptable->VddMem0VrMapping = smc_dpm_table->vddmem0vrmapping;
158 	ppsmc_pptable->VddMem1VrMapping = smc_dpm_table->vddmem1vrmapping;
159 
160 	ppsmc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->gfxulvphasesheddingmask;
161 	ppsmc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->soculvphasesheddingmask;
162 	ppsmc_pptable->ExternalSensorPresent = smc_dpm_table->externalsensorpresent;
163 
164 	ppsmc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent;
165 	ppsmc_pptable->GfxOffset = smc_dpm_table->gfxoffset;
166 	ppsmc_pptable->Padding_TelemetryGfx = smc_dpm_table->padding_telemetrygfx;
167 
168 	ppsmc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent;
169 	ppsmc_pptable->SocOffset = smc_dpm_table->socoffset;
170 	ppsmc_pptable->Padding_TelemetrySoc = smc_dpm_table->padding_telemetrysoc;
171 
172 	ppsmc_pptable->Mem0MaxCurrent = smc_dpm_table->mem0maxcurrent;
173 	ppsmc_pptable->Mem0Offset = smc_dpm_table->mem0offset;
174 	ppsmc_pptable->Padding_TelemetryMem0 = smc_dpm_table->padding_telemetrymem0;
175 
176 	ppsmc_pptable->Mem1MaxCurrent = smc_dpm_table->mem1maxcurrent;
177 	ppsmc_pptable->Mem1Offset = smc_dpm_table->mem1offset;
178 	ppsmc_pptable->Padding_TelemetryMem1 = smc_dpm_table->padding_telemetrymem1;
179 
180 	ppsmc_pptable->AcDcGpio = smc_dpm_table->acdcgpio;
181 	ppsmc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity;
182 	ppsmc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio;
183 	ppsmc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity;
184 
185 	ppsmc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio;
186 	ppsmc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity;
187 	ppsmc_pptable->Padding1 = smc_dpm_table->padding1;
188 	ppsmc_pptable->Padding2 = smc_dpm_table->padding2;
189 
190 	ppsmc_pptable->LedPin0 = smc_dpm_table->ledpin0;
191 	ppsmc_pptable->LedPin1 = smc_dpm_table->ledpin1;
192 	ppsmc_pptable->LedPin2 = smc_dpm_table->ledpin2;
193 
194 	ppsmc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->pllgfxclkspreadenabled;
195 	ppsmc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->pllgfxclkspreadpercent;
196 	ppsmc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->pllgfxclkspreadfreq;
197 
198 	ppsmc_pptable->UclkSpreadEnabled = 0;
199 	ppsmc_pptable->UclkSpreadPercent = smc_dpm_table->uclkspreadpercent;
200 	ppsmc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq;
201 
202 	ppsmc_pptable->FclkSpreadEnabled = smc_dpm_table->fclkspreadenabled;
203 	ppsmc_pptable->FclkSpreadPercent = smc_dpm_table->fclkspreadpercent;
204 	ppsmc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq;
205 
206 	ppsmc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table->fllgfxclkspreadenabled;
207 	ppsmc_pptable->FllGfxclkSpreadPercent = smc_dpm_table->fllgfxclkspreadpercent;
208 	ppsmc_pptable->FllGfxclkSpreadFreq = smc_dpm_table->fllgfxclkspreadfreq;
209 
210 	for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) {
211 		ppsmc_pptable->I2cControllers[i].Enabled =
212 			smc_dpm_table->i2ccontrollers[i].enabled;
213 		ppsmc_pptable->I2cControllers[i].SlaveAddress =
214 			smc_dpm_table->i2ccontrollers[i].slaveaddress;
215 		ppsmc_pptable->I2cControllers[i].ControllerPort =
216 			smc_dpm_table->i2ccontrollers[i].controllerport;
217 		ppsmc_pptable->I2cControllers[i].ThermalThrottler =
218 			smc_dpm_table->i2ccontrollers[i].thermalthrottler;
219 		ppsmc_pptable->I2cControllers[i].I2cProtocol =
220 			smc_dpm_table->i2ccontrollers[i].i2cprotocol;
221 		ppsmc_pptable->I2cControllers[i].I2cSpeed =
222 			smc_dpm_table->i2ccontrollers[i].i2cspeed;
223 	}
224 
225 	return 0;
226 }
227 
228 static int override_powerplay_table_fantargettemperature(struct pp_hwmgr *hwmgr)
229 {
230 	struct phm_ppt_v3_information *pptable_information =
231 		(struct phm_ppt_v3_information *)hwmgr->pptable;
232 	PPTable_t *ppsmc_pptable = (PPTable_t *)(pptable_information->smc_pptable);
233 
234 	ppsmc_pptable->FanTargetTemperature = VEGA20_FAN_TARGET_TEMPERATURE_OVERRIDE;
235 
236 	return 0;
237 }
238 
239 #define VEGA20_ENGINECLOCK_HARDMAX 198000
240 static int init_powerplay_table_information(
241 		struct pp_hwmgr *hwmgr,
242 		const ATOM_Vega20_POWERPLAYTABLE *powerplay_table)
243 {
244 	struct phm_ppt_v3_information *pptable_information =
245 		(struct phm_ppt_v3_information *)hwmgr->pptable;
246 	uint32_t disable_power_control = 0;
247 	uint32_t od_feature_count, od_setting_count, power_saving_clock_count;
248 	int result;
249 
250 	hwmgr->thermal_controller.ucType = powerplay_table->ucThermalControllerType;
251 	pptable_information->uc_thermal_controller_type = powerplay_table->ucThermalControllerType;
252 	hwmgr->thermal_controller.fanInfo.ulMinRPM = 0;
253 	hwmgr->thermal_controller.fanInfo.ulMaxRPM = powerplay_table->smcPPTable.FanMaximumRpm;
254 
255 	set_hw_cap(hwmgr,
256 		ATOM_VEGA20_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
257 		PHM_PlatformCaps_ThermalController);
258 
259 	phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
260 
261 	if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) {
262 		od_feature_count =
263 			(le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) >
264 			 ATOM_VEGA20_ODFEATURE_COUNT) ?
265 			ATOM_VEGA20_ODFEATURE_COUNT :
266 			le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount);
267 		od_setting_count =
268 			(le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) >
269 			 ATOM_VEGA20_ODSETTING_COUNT) ?
270 			ATOM_VEGA20_ODSETTING_COUNT :
271 			le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount);
272 
273 		copy_overdrive_feature_capabilities_array(hwmgr,
274 				&pptable_information->od_feature_capabilities,
275 				powerplay_table->OverDrive8Table.ODFeatureCapabilities,
276 				od_feature_count);
277 		phm_copy_overdrive_settings_limits_array(hwmgr,
278 				&pptable_information->od_settings_max,
279 				powerplay_table->OverDrive8Table.ODSettingsMax,
280 				od_setting_count);
281 		phm_copy_overdrive_settings_limits_array(hwmgr,
282 				&pptable_information->od_settings_min,
283 				powerplay_table->OverDrive8Table.ODSettingsMin,
284 				od_setting_count);
285 	}
286 
287 	pptable_information->us_small_power_limit1 = le16_to_cpu(powerplay_table->usSmallPowerLimit1);
288 	pptable_information->us_small_power_limit2 = le16_to_cpu(powerplay_table->usSmallPowerLimit2);
289 	pptable_information->us_boost_power_limit = le16_to_cpu(powerplay_table->usBoostPowerLimit);
290 	pptable_information->us_od_turbo_power_limit = le16_to_cpu(powerplay_table->usODTurboPowerLimit);
291 	pptable_information->us_od_powersave_power_limit = le16_to_cpu(powerplay_table->usODPowerSavePowerLimit);
292 
293 	pptable_information->us_software_shutdown_temp = le16_to_cpu(powerplay_table->usSoftwareShutdownTemp);
294 
295 	hwmgr->platform_descriptor.TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]);
296 
297 	disable_power_control = 0;
298 	if (!disable_power_control && hwmgr->platform_descriptor.TDPODLimit)
299 		/* enable TDP overdrive (PowerControl) feature as well if supported */
300 		phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_PowerControl);
301 
302 	if (powerplay_table->PowerSavingClockTable.ucTableRevision == 1) {
303 		power_saving_clock_count =
304 			(le32_to_cpu(powerplay_table->PowerSavingClockTable.PowerSavingClockCount) >=
305 			 ATOM_VEGA20_PPCLOCK_COUNT) ?
306 			ATOM_VEGA20_PPCLOCK_COUNT :
307 			le32_to_cpu(powerplay_table->PowerSavingClockTable.PowerSavingClockCount);
308 		phm_copy_clock_limits_array(hwmgr,
309 				&pptable_information->power_saving_clock_max,
310 				powerplay_table->PowerSavingClockTable.PowerSavingClockMax,
311 				power_saving_clock_count);
312 		phm_copy_clock_limits_array(hwmgr,
313 				&pptable_information->power_saving_clock_min,
314 				powerplay_table->PowerSavingClockTable.PowerSavingClockMin,
315 				power_saving_clock_count);
316 	}
317 
318 	pptable_information->smc_pptable = kmemdup(&(powerplay_table->smcPPTable),
319 						   sizeof(PPTable_t),
320 						   GFP_KERNEL);
321 	if (pptable_information->smc_pptable == NULL)
322 		return -ENOMEM;
323 
324 
325 	result = append_vbios_pptable(hwmgr, (pptable_information->smc_pptable));
326 	if (result)
327 		return result;
328 
329 	result = override_powerplay_table_fantargettemperature(hwmgr);
330 
331 	return result;
332 }
333 
334 static int vega20_pp_tables_initialize(struct pp_hwmgr *hwmgr)
335 {
336 	int result = 0;
337 	const ATOM_Vega20_POWERPLAYTABLE *powerplay_table;
338 
339 	hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v3_information), GFP_KERNEL);
340 	PP_ASSERT_WITH_CODE((hwmgr->pptable != NULL),
341 		"Failed to allocate hwmgr->pptable!", return -ENOMEM);
342 
343 	powerplay_table = get_powerplay_table(hwmgr);
344 	PP_ASSERT_WITH_CODE((powerplay_table != NULL),
345 		"Missing PowerPlay Table!", return -1);
346 
347 	result = check_powerplay_tables(hwmgr, powerplay_table);
348 	PP_ASSERT_WITH_CODE((result == 0),
349 		"check_powerplay_tables failed", return result);
350 
351 	result = set_platform_caps(hwmgr,
352 			le32_to_cpu(powerplay_table->ulPlatformCaps));
353 	PP_ASSERT_WITH_CODE((result == 0),
354 		"set_platform_caps failed", return result);
355 
356 	result = init_powerplay_table_information(hwmgr, powerplay_table);
357 	PP_ASSERT_WITH_CODE((result == 0),
358 		"init_powerplay_table_information failed", return result);
359 
360 	return result;
361 }
362 
363 static int vega20_pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
364 {
365 	struct phm_ppt_v3_information *pp_table_info =
366 			(struct phm_ppt_v3_information *)(hwmgr->pptable);
367 
368 	kfree(pp_table_info->power_saving_clock_max);
369 	pp_table_info->power_saving_clock_max = NULL;
370 
371 	kfree(pp_table_info->power_saving_clock_min);
372 	pp_table_info->power_saving_clock_min = NULL;
373 
374 	kfree(pp_table_info->od_feature_capabilities);
375 	pp_table_info->od_feature_capabilities = NULL;
376 
377 	kfree(pp_table_info->od_settings_max);
378 	pp_table_info->od_settings_max = NULL;
379 
380 	kfree(pp_table_info->od_settings_min);
381 	pp_table_info->od_settings_min = NULL;
382 
383 	kfree(pp_table_info->smc_pptable);
384 	pp_table_info->smc_pptable = NULL;
385 
386 	kfree(hwmgr->pptable);
387 	hwmgr->pptable = NULL;
388 
389 	return 0;
390 }
391 
392 const struct pp_table_func vega20_pptable_funcs = {
393 	.pptable_init = vega20_pp_tables_initialize,
394 	.pptable_fini = vega20_pp_tables_uninitialize,
395 };
396