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