1 /* 2 * Copyright 2015 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 "pp_debug.h" 24 #include <linux/module.h> 25 #include <linux/slab.h> 26 #include <linux/delay.h> 27 #include "atom.h" 28 #include "ppatomctrl.h" 29 #include "atombios.h" 30 #include "cgs_common.h" 31 #include "ppevvmath.h" 32 33 #define MEM_ID_MASK 0xff000000 34 #define MEM_ID_SHIFT 24 35 #define CLOCK_RANGE_MASK 0x00ffffff 36 #define CLOCK_RANGE_SHIFT 0 37 #define LOW_NIBBLE_MASK 0xf 38 #define DATA_EQU_PREV 0 39 #define DATA_FROM_TABLE 4 40 41 union voltage_object_info { 42 struct _ATOM_VOLTAGE_OBJECT_INFO v1; 43 struct _ATOM_VOLTAGE_OBJECT_INFO_V2 v2; 44 struct _ATOM_VOLTAGE_OBJECT_INFO_V3_1 v3; 45 }; 46 47 static int atomctrl_retrieve_ac_timing( 48 uint8_t index, 49 ATOM_INIT_REG_BLOCK *reg_block, 50 pp_atomctrl_mc_reg_table *table) 51 { 52 uint32_t i, j; 53 uint8_t tmem_id; 54 ATOM_MEMORY_SETTING_DATA_BLOCK *reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) 55 ((uint8_t *)reg_block + (2 * sizeof(uint16_t)) + le16_to_cpu(reg_block->usRegIndexTblSize)); 56 57 uint8_t num_ranges = 0; 58 59 while (*(uint32_t *)reg_data != END_OF_REG_DATA_BLOCK && 60 num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES) { 61 tmem_id = (uint8_t)((*(uint32_t *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT); 62 63 if (index == tmem_id) { 64 table->mc_reg_table_entry[num_ranges].mclk_max = 65 (uint32_t)((*(uint32_t *)reg_data & CLOCK_RANGE_MASK) >> 66 CLOCK_RANGE_SHIFT); 67 68 for (i = 0, j = 1; i < table->last; i++) { 69 if ((table->mc_reg_address[i].uc_pre_reg_data & 70 LOW_NIBBLE_MASK) == DATA_FROM_TABLE) { 71 table->mc_reg_table_entry[num_ranges].mc_data[i] = 72 (uint32_t)*((uint32_t *)reg_data + j); 73 j++; 74 } else if ((table->mc_reg_address[i].uc_pre_reg_data & 75 LOW_NIBBLE_MASK) == DATA_EQU_PREV) { 76 table->mc_reg_table_entry[num_ranges].mc_data[i] = 77 table->mc_reg_table_entry[num_ranges].mc_data[i-1]; 78 } 79 } 80 num_ranges++; 81 } 82 83 reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *) 84 ((uint8_t *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize)) ; 85 } 86 87 PP_ASSERT_WITH_CODE((*(uint32_t *)reg_data == END_OF_REG_DATA_BLOCK), 88 "Invalid VramInfo table.", return -1); 89 table->num_entries = num_ranges; 90 91 return 0; 92 } 93 94 /** 95 * atomctrl_set_mc_reg_address_table - Get memory clock AC timing registers index from VBIOS table 96 * VBIOS set end of memory clock AC timing registers by ucPreRegDataLength bit6 = 1 97 * @reg_block: the address ATOM_INIT_REG_BLOCK 98 * @table: the address of MCRegTable 99 * Return: 0 100 */ 101 static int atomctrl_set_mc_reg_address_table( 102 ATOM_INIT_REG_BLOCK *reg_block, 103 pp_atomctrl_mc_reg_table *table) 104 { 105 uint8_t i = 0; 106 uint8_t num_entries = (uint8_t)((le16_to_cpu(reg_block->usRegIndexTblSize)) 107 / sizeof(ATOM_INIT_REG_INDEX_FORMAT)); 108 ATOM_INIT_REG_INDEX_FORMAT *format = ®_block->asRegIndexBuf[0]; 109 110 num_entries--; /* subtract 1 data end mark entry */ 111 112 PP_ASSERT_WITH_CODE((num_entries <= VBIOS_MC_REGISTER_ARRAY_SIZE), 113 "Invalid VramInfo table.", return -1); 114 115 /* ucPreRegDataLength bit6 = 1 is the end of memory clock AC timing registers */ 116 while ((!(format->ucPreRegDataLength & ACCESS_PLACEHOLDER)) && 117 (i < num_entries)) { 118 table->mc_reg_address[i].s1 = 119 (uint16_t)(le16_to_cpu(format->usRegIndex)); 120 table->mc_reg_address[i].uc_pre_reg_data = 121 format->ucPreRegDataLength; 122 123 i++; 124 format = (ATOM_INIT_REG_INDEX_FORMAT *) 125 ((uint8_t *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT)); 126 } 127 128 table->last = i; 129 return 0; 130 } 131 132 int atomctrl_initialize_mc_reg_table( 133 struct pp_hwmgr *hwmgr, 134 uint8_t module_index, 135 pp_atomctrl_mc_reg_table *table) 136 { 137 ATOM_VRAM_INFO_HEADER_V2_1 *vram_info; 138 ATOM_INIT_REG_BLOCK *reg_block; 139 int result = 0; 140 u8 frev, crev; 141 u16 size; 142 143 vram_info = (ATOM_VRAM_INFO_HEADER_V2_1 *) 144 smu_atom_get_data_table(hwmgr->adev, 145 GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev); 146 147 if (module_index >= vram_info->ucNumOfVRAMModule) { 148 pr_err("Invalid VramInfo table."); 149 result = -1; 150 } else if (vram_info->sHeader.ucTableFormatRevision < 2) { 151 pr_err("Invalid VramInfo table."); 152 result = -1; 153 } 154 155 if (0 == result) { 156 reg_block = (ATOM_INIT_REG_BLOCK *) 157 ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset)); 158 result = atomctrl_set_mc_reg_address_table(reg_block, table); 159 } 160 161 if (0 == result) { 162 result = atomctrl_retrieve_ac_timing(module_index, 163 reg_block, table); 164 } 165 166 return result; 167 } 168 169 int atomctrl_initialize_mc_reg_table_v2_2( 170 struct pp_hwmgr *hwmgr, 171 uint8_t module_index, 172 pp_atomctrl_mc_reg_table *table) 173 { 174 ATOM_VRAM_INFO_HEADER_V2_2 *vram_info; 175 ATOM_INIT_REG_BLOCK *reg_block; 176 int result = 0; 177 u8 frev, crev; 178 u16 size; 179 180 vram_info = (ATOM_VRAM_INFO_HEADER_V2_2 *) 181 smu_atom_get_data_table(hwmgr->adev, 182 GetIndexIntoMasterTable(DATA, VRAM_Info), &size, &frev, &crev); 183 184 if (module_index >= vram_info->ucNumOfVRAMModule) { 185 pr_err("Invalid VramInfo table."); 186 result = -1; 187 } else if (vram_info->sHeader.ucTableFormatRevision < 2) { 188 pr_err("Invalid VramInfo table."); 189 result = -1; 190 } 191 192 if (0 == result) { 193 reg_block = (ATOM_INIT_REG_BLOCK *) 194 ((uint8_t *)vram_info + le16_to_cpu(vram_info->usMemClkPatchTblOffset)); 195 result = atomctrl_set_mc_reg_address_table(reg_block, table); 196 } 197 198 if (0 == result) { 199 result = atomctrl_retrieve_ac_timing(module_index, 200 reg_block, table); 201 } 202 203 return result; 204 } 205 206 /* 207 * Set DRAM timings based on engine clock and memory clock. 208 */ 209 int atomctrl_set_engine_dram_timings_rv770( 210 struct pp_hwmgr *hwmgr, 211 uint32_t engine_clock, 212 uint32_t memory_clock) 213 { 214 struct amdgpu_device *adev = hwmgr->adev; 215 216 SET_ENGINE_CLOCK_PS_ALLOCATION engine_clock_parameters; 217 218 /* They are both in 10KHz Units. */ 219 engine_clock_parameters.ulTargetEngineClock = 220 cpu_to_le32((engine_clock & SET_CLOCK_FREQ_MASK) | 221 ((COMPUTE_ENGINE_PLL_PARAM << 24))); 222 223 /* in 10 khz units.*/ 224 engine_clock_parameters.sReserved.ulClock = 225 cpu_to_le32(memory_clock & SET_CLOCK_FREQ_MASK); 226 227 return amdgpu_atom_execute_table(adev->mode_info.atom_context, 228 GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings), 229 (uint32_t *)&engine_clock_parameters); 230 } 231 232 /* 233 * Private Function to get the PowerPlay Table Address. 234 * WARNING: The tabled returned by this function is in 235 * dynamically allocated memory. 236 * The caller has to release if by calling kfree. 237 */ 238 static ATOM_VOLTAGE_OBJECT_INFO *get_voltage_info_table(void *device) 239 { 240 int index = GetIndexIntoMasterTable(DATA, VoltageObjectInfo); 241 u8 frev, crev; 242 u16 size; 243 union voltage_object_info *voltage_info; 244 245 voltage_info = (union voltage_object_info *) 246 smu_atom_get_data_table(device, index, 247 &size, &frev, &crev); 248 249 if (voltage_info != NULL) 250 return (ATOM_VOLTAGE_OBJECT_INFO *) &(voltage_info->v3); 251 else 252 return NULL; 253 } 254 255 static const ATOM_VOLTAGE_OBJECT_V3 *atomctrl_lookup_voltage_type_v3( 256 const ATOM_VOLTAGE_OBJECT_INFO_V3_1 * voltage_object_info_table, 257 uint8_t voltage_type, uint8_t voltage_mode) 258 { 259 unsigned int size = le16_to_cpu(voltage_object_info_table->sHeader.usStructureSize); 260 unsigned int offset = offsetof(ATOM_VOLTAGE_OBJECT_INFO_V3_1, asVoltageObj[0]); 261 uint8_t *start = (uint8_t *)voltage_object_info_table; 262 263 while (offset < size) { 264 const ATOM_VOLTAGE_OBJECT_V3 *voltage_object = 265 (const ATOM_VOLTAGE_OBJECT_V3 *)(start + offset); 266 267 if (voltage_type == voltage_object->asGpioVoltageObj.sHeader.ucVoltageType && 268 voltage_mode == voltage_object->asGpioVoltageObj.sHeader.ucVoltageMode) 269 return voltage_object; 270 271 offset += le16_to_cpu(voltage_object->asGpioVoltageObj.sHeader.usSize); 272 } 273 274 return NULL; 275 } 276 277 /** 278 * atomctrl_get_memory_pll_dividers_si(). 279 * 280 * @hwmgr: input parameter: pointer to HwMgr 281 * @clock_value: input parameter: memory clock 282 * @mpll_param: output parameter: memory clock parameters 283 * @strobe_mode: input parameter: 1 for strobe mode, 0 for performance mode 284 */ 285 int atomctrl_get_memory_pll_dividers_si( 286 struct pp_hwmgr *hwmgr, 287 uint32_t clock_value, 288 pp_atomctrl_memory_clock_param *mpll_param, 289 bool strobe_mode) 290 { 291 struct amdgpu_device *adev = hwmgr->adev; 292 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_1 mpll_parameters; 293 int result; 294 295 mpll_parameters.ulClock = cpu_to_le32(clock_value); 296 mpll_parameters.ucInputFlag = (uint8_t)((strobe_mode) ? 1 : 0); 297 298 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 299 GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), 300 (uint32_t *)&mpll_parameters); 301 302 if (0 == result) { 303 mpll_param->mpll_fb_divider.clk_frac = 304 le16_to_cpu(mpll_parameters.ulFbDiv.usFbDivFrac); 305 mpll_param->mpll_fb_divider.cl_kf = 306 le16_to_cpu(mpll_parameters.ulFbDiv.usFbDiv); 307 mpll_param->mpll_post_divider = 308 (uint32_t)mpll_parameters.ucPostDiv; 309 mpll_param->vco_mode = 310 (uint32_t)(mpll_parameters.ucPllCntlFlag & 311 MPLL_CNTL_FLAG_VCO_MODE_MASK); 312 mpll_param->yclk_sel = 313 (uint32_t)((mpll_parameters.ucPllCntlFlag & 314 MPLL_CNTL_FLAG_BYPASS_DQ_PLL) ? 1 : 0); 315 mpll_param->qdr = 316 (uint32_t)((mpll_parameters.ucPllCntlFlag & 317 MPLL_CNTL_FLAG_QDR_ENABLE) ? 1 : 0); 318 mpll_param->half_rate = 319 (uint32_t)((mpll_parameters.ucPllCntlFlag & 320 MPLL_CNTL_FLAG_AD_HALF_RATE) ? 1 : 0); 321 mpll_param->dll_speed = 322 (uint32_t)(mpll_parameters.ucDllSpeed); 323 mpll_param->bw_ctrl = 324 (uint32_t)(mpll_parameters.ucBWCntl); 325 } 326 327 return result; 328 } 329 330 /** 331 * atomctrl_get_memory_pll_dividers_vi(). 332 * 333 * @hwmgr: input parameter: pointer to HwMgr 334 * @clock_value: input parameter: memory clock 335 * @mpll_param: output parameter: memory clock parameters 336 */ 337 int atomctrl_get_memory_pll_dividers_vi(struct pp_hwmgr *hwmgr, 338 uint32_t clock_value, pp_atomctrl_memory_clock_param *mpll_param) 339 { 340 struct amdgpu_device *adev = hwmgr->adev; 341 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_2 mpll_parameters; 342 int result; 343 344 mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value); 345 346 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 347 GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), 348 (uint32_t *)&mpll_parameters); 349 350 if (!result) 351 mpll_param->mpll_post_divider = 352 (uint32_t)mpll_parameters.ulClock.ucPostDiv; 353 354 return result; 355 } 356 357 int atomctrl_get_memory_pll_dividers_ai(struct pp_hwmgr *hwmgr, 358 uint32_t clock_value, 359 pp_atomctrl_memory_clock_param_ai *mpll_param) 360 { 361 struct amdgpu_device *adev = hwmgr->adev; 362 COMPUTE_MEMORY_CLOCK_PARAM_PARAMETERS_V2_3 mpll_parameters = {{0}, 0, 0}; 363 int result; 364 365 mpll_parameters.ulClock.ulClock = cpu_to_le32(clock_value); 366 367 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 368 GetIndexIntoMasterTable(COMMAND, ComputeMemoryClockParam), 369 (uint32_t *)&mpll_parameters); 370 371 /* VEGAM's mpll takes sometime to finish computing */ 372 udelay(10); 373 374 if (!result) { 375 mpll_param->ulMclk_fcw_int = 376 le16_to_cpu(mpll_parameters.usMclk_fcw_int); 377 mpll_param->ulMclk_fcw_frac = 378 le16_to_cpu(mpll_parameters.usMclk_fcw_frac); 379 mpll_param->ulClock = 380 le32_to_cpu(mpll_parameters.ulClock.ulClock); 381 mpll_param->ulPostDiv = mpll_parameters.ulClock.ucPostDiv; 382 } 383 384 return result; 385 } 386 387 int atomctrl_get_engine_pll_dividers_kong(struct pp_hwmgr *hwmgr, 388 uint32_t clock_value, 389 pp_atomctrl_clock_dividers_kong *dividers) 390 { 391 struct amdgpu_device *adev = hwmgr->adev; 392 COMPUTE_MEMORY_ENGINE_PLL_PARAMETERS_V4 pll_parameters; 393 int result; 394 395 pll_parameters.ulClock = cpu_to_le32(clock_value); 396 397 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 398 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), 399 (uint32_t *)&pll_parameters); 400 401 if (0 == result) { 402 dividers->pll_post_divider = pll_parameters.ucPostDiv; 403 dividers->real_clock = le32_to_cpu(pll_parameters.ulClock); 404 } 405 406 return result; 407 } 408 409 int atomctrl_get_engine_pll_dividers_vi( 410 struct pp_hwmgr *hwmgr, 411 uint32_t clock_value, 412 pp_atomctrl_clock_dividers_vi *dividers) 413 { 414 struct amdgpu_device *adev = hwmgr->adev; 415 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters; 416 int result; 417 418 pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value); 419 pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK; 420 421 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 422 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), 423 (uint32_t *)&pll_patameters); 424 425 if (0 == result) { 426 dividers->pll_post_divider = 427 pll_patameters.ulClock.ucPostDiv; 428 dividers->real_clock = 429 le32_to_cpu(pll_patameters.ulClock.ulClock); 430 431 dividers->ul_fb_div.ul_fb_div_frac = 432 le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac); 433 dividers->ul_fb_div.ul_fb_div = 434 le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv); 435 436 dividers->uc_pll_ref_div = 437 pll_patameters.ucPllRefDiv; 438 dividers->uc_pll_post_div = 439 pll_patameters.ucPllPostDiv; 440 dividers->uc_pll_cntl_flag = 441 pll_patameters.ucPllCntlFlag; 442 } 443 444 return result; 445 } 446 447 int atomctrl_get_engine_pll_dividers_ai(struct pp_hwmgr *hwmgr, 448 uint32_t clock_value, 449 pp_atomctrl_clock_dividers_ai *dividers) 450 { 451 struct amdgpu_device *adev = hwmgr->adev; 452 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_7 pll_patameters; 453 int result; 454 455 pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value); 456 pll_patameters.ulClock.ucPostDiv = COMPUTE_GPUCLK_INPUT_FLAG_SCLK; 457 458 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 459 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), 460 (uint32_t *)&pll_patameters); 461 462 if (0 == result) { 463 dividers->usSclk_fcw_frac = le16_to_cpu(pll_patameters.usSclk_fcw_frac); 464 dividers->usSclk_fcw_int = le16_to_cpu(pll_patameters.usSclk_fcw_int); 465 dividers->ucSclkPostDiv = pll_patameters.ucSclkPostDiv; 466 dividers->ucSclkVcoMode = pll_patameters.ucSclkVcoMode; 467 dividers->ucSclkPllRange = pll_patameters.ucSclkPllRange; 468 dividers->ucSscEnable = pll_patameters.ucSscEnable; 469 dividers->usSsc_fcw1_frac = le16_to_cpu(pll_patameters.usSsc_fcw1_frac); 470 dividers->usSsc_fcw1_int = le16_to_cpu(pll_patameters.usSsc_fcw1_int); 471 dividers->usPcc_fcw_int = le16_to_cpu(pll_patameters.usPcc_fcw_int); 472 dividers->usSsc_fcw_slew_frac = le16_to_cpu(pll_patameters.usSsc_fcw_slew_frac); 473 dividers->usPcc_fcw_slew_frac = le16_to_cpu(pll_patameters.usPcc_fcw_slew_frac); 474 } 475 return result; 476 } 477 478 int atomctrl_get_dfs_pll_dividers_vi( 479 struct pp_hwmgr *hwmgr, 480 uint32_t clock_value, 481 pp_atomctrl_clock_dividers_vi *dividers) 482 { 483 struct amdgpu_device *adev = hwmgr->adev; 484 COMPUTE_GPU_CLOCK_OUTPUT_PARAMETERS_V1_6 pll_patameters; 485 int result; 486 487 pll_patameters.ulClock.ulClock = cpu_to_le32(clock_value); 488 pll_patameters.ulClock.ucPostDiv = 489 COMPUTE_GPUCLK_INPUT_FLAG_DEFAULT_GPUCLK; 490 491 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 492 GetIndexIntoMasterTable(COMMAND, ComputeMemoryEnginePLL), 493 (uint32_t *)&pll_patameters); 494 495 if (0 == result) { 496 dividers->pll_post_divider = 497 pll_patameters.ulClock.ucPostDiv; 498 dividers->real_clock = 499 le32_to_cpu(pll_patameters.ulClock.ulClock); 500 501 dividers->ul_fb_div.ul_fb_div_frac = 502 le16_to_cpu(pll_patameters.ulFbDiv.usFbDivFrac); 503 dividers->ul_fb_div.ul_fb_div = 504 le16_to_cpu(pll_patameters.ulFbDiv.usFbDiv); 505 506 dividers->uc_pll_ref_div = 507 pll_patameters.ucPllRefDiv; 508 dividers->uc_pll_post_div = 509 pll_patameters.ucPllPostDiv; 510 dividers->uc_pll_cntl_flag = 511 pll_patameters.ucPllCntlFlag; 512 } 513 514 return result; 515 } 516 517 /* 518 * Get the reference clock in 10KHz 519 */ 520 uint32_t atomctrl_get_reference_clock(struct pp_hwmgr *hwmgr) 521 { 522 ATOM_FIRMWARE_INFO *fw_info; 523 u8 frev, crev; 524 u16 size; 525 uint32_t clock; 526 527 fw_info = (ATOM_FIRMWARE_INFO *) 528 smu_atom_get_data_table(hwmgr->adev, 529 GetIndexIntoMasterTable(DATA, FirmwareInfo), 530 &size, &frev, &crev); 531 532 if (fw_info == NULL) 533 clock = 2700; 534 else 535 clock = (uint32_t)(le16_to_cpu(fw_info->usReferenceClock)); 536 537 return clock; 538 } 539 540 /* 541 * Returns true if the given voltage type is controlled by GPIO pins. 542 * voltage_type is one of SET_VOLTAGE_TYPE_ASIC_VDDC, 543 * SET_VOLTAGE_TYPE_ASIC_MVDDC, SET_VOLTAGE_TYPE_ASIC_MVDDQ. 544 * voltage_mode is one of ATOM_SET_VOLTAGE, ATOM_SET_VOLTAGE_PHASE 545 */ 546 bool atomctrl_is_voltage_controlled_by_gpio_v3( 547 struct pp_hwmgr *hwmgr, 548 uint8_t voltage_type, 549 uint8_t voltage_mode) 550 { 551 ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info = 552 (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev); 553 bool ret; 554 555 PP_ASSERT_WITH_CODE((NULL != voltage_info), 556 "Could not find Voltage Table in BIOS.", return false;); 557 558 ret = (NULL != atomctrl_lookup_voltage_type_v3 559 (voltage_info, voltage_type, voltage_mode)) ? true : false; 560 561 return ret; 562 } 563 564 int atomctrl_get_voltage_table_v3( 565 struct pp_hwmgr *hwmgr, 566 uint8_t voltage_type, 567 uint8_t voltage_mode, 568 pp_atomctrl_voltage_table *voltage_table) 569 { 570 ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info = 571 (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev); 572 const ATOM_VOLTAGE_OBJECT_V3 *voltage_object; 573 unsigned int i; 574 575 PP_ASSERT_WITH_CODE((NULL != voltage_info), 576 "Could not find Voltage Table in BIOS.", return -1;); 577 578 voltage_object = atomctrl_lookup_voltage_type_v3 579 (voltage_info, voltage_type, voltage_mode); 580 581 if (voltage_object == NULL) 582 return -1; 583 584 PP_ASSERT_WITH_CODE( 585 (voltage_object->asGpioVoltageObj.ucGpioEntryNum <= 586 PP_ATOMCTRL_MAX_VOLTAGE_ENTRIES), 587 "Too many voltage entries!", 588 return -1; 589 ); 590 591 for (i = 0; i < voltage_object->asGpioVoltageObj.ucGpioEntryNum; i++) { 592 voltage_table->entries[i].value = 593 le16_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].usVoltageValue); 594 voltage_table->entries[i].smio_low = 595 le32_to_cpu(voltage_object->asGpioVoltageObj.asVolGpioLut[i].ulVoltageId); 596 } 597 598 voltage_table->mask_low = 599 le32_to_cpu(voltage_object->asGpioVoltageObj.ulGpioMaskVal); 600 voltage_table->count = 601 voltage_object->asGpioVoltageObj.ucGpioEntryNum; 602 voltage_table->phase_delay = 603 voltage_object->asGpioVoltageObj.ucPhaseDelay; 604 605 return 0; 606 } 607 608 static bool atomctrl_lookup_gpio_pin( 609 ATOM_GPIO_PIN_LUT * gpio_lookup_table, 610 const uint32_t pinId, 611 pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment) 612 { 613 unsigned int size = le16_to_cpu(gpio_lookup_table->sHeader.usStructureSize); 614 unsigned int offset = offsetof(ATOM_GPIO_PIN_LUT, asGPIO_Pin[0]); 615 uint8_t *start = (uint8_t *)gpio_lookup_table; 616 617 while (offset < size) { 618 const ATOM_GPIO_PIN_ASSIGNMENT *pin_assignment = 619 (const ATOM_GPIO_PIN_ASSIGNMENT *)(start + offset); 620 621 if (pinId == pin_assignment->ucGPIO_ID) { 622 gpio_pin_assignment->uc_gpio_pin_bit_shift = 623 pin_assignment->ucGpioPinBitShift; 624 gpio_pin_assignment->us_gpio_pin_aindex = 625 le16_to_cpu(pin_assignment->usGpioPin_AIndex); 626 return true; 627 } 628 629 offset += offsetof(ATOM_GPIO_PIN_ASSIGNMENT, ucGPIO_ID) + 1; 630 } 631 632 return false; 633 } 634 635 /* 636 * Private Function to get the PowerPlay Table Address. 637 * WARNING: The tabled returned by this function is in 638 * dynamically allocated memory. 639 * The caller has to release if by calling kfree. 640 */ 641 static ATOM_GPIO_PIN_LUT *get_gpio_lookup_table(void *device) 642 { 643 u8 frev, crev; 644 u16 size; 645 void *table_address; 646 647 table_address = (ATOM_GPIO_PIN_LUT *) 648 smu_atom_get_data_table(device, 649 GetIndexIntoMasterTable(DATA, GPIO_Pin_LUT), 650 &size, &frev, &crev); 651 652 PP_ASSERT_WITH_CODE((NULL != table_address), 653 "Error retrieving BIOS Table Address!", return NULL;); 654 655 return (ATOM_GPIO_PIN_LUT *)table_address; 656 } 657 658 /* 659 * Returns 1 if the given pin id find in lookup table. 660 */ 661 bool atomctrl_get_pp_assign_pin( 662 struct pp_hwmgr *hwmgr, 663 const uint32_t pinId, 664 pp_atomctrl_gpio_pin_assignment *gpio_pin_assignment) 665 { 666 bool bRet = false; 667 ATOM_GPIO_PIN_LUT *gpio_lookup_table = 668 get_gpio_lookup_table(hwmgr->adev); 669 670 PP_ASSERT_WITH_CODE((NULL != gpio_lookup_table), 671 "Could not find GPIO lookup Table in BIOS.", return false); 672 673 bRet = atomctrl_lookup_gpio_pin(gpio_lookup_table, pinId, 674 gpio_pin_assignment); 675 676 return bRet; 677 } 678 679 int atomctrl_calculate_voltage_evv_on_sclk( 680 struct pp_hwmgr *hwmgr, 681 uint8_t voltage_type, 682 uint32_t sclk, 683 uint16_t virtual_voltage_Id, 684 uint16_t *voltage, 685 uint16_t dpm_level, 686 bool debug) 687 { 688 ATOM_ASIC_PROFILING_INFO_V3_4 *getASICProfilingInfo; 689 struct amdgpu_device *adev = hwmgr->adev; 690 EFUSE_LINEAR_FUNC_PARAM sRO_fuse; 691 EFUSE_LINEAR_FUNC_PARAM sCACm_fuse; 692 EFUSE_LINEAR_FUNC_PARAM sCACb_fuse; 693 EFUSE_LOGISTIC_FUNC_PARAM sKt_Beta_fuse; 694 EFUSE_LOGISTIC_FUNC_PARAM sKv_m_fuse; 695 EFUSE_LOGISTIC_FUNC_PARAM sKv_b_fuse; 696 EFUSE_INPUT_PARAMETER sInput_FuseValues; 697 READ_EFUSE_VALUE_PARAMETER sOutput_FuseValues; 698 699 uint32_t ul_RO_fused, ul_CACb_fused, ul_CACm_fused, ul_Kt_Beta_fused, ul_Kv_m_fused, ul_Kv_b_fused; 700 fInt fSM_A0, fSM_A1, fSM_A2, fSM_A3, fSM_A4, fSM_A5, fSM_A6, fSM_A7; 701 fInt fMargin_RO_a, fMargin_RO_b, fMargin_RO_c, fMargin_fixed, fMargin_FMAX_mean, fMargin_Plat_mean, fMargin_FMAX_sigma, fMargin_Plat_sigma, fMargin_DC_sigma; 702 fInt fLkg_FT, repeat; 703 fInt fMicro_FMAX, fMicro_CR, fSigma_FMAX, fSigma_CR, fSigma_DC, fDC_SCLK, fSquared_Sigma_DC, fSquared_Sigma_CR, fSquared_Sigma_FMAX; 704 fInt fRLL_LoadLine, fDerateTDP, fVDDC_base, fA_Term, fC_Term, fB_Term, fRO_DC_margin; 705 fInt fRO_fused, fCACm_fused, fCACb_fused, fKv_m_fused, fKv_b_fused, fKt_Beta_fused, fFT_Lkg_V0NORM; 706 fInt fSclk_margin, fSclk, fEVV_V; 707 fInt fV_min, fV_max, fT_prod, fLKG_Factor, fT_FT, fV_FT, fV_x, fTDP_Power, fTDP_Power_right, fTDP_Power_left, fTDP_Current, fV_NL; 708 uint32_t ul_FT_Lkg_V0NORM; 709 fInt fLn_MaxDivMin, fMin, fAverage, fRange; 710 fInt fRoots[2]; 711 fInt fStepSize = GetScaledFraction(625, 100000); 712 713 int result; 714 715 getASICProfilingInfo = (ATOM_ASIC_PROFILING_INFO_V3_4 *) 716 smu_atom_get_data_table(hwmgr->adev, 717 GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo), 718 NULL, NULL, NULL); 719 720 if (!getASICProfilingInfo) 721 return -1; 722 723 if (getASICProfilingInfo->asHeader.ucTableFormatRevision < 3 || 724 (getASICProfilingInfo->asHeader.ucTableFormatRevision == 3 && 725 getASICProfilingInfo->asHeader.ucTableContentRevision < 4)) 726 return -1; 727 728 /*----------------------------------------------------------- 729 *GETTING MULTI-STEP PARAMETERS RELATED TO CURRENT DPM LEVEL 730 *----------------------------------------------------------- 731 */ 732 fRLL_LoadLine = Divide(getASICProfilingInfo->ulLoadLineSlop, 1000); 733 734 switch (dpm_level) { 735 case 1: 736 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM1), 1000); 737 break; 738 case 2: 739 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM2), 1000); 740 break; 741 case 3: 742 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM3), 1000); 743 break; 744 case 4: 745 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM4), 1000); 746 break; 747 case 5: 748 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM5), 1000); 749 break; 750 case 6: 751 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM6), 1000); 752 break; 753 case 7: 754 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM7), 1000); 755 break; 756 default: 757 pr_err("DPM Level not supported\n"); 758 fDerateTDP = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulTdpDerateDPM0), 1000); 759 } 760 761 /*------------------------- 762 * DECODING FUSE VALUES 763 * ------------------------ 764 */ 765 /*Decode RO_Fused*/ 766 sRO_fuse = getASICProfilingInfo->sRoFuse; 767 768 sInput_FuseValues.usEfuseIndex = sRO_fuse.usEfuseIndex; 769 sInput_FuseValues.ucBitShift = sRO_fuse.ucEfuseBitLSB; 770 sInput_FuseValues.ucBitLength = sRO_fuse.ucEfuseLength; 771 772 sOutput_FuseValues.sEfuse = sInput_FuseValues; 773 774 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 775 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 776 (uint32_t *)&sOutput_FuseValues); 777 778 if (result) 779 return result; 780 781 /* Finally, the actual fuse value */ 782 ul_RO_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 783 fMin = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseMin), 1); 784 fRange = GetScaledFraction(le32_to_cpu(sRO_fuse.ulEfuseEncodeRange), 1); 785 fRO_fused = fDecodeLinearFuse(ul_RO_fused, fMin, fRange, sRO_fuse.ucEfuseLength); 786 787 sCACm_fuse = getASICProfilingInfo->sCACm; 788 789 sInput_FuseValues.usEfuseIndex = sCACm_fuse.usEfuseIndex; 790 sInput_FuseValues.ucBitShift = sCACm_fuse.ucEfuseBitLSB; 791 sInput_FuseValues.ucBitLength = sCACm_fuse.ucEfuseLength; 792 793 sOutput_FuseValues.sEfuse = sInput_FuseValues; 794 795 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 796 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 797 (uint32_t *)&sOutput_FuseValues); 798 799 if (result) 800 return result; 801 802 ul_CACm_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 803 fMin = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseMin), 1000); 804 fRange = GetScaledFraction(le32_to_cpu(sCACm_fuse.ulEfuseEncodeRange), 1000); 805 806 fCACm_fused = fDecodeLinearFuse(ul_CACm_fused, fMin, fRange, sCACm_fuse.ucEfuseLength); 807 808 sCACb_fuse = getASICProfilingInfo->sCACb; 809 810 sInput_FuseValues.usEfuseIndex = sCACb_fuse.usEfuseIndex; 811 sInput_FuseValues.ucBitShift = sCACb_fuse.ucEfuseBitLSB; 812 sInput_FuseValues.ucBitLength = sCACb_fuse.ucEfuseLength; 813 sOutput_FuseValues.sEfuse = sInput_FuseValues; 814 815 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 816 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 817 (uint32_t *)&sOutput_FuseValues); 818 819 if (result) 820 return result; 821 822 ul_CACb_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 823 fMin = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseMin), 1000); 824 fRange = GetScaledFraction(le32_to_cpu(sCACb_fuse.ulEfuseEncodeRange), 1000); 825 826 fCACb_fused = fDecodeLinearFuse(ul_CACb_fused, fMin, fRange, sCACb_fuse.ucEfuseLength); 827 828 sKt_Beta_fuse = getASICProfilingInfo->sKt_b; 829 830 sInput_FuseValues.usEfuseIndex = sKt_Beta_fuse.usEfuseIndex; 831 sInput_FuseValues.ucBitShift = sKt_Beta_fuse.ucEfuseBitLSB; 832 sInput_FuseValues.ucBitLength = sKt_Beta_fuse.ucEfuseLength; 833 834 sOutput_FuseValues.sEfuse = sInput_FuseValues; 835 836 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 837 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 838 (uint32_t *)&sOutput_FuseValues); 839 840 if (result) 841 return result; 842 843 ul_Kt_Beta_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 844 fAverage = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeAverage), 1000); 845 fRange = GetScaledFraction(le32_to_cpu(sKt_Beta_fuse.ulEfuseEncodeRange), 1000); 846 847 fKt_Beta_fused = fDecodeLogisticFuse(ul_Kt_Beta_fused, 848 fAverage, fRange, sKt_Beta_fuse.ucEfuseLength); 849 850 sKv_m_fuse = getASICProfilingInfo->sKv_m; 851 852 sInput_FuseValues.usEfuseIndex = sKv_m_fuse.usEfuseIndex; 853 sInput_FuseValues.ucBitShift = sKv_m_fuse.ucEfuseBitLSB; 854 sInput_FuseValues.ucBitLength = sKv_m_fuse.ucEfuseLength; 855 856 sOutput_FuseValues.sEfuse = sInput_FuseValues; 857 858 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 859 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 860 (uint32_t *)&sOutput_FuseValues); 861 if (result) 862 return result; 863 864 ul_Kv_m_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 865 fAverage = GetScaledFraction(le32_to_cpu(sKv_m_fuse.ulEfuseEncodeAverage), 1000); 866 fRange = GetScaledFraction((le32_to_cpu(sKv_m_fuse.ulEfuseEncodeRange) & 0x7fffffff), 1000); 867 fRange = fMultiply(fRange, ConvertToFraction(-1)); 868 869 fKv_m_fused = fDecodeLogisticFuse(ul_Kv_m_fused, 870 fAverage, fRange, sKv_m_fuse.ucEfuseLength); 871 872 sKv_b_fuse = getASICProfilingInfo->sKv_b; 873 874 sInput_FuseValues.usEfuseIndex = sKv_b_fuse.usEfuseIndex; 875 sInput_FuseValues.ucBitShift = sKv_b_fuse.ucEfuseBitLSB; 876 sInput_FuseValues.ucBitLength = sKv_b_fuse.ucEfuseLength; 877 sOutput_FuseValues.sEfuse = sInput_FuseValues; 878 879 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 880 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 881 (uint32_t *)&sOutput_FuseValues); 882 883 if (result) 884 return result; 885 886 ul_Kv_b_fused = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 887 fAverage = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeAverage), 1000); 888 fRange = GetScaledFraction(le32_to_cpu(sKv_b_fuse.ulEfuseEncodeRange), 1000); 889 890 fKv_b_fused = fDecodeLogisticFuse(ul_Kv_b_fused, 891 fAverage, fRange, sKv_b_fuse.ucEfuseLength); 892 893 /* Decoding the Leakage - No special struct container */ 894 /* 895 * usLkgEuseIndex=56 896 * ucLkgEfuseBitLSB=6 897 * ucLkgEfuseLength=10 898 * ulLkgEncodeLn_MaxDivMin=69077 899 * ulLkgEncodeMax=1000000 900 * ulLkgEncodeMin=1000 901 * ulEfuseLogisticAlpha=13 902 */ 903 904 sInput_FuseValues.usEfuseIndex = getASICProfilingInfo->usLkgEuseIndex; 905 sInput_FuseValues.ucBitShift = getASICProfilingInfo->ucLkgEfuseBitLSB; 906 sInput_FuseValues.ucBitLength = getASICProfilingInfo->ucLkgEfuseLength; 907 908 sOutput_FuseValues.sEfuse = sInput_FuseValues; 909 910 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 911 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 912 (uint32_t *)&sOutput_FuseValues); 913 914 if (result) 915 return result; 916 917 ul_FT_Lkg_V0NORM = le32_to_cpu(sOutput_FuseValues.ulEfuseValue); 918 fLn_MaxDivMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeLn_MaxDivMin), 10000); 919 fMin = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLkgEncodeMin), 10000); 920 921 fFT_Lkg_V0NORM = fDecodeLeakageID(ul_FT_Lkg_V0NORM, 922 fLn_MaxDivMin, fMin, getASICProfilingInfo->ucLkgEfuseLength); 923 fLkg_FT = fFT_Lkg_V0NORM; 924 925 /*------------------------------------------- 926 * PART 2 - Grabbing all required values 927 *------------------------------------------- 928 */ 929 fSM_A0 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A0), 1000000), 930 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A0_sign))); 931 fSM_A1 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A1), 1000000), 932 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A1_sign))); 933 fSM_A2 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A2), 100000), 934 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A2_sign))); 935 fSM_A3 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A3), 1000000), 936 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A3_sign))); 937 fSM_A4 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A4), 1000000), 938 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A4_sign))); 939 fSM_A5 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A5), 1000), 940 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A5_sign))); 941 fSM_A6 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A6), 1000), 942 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A6_sign))); 943 fSM_A7 = fMultiply(GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulSM_A7), 1000), 944 ConvertToFraction(uPow(-1, getASICProfilingInfo->ucSM_A7_sign))); 945 946 fMargin_RO_a = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_a)); 947 fMargin_RO_b = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_b)); 948 fMargin_RO_c = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_RO_c)); 949 950 fMargin_fixed = ConvertToFraction(le32_to_cpu(getASICProfilingInfo->ulMargin_fixed)); 951 952 fMargin_FMAX_mean = GetScaledFraction( 953 le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_mean), 10000); 954 fMargin_Plat_mean = GetScaledFraction( 955 le32_to_cpu(getASICProfilingInfo->ulMargin_plat_mean), 10000); 956 fMargin_FMAX_sigma = GetScaledFraction( 957 le32_to_cpu(getASICProfilingInfo->ulMargin_Fmax_sigma), 10000); 958 fMargin_Plat_sigma = GetScaledFraction( 959 le32_to_cpu(getASICProfilingInfo->ulMargin_plat_sigma), 10000); 960 961 fMargin_DC_sigma = GetScaledFraction( 962 le32_to_cpu(getASICProfilingInfo->ulMargin_DC_sigma), 100); 963 fMargin_DC_sigma = fDivide(fMargin_DC_sigma, ConvertToFraction(1000)); 964 965 fCACm_fused = fDivide(fCACm_fused, ConvertToFraction(100)); 966 fCACb_fused = fDivide(fCACb_fused, ConvertToFraction(100)); 967 fKt_Beta_fused = fDivide(fKt_Beta_fused, ConvertToFraction(100)); 968 fKv_m_fused = fNegate(fDivide(fKv_m_fused, ConvertToFraction(100))); 969 fKv_b_fused = fDivide(fKv_b_fused, ConvertToFraction(10)); 970 971 fSclk = GetScaledFraction(sclk, 100); 972 973 fV_max = fDivide(GetScaledFraction( 974 le32_to_cpu(getASICProfilingInfo->ulMaxVddc), 1000), ConvertToFraction(4)); 975 fT_prod = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulBoardCoreTemp), 10); 976 fLKG_Factor = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulEvvLkgFactor), 100); 977 fT_FT = GetScaledFraction(le32_to_cpu(getASICProfilingInfo->ulLeakageTemp), 10); 978 fV_FT = fDivide(GetScaledFraction( 979 le32_to_cpu(getASICProfilingInfo->ulLeakageVoltage), 1000), ConvertToFraction(4)); 980 fV_min = fDivide(GetScaledFraction( 981 le32_to_cpu(getASICProfilingInfo->ulMinVddc), 1000), ConvertToFraction(4)); 982 983 /*----------------------- 984 * PART 3 985 *----------------------- 986 */ 987 988 fA_Term = fAdd(fMargin_RO_a, fAdd(fMultiply(fSM_A4, fSclk), fSM_A5)); 989 fB_Term = fAdd(fAdd(fMultiply(fSM_A2, fSclk), fSM_A6), fMargin_RO_b); 990 fC_Term = fAdd(fMargin_RO_c, 991 fAdd(fMultiply(fSM_A0, fLkg_FT), 992 fAdd(fMultiply(fSM_A1, fMultiply(fLkg_FT, fSclk)), 993 fAdd(fMultiply(fSM_A3, fSclk), 994 fSubtract(fSM_A7, fRO_fused))))); 995 996 fVDDC_base = fSubtract(fRO_fused, 997 fSubtract(fMargin_RO_c, 998 fSubtract(fSM_A3, fMultiply(fSM_A1, fSclk)))); 999 fVDDC_base = fDivide(fVDDC_base, fAdd(fMultiply(fSM_A0, fSclk), fSM_A2)); 1000 1001 repeat = fSubtract(fVDDC_base, 1002 fDivide(fMargin_DC_sigma, ConvertToFraction(1000))); 1003 1004 fRO_DC_margin = fAdd(fMultiply(fMargin_RO_a, 1005 fGetSquare(repeat)), 1006 fAdd(fMultiply(fMargin_RO_b, repeat), 1007 fMargin_RO_c)); 1008 1009 fDC_SCLK = fSubtract(fRO_fused, 1010 fSubtract(fRO_DC_margin, 1011 fSubtract(fSM_A3, 1012 fMultiply(fSM_A2, repeat)))); 1013 fDC_SCLK = fDivide(fDC_SCLK, fAdd(fMultiply(fSM_A0, repeat), fSM_A1)); 1014 1015 fSigma_DC = fSubtract(fSclk, fDC_SCLK); 1016 1017 fMicro_FMAX = fMultiply(fSclk, fMargin_FMAX_mean); 1018 fMicro_CR = fMultiply(fSclk, fMargin_Plat_mean); 1019 fSigma_FMAX = fMultiply(fSclk, fMargin_FMAX_sigma); 1020 fSigma_CR = fMultiply(fSclk, fMargin_Plat_sigma); 1021 1022 fSquared_Sigma_DC = fGetSquare(fSigma_DC); 1023 fSquared_Sigma_CR = fGetSquare(fSigma_CR); 1024 fSquared_Sigma_FMAX = fGetSquare(fSigma_FMAX); 1025 1026 fSclk_margin = fAdd(fMicro_FMAX, 1027 fAdd(fMicro_CR, 1028 fAdd(fMargin_fixed, 1029 fSqrt(fAdd(fSquared_Sigma_FMAX, 1030 fAdd(fSquared_Sigma_DC, fSquared_Sigma_CR)))))); 1031 /* 1032 fA_Term = fSM_A4 * (fSclk + fSclk_margin) + fSM_A5; 1033 fB_Term = fSM_A2 * (fSclk + fSclk_margin) + fSM_A6; 1034 fC_Term = fRO_DC_margin + fSM_A0 * fLkg_FT + fSM_A1 * fLkg_FT * (fSclk + fSclk_margin) + fSM_A3 * (fSclk + fSclk_margin) + fSM_A7 - fRO_fused; 1035 */ 1036 1037 fA_Term = fAdd(fMultiply(fSM_A4, fAdd(fSclk, fSclk_margin)), fSM_A5); 1038 fB_Term = fAdd(fMultiply(fSM_A2, fAdd(fSclk, fSclk_margin)), fSM_A6); 1039 fC_Term = fAdd(fRO_DC_margin, 1040 fAdd(fMultiply(fSM_A0, fLkg_FT), 1041 fAdd(fMultiply(fMultiply(fSM_A1, fLkg_FT), 1042 fAdd(fSclk, fSclk_margin)), 1043 fAdd(fMultiply(fSM_A3, 1044 fAdd(fSclk, fSclk_margin)), 1045 fSubtract(fSM_A7, fRO_fused))))); 1046 1047 SolveQuadracticEqn(fA_Term, fB_Term, fC_Term, fRoots); 1048 1049 if (GreaterThan(fRoots[0], fRoots[1])) 1050 fEVV_V = fRoots[1]; 1051 else 1052 fEVV_V = fRoots[0]; 1053 1054 if (GreaterThan(fV_min, fEVV_V)) 1055 fEVV_V = fV_min; 1056 else if (GreaterThan(fEVV_V, fV_max)) 1057 fEVV_V = fSubtract(fV_max, fStepSize); 1058 1059 fEVV_V = fRoundUpByStepSize(fEVV_V, fStepSize, 0); 1060 1061 /*----------------- 1062 * PART 4 1063 *----------------- 1064 */ 1065 1066 fV_x = fV_min; 1067 1068 while (GreaterThan(fAdd(fV_max, fStepSize), fV_x)) { 1069 fTDP_Power_left = fMultiply(fMultiply(fMultiply(fAdd( 1070 fMultiply(fCACm_fused, fV_x), fCACb_fused), fSclk), 1071 fGetSquare(fV_x)), fDerateTDP); 1072 1073 fTDP_Power_right = fMultiply(fFT_Lkg_V0NORM, fMultiply(fLKG_Factor, 1074 fMultiply(fExponential(fMultiply(fAdd(fMultiply(fKv_m_fused, 1075 fT_prod), fKv_b_fused), fV_x)), fV_x))); 1076 fTDP_Power_right = fMultiply(fTDP_Power_right, fExponential(fMultiply( 1077 fKt_Beta_fused, fT_prod))); 1078 fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply( 1079 fAdd(fMultiply(fKv_m_fused, fT_prod), fKv_b_fused), fV_FT))); 1080 fTDP_Power_right = fDivide(fTDP_Power_right, fExponential(fMultiply( 1081 fKt_Beta_fused, fT_FT))); 1082 1083 fTDP_Power = fAdd(fTDP_Power_left, fTDP_Power_right); 1084 1085 fTDP_Current = fDivide(fTDP_Power, fV_x); 1086 1087 fV_NL = fAdd(fV_x, fDivide(fMultiply(fTDP_Current, fRLL_LoadLine), 1088 ConvertToFraction(10))); 1089 1090 fV_NL = fRoundUpByStepSize(fV_NL, fStepSize, 0); 1091 1092 if (GreaterThan(fV_max, fV_NL) && 1093 (GreaterThan(fV_NL, fEVV_V) || 1094 Equal(fV_NL, fEVV_V))) { 1095 fV_NL = fMultiply(fV_NL, ConvertToFraction(1000)); 1096 1097 *voltage = (uint16_t)fV_NL.partial.real; 1098 break; 1099 } else 1100 fV_x = fAdd(fV_x, fStepSize); 1101 } 1102 1103 return result; 1104 } 1105 1106 /** 1107 * atomctrl_get_voltage_evv_on_sclk gets voltage via call to ATOM COMMAND table. 1108 * @hwmgr: input: pointer to hwManager 1109 * @voltage_type: input: type of EVV voltage VDDC or VDDGFX 1110 * @sclk: input: in 10Khz unit. DPM state SCLK frequency 1111 * which is define in PPTable SCLK/VDDC dependence 1112 * table associated with this virtual_voltage_Id 1113 * @virtual_voltage_Id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08 1114 * @voltage: output: real voltage level in unit of mv 1115 */ 1116 int atomctrl_get_voltage_evv_on_sclk( 1117 struct pp_hwmgr *hwmgr, 1118 uint8_t voltage_type, 1119 uint32_t sclk, uint16_t virtual_voltage_Id, 1120 uint16_t *voltage) 1121 { 1122 struct amdgpu_device *adev = hwmgr->adev; 1123 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space; 1124 int result; 1125 1126 get_voltage_info_param_space.ucVoltageType = 1127 voltage_type; 1128 get_voltage_info_param_space.ucVoltageMode = 1129 ATOM_GET_VOLTAGE_EVV_VOLTAGE; 1130 get_voltage_info_param_space.usVoltageLevel = 1131 cpu_to_le16(virtual_voltage_Id); 1132 get_voltage_info_param_space.ulSCLKFreq = 1133 cpu_to_le32(sclk); 1134 1135 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1136 GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), 1137 (uint32_t *)&get_voltage_info_param_space); 1138 1139 *voltage = result ? 0 : 1140 le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *) 1141 (&get_voltage_info_param_space))->usVoltageLevel); 1142 1143 return result; 1144 } 1145 1146 /** 1147 * atomctrl_get_voltage_evv gets voltage via call to ATOM COMMAND table. 1148 * @hwmgr: input: pointer to hwManager 1149 * @virtual_voltage_id: input: voltage id which match per voltage DPM state: 0xff01, 0xff02.. 0xff08 1150 * @voltage: output: real voltage level in unit of mv 1151 */ 1152 int atomctrl_get_voltage_evv(struct pp_hwmgr *hwmgr, 1153 uint16_t virtual_voltage_id, 1154 uint16_t *voltage) 1155 { 1156 struct amdgpu_device *adev = hwmgr->adev; 1157 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_2 get_voltage_info_param_space; 1158 int result; 1159 int entry_id; 1160 1161 /* search for leakage voltage ID 0xff01 ~ 0xff08 and sckl */ 1162 for (entry_id = 0; entry_id < hwmgr->dyn_state.vddc_dependency_on_sclk->count; entry_id++) { 1163 if (hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].v == virtual_voltage_id) { 1164 /* found */ 1165 break; 1166 } 1167 } 1168 1169 if (entry_id >= hwmgr->dyn_state.vddc_dependency_on_sclk->count) { 1170 pr_debug("Can't find requested voltage id in vddc_dependency_on_sclk table!\n"); 1171 return -EINVAL; 1172 } 1173 1174 get_voltage_info_param_space.ucVoltageType = VOLTAGE_TYPE_VDDC; 1175 get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; 1176 get_voltage_info_param_space.usVoltageLevel = virtual_voltage_id; 1177 get_voltage_info_param_space.ulSCLKFreq = 1178 cpu_to_le32(hwmgr->dyn_state.vddc_dependency_on_sclk->entries[entry_id].clk); 1179 1180 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1181 GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), 1182 (uint32_t *)&get_voltage_info_param_space); 1183 1184 if (0 != result) 1185 return result; 1186 1187 *voltage = le16_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_2 *) 1188 (&get_voltage_info_param_space))->usVoltageLevel); 1189 1190 return result; 1191 } 1192 1193 /* 1194 * Get the mpll reference clock in 10KHz 1195 */ 1196 uint32_t atomctrl_get_mpll_reference_clock(struct pp_hwmgr *hwmgr) 1197 { 1198 ATOM_COMMON_TABLE_HEADER *fw_info; 1199 uint32_t clock; 1200 u8 frev, crev; 1201 u16 size; 1202 1203 fw_info = (ATOM_COMMON_TABLE_HEADER *) 1204 smu_atom_get_data_table(hwmgr->adev, 1205 GetIndexIntoMasterTable(DATA, FirmwareInfo), 1206 &size, &frev, &crev); 1207 1208 if (fw_info == NULL) 1209 clock = 2700; 1210 else { 1211 if ((fw_info->ucTableFormatRevision == 2) && 1212 (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) { 1213 ATOM_FIRMWARE_INFO_V2_1 *fwInfo_2_1 = 1214 (ATOM_FIRMWARE_INFO_V2_1 *)fw_info; 1215 clock = (uint32_t)(le16_to_cpu(fwInfo_2_1->usMemoryReferenceClock)); 1216 } else { 1217 ATOM_FIRMWARE_INFO *fwInfo_0_0 = 1218 (ATOM_FIRMWARE_INFO *)fw_info; 1219 clock = (uint32_t)(le16_to_cpu(fwInfo_0_0->usReferenceClock)); 1220 } 1221 } 1222 1223 return clock; 1224 } 1225 1226 /* 1227 * Get the asic internal spread spectrum table 1228 */ 1229 static ATOM_ASIC_INTERNAL_SS_INFO *asic_internal_ss_get_ss_table(void *device) 1230 { 1231 ATOM_ASIC_INTERNAL_SS_INFO *table = NULL; 1232 u8 frev, crev; 1233 u16 size; 1234 1235 table = (ATOM_ASIC_INTERNAL_SS_INFO *) 1236 smu_atom_get_data_table(device, 1237 GetIndexIntoMasterTable(DATA, ASIC_InternalSS_Info), 1238 &size, &frev, &crev); 1239 1240 return table; 1241 } 1242 1243 bool atomctrl_is_asic_internal_ss_supported(struct pp_hwmgr *hwmgr) 1244 { 1245 ATOM_ASIC_INTERNAL_SS_INFO *table = 1246 asic_internal_ss_get_ss_table(hwmgr->adev); 1247 1248 if (table) 1249 return true; 1250 else 1251 return false; 1252 } 1253 1254 /* 1255 * Get the asic internal spread spectrum assignment 1256 */ 1257 static int asic_internal_ss_get_ss_asignment(struct pp_hwmgr *hwmgr, 1258 const uint8_t clockSource, 1259 const uint32_t clockSpeed, 1260 pp_atomctrl_internal_ss_info *ssEntry) 1261 { 1262 ATOM_ASIC_INTERNAL_SS_INFO *table; 1263 ATOM_ASIC_SS_ASSIGNMENT *ssInfo; 1264 int entry_found = 0; 1265 1266 memset(ssEntry, 0x00, sizeof(pp_atomctrl_internal_ss_info)); 1267 1268 table = asic_internal_ss_get_ss_table(hwmgr->adev); 1269 1270 if (NULL == table) 1271 return -1; 1272 1273 ssInfo = &table->asSpreadSpectrum[0]; 1274 1275 while (((uint8_t *)ssInfo - (uint8_t *)table) < 1276 le16_to_cpu(table->sHeader.usStructureSize)) { 1277 if ((clockSource == ssInfo->ucClockIndication) && 1278 ((uint32_t)clockSpeed <= le32_to_cpu(ssInfo->ulTargetClockRange))) { 1279 entry_found = 1; 1280 break; 1281 } 1282 1283 ssInfo = (ATOM_ASIC_SS_ASSIGNMENT *)((uint8_t *)ssInfo + 1284 sizeof(ATOM_ASIC_SS_ASSIGNMENT)); 1285 } 1286 1287 if (entry_found) { 1288 ssEntry->speed_spectrum_percentage = 1289 le16_to_cpu(ssInfo->usSpreadSpectrumPercentage); 1290 ssEntry->speed_spectrum_rate = le16_to_cpu(ssInfo->usSpreadRateInKhz); 1291 1292 if (((GET_DATA_TABLE_MAJOR_REVISION(table) == 2) && 1293 (GET_DATA_TABLE_MINOR_REVISION(table) >= 2)) || 1294 (GET_DATA_TABLE_MAJOR_REVISION(table) == 3)) { 1295 ssEntry->speed_spectrum_rate /= 100; 1296 } 1297 1298 switch (ssInfo->ucSpreadSpectrumMode) { 1299 case 0: 1300 ssEntry->speed_spectrum_mode = 1301 pp_atomctrl_spread_spectrum_mode_down; 1302 break; 1303 case 1: 1304 ssEntry->speed_spectrum_mode = 1305 pp_atomctrl_spread_spectrum_mode_center; 1306 break; 1307 default: 1308 ssEntry->speed_spectrum_mode = 1309 pp_atomctrl_spread_spectrum_mode_down; 1310 break; 1311 } 1312 } 1313 1314 return entry_found ? 0 : 1; 1315 } 1316 1317 /* 1318 * Get the memory clock spread spectrum info 1319 */ 1320 int atomctrl_get_memory_clock_spread_spectrum( 1321 struct pp_hwmgr *hwmgr, 1322 const uint32_t memory_clock, 1323 pp_atomctrl_internal_ss_info *ssInfo) 1324 { 1325 return asic_internal_ss_get_ss_asignment(hwmgr, 1326 ASIC_INTERNAL_MEMORY_SS, memory_clock, ssInfo); 1327 } 1328 1329 /* 1330 * Get the engine clock spread spectrum info 1331 */ 1332 int atomctrl_get_engine_clock_spread_spectrum( 1333 struct pp_hwmgr *hwmgr, 1334 const uint32_t engine_clock, 1335 pp_atomctrl_internal_ss_info *ssInfo) 1336 { 1337 return asic_internal_ss_get_ss_asignment(hwmgr, 1338 ASIC_INTERNAL_ENGINE_SS, engine_clock, ssInfo); 1339 } 1340 1341 int atomctrl_read_efuse(struct pp_hwmgr *hwmgr, uint16_t start_index, 1342 uint16_t end_index, uint32_t *efuse) 1343 { 1344 struct amdgpu_device *adev = hwmgr->adev; 1345 uint32_t mask; 1346 int result; 1347 READ_EFUSE_VALUE_PARAMETER efuse_param; 1348 1349 if ((end_index - start_index) == 31) 1350 mask = 0xFFFFFFFF; 1351 else 1352 mask = (1 << ((end_index - start_index) + 1)) - 1; 1353 1354 efuse_param.sEfuse.usEfuseIndex = cpu_to_le16((start_index / 32) * 4); 1355 efuse_param.sEfuse.ucBitShift = (uint8_t) 1356 (start_index - ((start_index / 32) * 32)); 1357 efuse_param.sEfuse.ucBitLength = (uint8_t) 1358 ((end_index - start_index) + 1); 1359 1360 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1361 GetIndexIntoMasterTable(COMMAND, ReadEfuseValue), 1362 (uint32_t *)&efuse_param); 1363 *efuse = result ? 0 : le32_to_cpu(efuse_param.ulEfuseValue) & mask; 1364 1365 return result; 1366 } 1367 1368 int atomctrl_set_ac_timing_ai(struct pp_hwmgr *hwmgr, uint32_t memory_clock, 1369 uint8_t level) 1370 { 1371 struct amdgpu_device *adev = hwmgr->adev; 1372 DYNAMICE_MEMORY_SETTINGS_PARAMETER_V2_1 memory_clock_parameters; 1373 int result; 1374 1375 memory_clock_parameters.asDPMMCReg.ulClock.ulClockFreq = 1376 memory_clock & SET_CLOCK_FREQ_MASK; 1377 memory_clock_parameters.asDPMMCReg.ulClock.ulComputeClockFlag = 1378 ADJUST_MC_SETTING_PARAM; 1379 memory_clock_parameters.asDPMMCReg.ucMclkDPMState = level; 1380 1381 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1382 GetIndexIntoMasterTable(COMMAND, DynamicMemorySettings), 1383 (uint32_t *)&memory_clock_parameters); 1384 1385 return result; 1386 } 1387 1388 int atomctrl_get_voltage_evv_on_sclk_ai(struct pp_hwmgr *hwmgr, uint8_t voltage_type, 1389 uint32_t sclk, uint16_t virtual_voltage_Id, uint32_t *voltage) 1390 { 1391 struct amdgpu_device *adev = hwmgr->adev; 1392 int result; 1393 GET_VOLTAGE_INFO_INPUT_PARAMETER_V1_3 get_voltage_info_param_space; 1394 1395 get_voltage_info_param_space.ucVoltageType = voltage_type; 1396 get_voltage_info_param_space.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE; 1397 get_voltage_info_param_space.usVoltageLevel = cpu_to_le16(virtual_voltage_Id); 1398 get_voltage_info_param_space.ulSCLKFreq = cpu_to_le32(sclk); 1399 1400 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1401 GetIndexIntoMasterTable(COMMAND, GetVoltageInfo), 1402 (uint32_t *)&get_voltage_info_param_space); 1403 1404 *voltage = result ? 0 : 1405 le32_to_cpu(((GET_EVV_VOLTAGE_INFO_OUTPUT_PARAMETER_V1_3 *)(&get_voltage_info_param_space))->ulVoltageLevel); 1406 1407 return result; 1408 } 1409 1410 int atomctrl_get_smc_sclk_range_table(struct pp_hwmgr *hwmgr, struct pp_atom_ctrl_sclk_range_table *table) 1411 { 1412 1413 int i; 1414 u8 frev, crev; 1415 u16 size; 1416 1417 ATOM_SMU_INFO_V2_1 *psmu_info = 1418 (ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev, 1419 GetIndexIntoMasterTable(DATA, SMU_Info), 1420 &size, &frev, &crev); 1421 1422 1423 for (i = 0; i < psmu_info->ucSclkEntryNum; i++) { 1424 table->entry[i].ucVco_setting = psmu_info->asSclkFcwRangeEntry[i].ucVco_setting; 1425 table->entry[i].ucPostdiv = psmu_info->asSclkFcwRangeEntry[i].ucPostdiv; 1426 table->entry[i].usFcw_pcc = 1427 le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_pcc); 1428 table->entry[i].usFcw_trans_upper = 1429 le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucFcw_trans_upper); 1430 table->entry[i].usRcw_trans_lower = 1431 le16_to_cpu(psmu_info->asSclkFcwRangeEntry[i].ucRcw_trans_lower); 1432 } 1433 1434 return 0; 1435 } 1436 1437 int atomctrl_get_vddc_shared_railinfo(struct pp_hwmgr *hwmgr, uint8_t *shared_rail) 1438 { 1439 ATOM_SMU_INFO_V2_1 *psmu_info = 1440 (ATOM_SMU_INFO_V2_1 *)smu_atom_get_data_table(hwmgr->adev, 1441 GetIndexIntoMasterTable(DATA, SMU_Info), 1442 NULL, NULL, NULL); 1443 if (!psmu_info) 1444 return -1; 1445 1446 *shared_rail = psmu_info->ucSharePowerSource; 1447 1448 return 0; 1449 } 1450 1451 int atomctrl_get_avfs_information(struct pp_hwmgr *hwmgr, 1452 struct pp_atom_ctrl__avfs_parameters *param) 1453 { 1454 ATOM_ASIC_PROFILING_INFO_V3_6 *profile = NULL; 1455 1456 if (param == NULL) 1457 return -EINVAL; 1458 1459 profile = (ATOM_ASIC_PROFILING_INFO_V3_6 *) 1460 smu_atom_get_data_table(hwmgr->adev, 1461 GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo), 1462 NULL, NULL, NULL); 1463 if (!profile) 1464 return -1; 1465 1466 param->ulAVFS_meanNsigma_Acontant0 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant0); 1467 param->ulAVFS_meanNsigma_Acontant1 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant1); 1468 param->ulAVFS_meanNsigma_Acontant2 = le32_to_cpu(profile->ulAVFS_meanNsigma_Acontant2); 1469 param->usAVFS_meanNsigma_DC_tol_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_DC_tol_sigma); 1470 param->usAVFS_meanNsigma_Platform_mean = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_mean); 1471 param->usAVFS_meanNsigma_Platform_sigma = le16_to_cpu(profile->usAVFS_meanNsigma_Platform_sigma); 1472 param->ulGB_VDROOP_TABLE_CKSOFF_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a0); 1473 param->ulGB_VDROOP_TABLE_CKSOFF_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a1); 1474 param->ulGB_VDROOP_TABLE_CKSOFF_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSOFF_a2); 1475 param->ulGB_VDROOP_TABLE_CKSON_a0 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a0); 1476 param->ulGB_VDROOP_TABLE_CKSON_a1 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a1); 1477 param->ulGB_VDROOP_TABLE_CKSON_a2 = le32_to_cpu(profile->ulGB_VDROOP_TABLE_CKSON_a2); 1478 param->ulAVFSGB_FUSE_TABLE_CKSOFF_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_m1); 1479 param->usAVFSGB_FUSE_TABLE_CKSOFF_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSOFF_m2); 1480 param->ulAVFSGB_FUSE_TABLE_CKSOFF_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSOFF_b); 1481 param->ulAVFSGB_FUSE_TABLE_CKSON_m1 = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_m1); 1482 param->usAVFSGB_FUSE_TABLE_CKSON_m2 = le16_to_cpu(profile->usAVFSGB_FUSE_TABLE_CKSON_m2); 1483 param->ulAVFSGB_FUSE_TABLE_CKSON_b = le32_to_cpu(profile->ulAVFSGB_FUSE_TABLE_CKSON_b); 1484 param->usMaxVoltage_0_25mv = le16_to_cpu(profile->usMaxVoltage_0_25mv); 1485 param->ucEnableGB_VDROOP_TABLE_CKSOFF = profile->ucEnableGB_VDROOP_TABLE_CKSOFF; 1486 param->ucEnableGB_VDROOP_TABLE_CKSON = profile->ucEnableGB_VDROOP_TABLE_CKSON; 1487 param->ucEnableGB_FUSE_TABLE_CKSOFF = profile->ucEnableGB_FUSE_TABLE_CKSOFF; 1488 param->ucEnableGB_FUSE_TABLE_CKSON = profile->ucEnableGB_FUSE_TABLE_CKSON; 1489 param->usPSM_Age_ComFactor = le16_to_cpu(profile->usPSM_Age_ComFactor); 1490 param->ucEnableApplyAVFS_CKS_OFF_Voltage = profile->ucEnableApplyAVFS_CKS_OFF_Voltage; 1491 1492 return 0; 1493 } 1494 1495 int atomctrl_get_svi2_info(struct pp_hwmgr *hwmgr, uint8_t voltage_type, 1496 uint8_t *svd_gpio_id, uint8_t *svc_gpio_id, 1497 uint16_t *load_line) 1498 { 1499 ATOM_VOLTAGE_OBJECT_INFO_V3_1 *voltage_info = 1500 (ATOM_VOLTAGE_OBJECT_INFO_V3_1 *)get_voltage_info_table(hwmgr->adev); 1501 1502 const ATOM_VOLTAGE_OBJECT_V3 *voltage_object; 1503 1504 PP_ASSERT_WITH_CODE((NULL != voltage_info), 1505 "Could not find Voltage Table in BIOS.", return -EINVAL); 1506 1507 voltage_object = atomctrl_lookup_voltage_type_v3 1508 (voltage_info, voltage_type, VOLTAGE_OBJ_SVID2); 1509 1510 *svd_gpio_id = voltage_object->asSVID2Obj.ucSVDGpioId; 1511 *svc_gpio_id = voltage_object->asSVID2Obj.ucSVCGpioId; 1512 *load_line = voltage_object->asSVID2Obj.usLoadLine_PSI; 1513 1514 return 0; 1515 } 1516 1517 int atomctrl_get_leakage_id_from_efuse(struct pp_hwmgr *hwmgr, uint16_t *virtual_voltage_id) 1518 { 1519 struct amdgpu_device *adev = hwmgr->adev; 1520 SET_VOLTAGE_PS_ALLOCATION allocation; 1521 SET_VOLTAGE_PARAMETERS_V1_3 *voltage_parameters = 1522 (SET_VOLTAGE_PARAMETERS_V1_3 *)&allocation.sASICSetVoltage; 1523 int result; 1524 1525 voltage_parameters->ucVoltageMode = ATOM_GET_LEAKAGE_ID; 1526 1527 result = amdgpu_atom_execute_table(adev->mode_info.atom_context, 1528 GetIndexIntoMasterTable(COMMAND, SetVoltage), 1529 (uint32_t *)voltage_parameters); 1530 1531 *virtual_voltage_id = voltage_parameters->usVoltageLevel; 1532 1533 return result; 1534 } 1535 1536 int atomctrl_get_leakage_vddc_base_on_leakage(struct pp_hwmgr *hwmgr, 1537 uint16_t *vddc, uint16_t *vddci, 1538 uint16_t virtual_voltage_id, 1539 uint16_t efuse_voltage_id) 1540 { 1541 int i, j; 1542 int ix; 1543 u16 *leakage_bin, *vddc_id_buf, *vddc_buf, *vddci_id_buf, *vddci_buf; 1544 ATOM_ASIC_PROFILING_INFO_V2_1 *profile; 1545 1546 *vddc = 0; 1547 *vddci = 0; 1548 1549 ix = GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo); 1550 1551 profile = (ATOM_ASIC_PROFILING_INFO_V2_1 *) 1552 smu_atom_get_data_table(hwmgr->adev, 1553 ix, 1554 NULL, NULL, NULL); 1555 if (!profile) 1556 return -EINVAL; 1557 1558 if ((profile->asHeader.ucTableFormatRevision >= 2) && 1559 (profile->asHeader.ucTableContentRevision >= 1) && 1560 (profile->asHeader.usStructureSize >= sizeof(ATOM_ASIC_PROFILING_INFO_V2_1))) { 1561 leakage_bin = (u16 *)((char *)profile + profile->usLeakageBinArrayOffset); 1562 vddc_id_buf = (u16 *)((char *)profile + profile->usElbVDDC_IdArrayOffset); 1563 vddc_buf = (u16 *)((char *)profile + profile->usElbVDDC_LevelArrayOffset); 1564 if (profile->ucElbVDDC_Num > 0) { 1565 for (i = 0; i < profile->ucElbVDDC_Num; i++) { 1566 if (vddc_id_buf[i] == virtual_voltage_id) { 1567 for (j = 0; j < profile->ucLeakageBinNum; j++) { 1568 if (efuse_voltage_id <= leakage_bin[j]) { 1569 *vddc = vddc_buf[j * profile->ucElbVDDC_Num + i]; 1570 break; 1571 } 1572 } 1573 break; 1574 } 1575 } 1576 } 1577 1578 vddci_id_buf = (u16 *)((char *)profile + profile->usElbVDDCI_IdArrayOffset); 1579 vddci_buf = (u16 *)((char *)profile + profile->usElbVDDCI_LevelArrayOffset); 1580 if (profile->ucElbVDDCI_Num > 0) { 1581 for (i = 0; i < profile->ucElbVDDCI_Num; i++) { 1582 if (vddci_id_buf[i] == virtual_voltage_id) { 1583 for (j = 0; j < profile->ucLeakageBinNum; j++) { 1584 if (efuse_voltage_id <= leakage_bin[j]) { 1585 *vddci = vddci_buf[j * profile->ucElbVDDCI_Num + i]; 1586 break; 1587 } 1588 } 1589 break; 1590 } 1591 } 1592 } 1593 } 1594 1595 return 0; 1596 } 1597 1598 void atomctrl_get_voltage_range(struct pp_hwmgr *hwmgr, uint32_t *max_vddc, 1599 uint32_t *min_vddc) 1600 { 1601 void *profile; 1602 1603 profile = smu_atom_get_data_table(hwmgr->adev, 1604 GetIndexIntoMasterTable(DATA, ASIC_ProfilingInfo), 1605 NULL, NULL, NULL); 1606 1607 if (profile) { 1608 switch (hwmgr->chip_id) { 1609 case CHIP_TONGA: 1610 case CHIP_FIJI: 1611 *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMaxVddc) / 4; 1612 *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_3 *)profile)->ulMinVddc) / 4; 1613 return; 1614 case CHIP_POLARIS11: 1615 case CHIP_POLARIS10: 1616 case CHIP_POLARIS12: 1617 *max_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMaxVddc) / 100; 1618 *min_vddc = le32_to_cpu(((ATOM_ASIC_PROFILING_INFO_V3_6 *)profile)->ulMinVddc) / 100; 1619 return; 1620 default: 1621 break; 1622 } 1623 } 1624 *max_vddc = 0; 1625 *min_vddc = 0; 1626 } 1627 1628 int atomctrl_get_edc_hilo_leakage_offset_table(struct pp_hwmgr *hwmgr, 1629 AtomCtrl_HiLoLeakageOffsetTable *table) 1630 { 1631 ATOM_GFX_INFO_V2_3 *gfxinfo = smu_atom_get_data_table(hwmgr->adev, 1632 GetIndexIntoMasterTable(DATA, GFX_Info), 1633 NULL, NULL, NULL); 1634 if (!gfxinfo) 1635 return -ENOENT; 1636 1637 table->usHiLoLeakageThreshold = gfxinfo->usHiLoLeakageThreshold; 1638 table->usEdcDidtLoDpm7TableOffset = gfxinfo->usEdcDidtLoDpm7TableOffset; 1639 table->usEdcDidtHiDpm7TableOffset = gfxinfo->usEdcDidtHiDpm7TableOffset; 1640 1641 return 0; 1642 } 1643 1644 static AtomCtrl_EDCLeakgeTable *get_edc_leakage_table(struct pp_hwmgr *hwmgr, 1645 uint16_t offset) 1646 { 1647 void *table_address; 1648 char *temp; 1649 1650 table_address = smu_atom_get_data_table(hwmgr->adev, 1651 GetIndexIntoMasterTable(DATA, GFX_Info), 1652 NULL, NULL, NULL); 1653 if (!table_address) 1654 return NULL; 1655 1656 temp = (char *)table_address; 1657 table_address += offset; 1658 1659 return (AtomCtrl_EDCLeakgeTable *)temp; 1660 } 1661 1662 int atomctrl_get_edc_leakage_table(struct pp_hwmgr *hwmgr, 1663 AtomCtrl_EDCLeakgeTable *table, 1664 uint16_t offset) 1665 { 1666 uint32_t length, i; 1667 AtomCtrl_EDCLeakgeTable *leakage_table = 1668 get_edc_leakage_table(hwmgr, offset); 1669 1670 if (!leakage_table) 1671 return -ENOENT; 1672 1673 length = sizeof(leakage_table->DIDT_REG) / 1674 sizeof(leakage_table->DIDT_REG[0]); 1675 for (i = 0; i < length; i++) 1676 table->DIDT_REG[i] = leakage_table->DIDT_REG[i]; 1677 1678 return 0; 1679 } 1680