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
set_hw_cap(struct pp_hwmgr * hwmgr,bool enable,enum phm_platform_caps cap)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
get_powerplay_table(struct pp_hwmgr * hwmgr)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
check_powerplay_tables(struct pp_hwmgr * hwmgr,const ATOM_Vega20_POWERPLAYTABLE * powerplay_table)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
set_platform_caps(struct pp_hwmgr * hwmgr,uint32_t powerplay_caps)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
copy_overdrive_feature_capabilities_array(struct pp_hwmgr * hwmgr,uint8_t ** pptable_info_array,const uint8_t * pptable_array,uint8_t od_feature_count)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
append_vbios_pptable(struct pp_hwmgr * hwmgr,PPTable_t * ppsmc_pptable)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
override_powerplay_table_fantargettemperature(struct pp_hwmgr * hwmgr)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
init_powerplay_table_information(struct pp_hwmgr * hwmgr,const ATOM_Vega20_POWERPLAYTABLE * powerplay_table)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
vega20_pp_tables_initialize(struct pp_hwmgr * hwmgr)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
vega20_pp_tables_uninitialize(struct pp_hwmgr * hwmgr)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