1 /* $NetBSD: amdgpu_process_pptables_v1_0.c,v 1.3 2021/12/19 12:21:29 riastradh Exp $ */ 2 3 /* 4 * Copyright 2015 Advanced Micro Devices, Inc. 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be included in 14 * all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 22 * OTHER DEALINGS IN THE SOFTWARE. 23 * 24 */ 25 #include <sys/cdefs.h> 26 __KERNEL_RCSID(0, "$NetBSD: amdgpu_process_pptables_v1_0.c,v 1.3 2021/12/19 12:21:29 riastradh Exp $"); 27 28 #include "pp_debug.h" 29 #include <linux/module.h> 30 #include <linux/slab.h> 31 32 #include "process_pptables_v1_0.h" 33 #include "ppatomctrl.h" 34 #include "atombios.h" 35 #include "hwmgr.h" 36 #include "cgs_common.h" 37 #include "pptable_v1_0.h" 38 39 /** 40 * Private Function used during initialization. 41 * @param hwmgr Pointer to the hardware manager. 42 * @param setIt A flag indication if the capability should be set (TRUE) or reset (FALSE). 43 * @param cap Which capability to set/reset. 44 */ 45 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool setIt, enum phm_platform_caps cap) 46 { 47 if (setIt) 48 phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap); 49 else 50 phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap); 51 } 52 53 54 /** 55 * Private Function used during initialization. 56 * @param hwmgr Pointer to the hardware manager. 57 * @param powerplay_caps the bit array (from BIOS) of capability bits. 58 * @exception the current implementation always returns 1. 59 */ 60 static int set_platform_caps(struct pp_hwmgr *hwmgr, uint32_t powerplay_caps) 61 { 62 PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE16____), 63 "ATOM_PP_PLATFORM_CAP_ASPM_L1 is not supported!", continue); 64 PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE64____), 65 "ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY is not supported!", continue); 66 PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE512____), 67 "ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL is not supported!", continue); 68 PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE1024____), 69 "ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1 is not supported!", continue); 70 PP_ASSERT_WITH_CODE((~powerplay_caps & ____RETIRE2048____), 71 "ATOM_PP_PLATFORM_CAP_HTLINKCONTROL is not supported!", continue); 72 73 set_hw_cap( 74 hwmgr, 75 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_POWERPLAY), 76 PHM_PlatformCaps_PowerPlaySupport 77 ); 78 79 set_hw_cap( 80 hwmgr, 81 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_SBIOSPOWERSOURCE), 82 PHM_PlatformCaps_BiosPowerSourceControl 83 ); 84 85 set_hw_cap( 86 hwmgr, 87 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_HARDWAREDC), 88 PHM_PlatformCaps_AutomaticDCTransition 89 ); 90 91 set_hw_cap( 92 hwmgr, 93 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_MVDD_CONTROL), 94 PHM_PlatformCaps_EnableMVDDControl 95 ); 96 97 set_hw_cap( 98 hwmgr, 99 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDCI_CONTROL), 100 PHM_PlatformCaps_ControlVDDCI 101 ); 102 103 set_hw_cap( 104 hwmgr, 105 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_VDDGFX_CONTROL), 106 PHM_PlatformCaps_ControlVDDGFX 107 ); 108 109 set_hw_cap( 110 hwmgr, 111 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_BACO), 112 PHM_PlatformCaps_BACO 113 ); 114 115 set_hw_cap( 116 hwmgr, 117 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_CAP_DISABLE_VOLTAGE_ISLAND), 118 PHM_PlatformCaps_DisableVoltageIsland 119 ); 120 121 set_hw_cap( 122 hwmgr, 123 0 != (powerplay_caps & ATOM_TONGA_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL), 124 PHM_PlatformCaps_CombinePCCWithThermalSignal 125 ); 126 127 set_hw_cap( 128 hwmgr, 129 0 != (powerplay_caps & ATOM_TONGA_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE), 130 PHM_PlatformCaps_LoadPostProductionFirmware 131 ); 132 133 return 0; 134 } 135 136 /** 137 * Private Function to get the PowerPlay Table Address. 138 */ 139 static const void *get_powerplay_table(struct pp_hwmgr *hwmgr) 140 { 141 int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo); 142 143 u16 size; 144 u8 frev, crev; 145 const void *table_address = (const void *)hwmgr->soft_pp_table; 146 147 if (!table_address) { 148 table_address = (ATOM_Tonga_POWERPLAYTABLE *) 149 smu_atom_get_data_table(hwmgr->adev, 150 index, &size, &frev, &crev); 151 hwmgr->soft_pp_table = table_address; /*Cache the result in RAM.*/ 152 hwmgr->soft_pp_table_size = size; 153 } 154 155 return table_address; 156 } 157 158 static int get_vddc_lookup_table( 159 struct pp_hwmgr *hwmgr, 160 phm_ppt_v1_voltage_lookup_table **lookup_table, 161 const ATOM_Tonga_Voltage_Lookup_Table *vddc_lookup_pp_tables, 162 uint32_t max_levels 163 ) 164 { 165 uint32_t table_size, i; 166 phm_ppt_v1_voltage_lookup_table *table; 167 phm_ppt_v1_voltage_lookup_record *record; 168 ATOM_Tonga_Voltage_Lookup_Record *atom_record; 169 170 PP_ASSERT_WITH_CODE((0 != vddc_lookup_pp_tables->ucNumEntries), 171 "Invalid CAC Leakage PowerPlay Table!", return 1); 172 173 table_size = sizeof(uint32_t) + 174 sizeof(phm_ppt_v1_voltage_lookup_record) * max_levels; 175 176 table = kzalloc(table_size, GFP_KERNEL); 177 178 if (NULL == table) 179 return -ENOMEM; 180 181 table->count = vddc_lookup_pp_tables->ucNumEntries; 182 183 for (i = 0; i < vddc_lookup_pp_tables->ucNumEntries; i++) { 184 record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 185 phm_ppt_v1_voltage_lookup_record, 186 entries, table, i); 187 atom_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 188 ATOM_Tonga_Voltage_Lookup_Record, 189 entries, vddc_lookup_pp_tables, i); 190 record->us_calculated = 0; 191 record->us_vdd = le16_to_cpu(atom_record->usVdd); 192 record->us_cac_low = le16_to_cpu(atom_record->usCACLow); 193 record->us_cac_mid = le16_to_cpu(atom_record->usCACMid); 194 record->us_cac_high = le16_to_cpu(atom_record->usCACHigh); 195 } 196 197 *lookup_table = table; 198 199 return 0; 200 } 201 202 /** 203 * Private Function used during initialization. 204 * Initialize Platform Power Management Parameter table 205 * @param hwmgr Pointer to the hardware manager. 206 * @param atom_ppm_table Pointer to PPM table in VBIOS 207 */ 208 static int get_platform_power_management_table( 209 struct pp_hwmgr *hwmgr, 210 ATOM_Tonga_PPM_Table *atom_ppm_table) 211 { 212 struct phm_ppm_table *ptr = kzalloc(sizeof(ATOM_Tonga_PPM_Table), GFP_KERNEL); 213 struct phm_ppt_v1_information *pp_table_information = 214 (struct phm_ppt_v1_information *)(hwmgr->pptable); 215 216 if (NULL == ptr) 217 return -ENOMEM; 218 219 ptr->ppm_design 220 = atom_ppm_table->ucPpmDesign; 221 ptr->cpu_core_number 222 = le16_to_cpu(atom_ppm_table->usCpuCoreNumber); 223 ptr->platform_tdp 224 = le32_to_cpu(atom_ppm_table->ulPlatformTDP); 225 ptr->small_ac_platform_tdp 226 = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP); 227 ptr->platform_tdc 228 = le32_to_cpu(atom_ppm_table->ulPlatformTDC); 229 ptr->small_ac_platform_tdc 230 = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC); 231 ptr->apu_tdp 232 = le32_to_cpu(atom_ppm_table->ulApuTDP); 233 ptr->dgpu_tdp 234 = le32_to_cpu(atom_ppm_table->ulDGpuTDP); 235 ptr->dgpu_ulv_power 236 = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower); 237 ptr->tj_max 238 = le32_to_cpu(atom_ppm_table->ulTjmax); 239 240 pp_table_information->ppm_parameter_table = ptr; 241 242 return 0; 243 } 244 245 /** 246 * Private Function used during initialization. 247 * Initialize TDP limits for DPM2 248 * @param hwmgr Pointer to the hardware manager. 249 * @param powerplay_table Pointer to the PowerPlay Table. 250 */ 251 static int init_dpm_2_parameters( 252 struct pp_hwmgr *hwmgr, 253 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table 254 ) 255 { 256 int result = 0; 257 struct phm_ppt_v1_information *pp_table_information = (struct phm_ppt_v1_information *)(hwmgr->pptable); 258 ATOM_Tonga_PPM_Table *atom_ppm_table; 259 uint32_t disable_ppm = 0; 260 uint32_t disable_power_control = 0; 261 262 pp_table_information->us_ulv_voltage_offset = 263 le16_to_cpu(powerplay_table->usUlvVoltageOffset); 264 265 pp_table_information->ppm_parameter_table = NULL; 266 pp_table_information->vddc_lookup_table = NULL; 267 pp_table_information->vddgfx_lookup_table = NULL; 268 /* TDP limits */ 269 hwmgr->platform_descriptor.TDPODLimit = 270 le16_to_cpu(powerplay_table->usPowerControlLimit); 271 hwmgr->platform_descriptor.TDPAdjustment = 0; 272 hwmgr->platform_descriptor.VidAdjustment = 0; 273 hwmgr->platform_descriptor.VidAdjustmentPolarity = 0; 274 hwmgr->platform_descriptor.VidMinLimit = 0; 275 hwmgr->platform_descriptor.VidMaxLimit = 1500000; 276 hwmgr->platform_descriptor.VidStep = 6250; 277 278 disable_power_control = 0; 279 if (0 == disable_power_control) { 280 /* enable TDP overdrive (PowerControl) feature as well if supported */ 281 if (hwmgr->platform_descriptor.TDPODLimit != 0) 282 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 283 PHM_PlatformCaps_PowerControl); 284 } 285 286 if (0 != powerplay_table->usVddcLookupTableOffset) { 287 const ATOM_Tonga_Voltage_Lookup_Table *pVddcCACTable = 288 (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + 289 le16_to_cpu(powerplay_table->usVddcLookupTableOffset)); 290 291 result = get_vddc_lookup_table(hwmgr, 292 &pp_table_information->vddc_lookup_table, pVddcCACTable, 16); 293 } 294 295 if (0 != powerplay_table->usVddgfxLookupTableOffset) { 296 const ATOM_Tonga_Voltage_Lookup_Table *pVddgfxCACTable = 297 (ATOM_Tonga_Voltage_Lookup_Table *)(((unsigned long)powerplay_table) + 298 le16_to_cpu(powerplay_table->usVddgfxLookupTableOffset)); 299 300 result = get_vddc_lookup_table(hwmgr, 301 &pp_table_information->vddgfx_lookup_table, pVddgfxCACTable, 16); 302 } 303 304 disable_ppm = 0; 305 if (0 == disable_ppm) { 306 atom_ppm_table = (ATOM_Tonga_PPM_Table *) 307 (((unsigned long)powerplay_table) + le16_to_cpu(powerplay_table->usPPMTableOffset)); 308 309 if (0 != powerplay_table->usPPMTableOffset) { 310 if (get_platform_power_management_table(hwmgr, atom_ppm_table) == 0) { 311 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 312 PHM_PlatformCaps_EnablePlatformPowerManagement); 313 } 314 } 315 } 316 317 return result; 318 } 319 320 static int get_valid_clk( 321 struct pp_hwmgr *hwmgr, 322 struct phm_clock_array **clk_table, 323 phm_ppt_v1_clock_voltage_dependency_table const *clk_volt_pp_table 324 ) 325 { 326 uint32_t table_size, i; 327 struct phm_clock_array *table; 328 phm_ppt_v1_clock_voltage_dependency_record *dep_record; 329 330 PP_ASSERT_WITH_CODE((0 != clk_volt_pp_table->count), 331 "Invalid PowerPlay Table!", return -1); 332 333 table_size = sizeof(uint32_t) + 334 sizeof(uint32_t) * clk_volt_pp_table->count; 335 336 table = kzalloc(table_size, GFP_KERNEL); 337 338 if (NULL == table) 339 return -ENOMEM; 340 341 table->count = (uint32_t)clk_volt_pp_table->count; 342 343 for (i = 0; i < table->count; i++) { 344 dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 345 phm_ppt_v1_clock_voltage_dependency_record, 346 entries, clk_volt_pp_table, i); 347 table->values[i] = (uint32_t)dep_record->clk; 348 } 349 *clk_table = table; 350 351 return 0; 352 } 353 354 static int get_hard_limits( 355 struct pp_hwmgr *hwmgr, 356 struct phm_clock_and_voltage_limits *limits, 357 ATOM_Tonga_Hard_Limit_Table const *limitable 358 ) 359 { 360 PP_ASSERT_WITH_CODE((0 != limitable->ucNumEntries), "Invalid PowerPlay Table!", return -1); 361 362 /* currently we always take entries[0] parameters */ 363 limits->sclk = le32_to_cpu(limitable->entries[0].ulSCLKLimit); 364 limits->mclk = le32_to_cpu(limitable->entries[0].ulMCLKLimit); 365 limits->vddc = le16_to_cpu(limitable->entries[0].usVddcLimit); 366 limits->vddci = le16_to_cpu(limitable->entries[0].usVddciLimit); 367 limits->vddgfx = le16_to_cpu(limitable->entries[0].usVddgfxLimit); 368 369 return 0; 370 } 371 372 static int get_mclk_voltage_dependency_table( 373 struct pp_hwmgr *hwmgr, 374 phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_mclk_dep_table, 375 ATOM_Tonga_MCLK_Dependency_Table const *mclk_dep_table 376 ) 377 { 378 uint32_t table_size, i; 379 phm_ppt_v1_clock_voltage_dependency_table *mclk_table; 380 phm_ppt_v1_clock_voltage_dependency_record *mclk_table_record; 381 ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; 382 383 PP_ASSERT_WITH_CODE((0 != mclk_dep_table->ucNumEntries), 384 "Invalid PowerPlay Table!", return -1); 385 386 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) 387 * mclk_dep_table->ucNumEntries; 388 389 mclk_table = kzalloc(table_size, GFP_KERNEL); 390 391 if (NULL == mclk_table) 392 return -ENOMEM; 393 394 mclk_table->count = (uint32_t)mclk_dep_table->ucNumEntries; 395 396 for (i = 0; i < mclk_dep_table->ucNumEntries; i++) { 397 mclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 398 phm_ppt_v1_clock_voltage_dependency_record, 399 entries, mclk_table, i); 400 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 401 ATOM_Tonga_MCLK_Dependency_Record, 402 entries, mclk_dep_table, i); 403 mclk_table_record->vddInd = mclk_dep_record->ucVddcInd; 404 mclk_table_record->vdd_offset = le16_to_cpu(mclk_dep_record->usVddgfxOffset); 405 mclk_table_record->vddci = le16_to_cpu(mclk_dep_record->usVddci); 406 mclk_table_record->mvdd = le16_to_cpu(mclk_dep_record->usMvdd); 407 mclk_table_record->clk = le32_to_cpu(mclk_dep_record->ulMclk); 408 } 409 410 *pp_tonga_mclk_dep_table = mclk_table; 411 412 return 0; 413 } 414 415 static int get_sclk_voltage_dependency_table( 416 struct pp_hwmgr *hwmgr, 417 phm_ppt_v1_clock_voltage_dependency_table **pp_tonga_sclk_dep_table, 418 PPTable_Generic_SubTable_Header const *sclk_dep_table 419 ) 420 { 421 uint32_t table_size, i; 422 phm_ppt_v1_clock_voltage_dependency_table *sclk_table; 423 phm_ppt_v1_clock_voltage_dependency_record *sclk_table_record; 424 425 if (sclk_dep_table->ucRevId < 1) { 426 const ATOM_Tonga_SCLK_Dependency_Table *tonga_table = 427 (const ATOM_Tonga_SCLK_Dependency_Table *)sclk_dep_table; 428 ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record; 429 430 PP_ASSERT_WITH_CODE((0 != tonga_table->ucNumEntries), 431 "Invalid PowerPlay Table!", return -1); 432 433 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) 434 * tonga_table->ucNumEntries; 435 436 sclk_table = kzalloc(table_size, GFP_KERNEL); 437 438 if (NULL == sclk_table) 439 return -ENOMEM; 440 441 sclk_table->count = (uint32_t)tonga_table->ucNumEntries; 442 443 for (i = 0; i < tonga_table->ucNumEntries; i++) { 444 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 445 ATOM_Tonga_SCLK_Dependency_Record, 446 entries, tonga_table, i); 447 sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 448 phm_ppt_v1_clock_voltage_dependency_record, 449 entries, sclk_table, i); 450 sclk_table_record->vddInd = sclk_dep_record->ucVddInd; 451 sclk_table_record->vdd_offset = le16_to_cpu(sclk_dep_record->usVddcOffset); 452 sclk_table_record->clk = le32_to_cpu(sclk_dep_record->ulSclk); 453 sclk_table_record->cks_enable = 454 (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0; 455 sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F); 456 } 457 } else { 458 const ATOM_Polaris_SCLK_Dependency_Table *polaris_table = 459 (const ATOM_Polaris_SCLK_Dependency_Table *)sclk_dep_table; 460 ATOM_Polaris_SCLK_Dependency_Record *sclk_dep_record; 461 462 PP_ASSERT_WITH_CODE((0 != polaris_table->ucNumEntries), 463 "Invalid PowerPlay Table!", return -1); 464 465 table_size = sizeof(uint32_t) + sizeof(phm_ppt_v1_clock_voltage_dependency_record) 466 * polaris_table->ucNumEntries; 467 468 sclk_table = kzalloc(table_size, GFP_KERNEL); 469 470 if (NULL == sclk_table) 471 return -ENOMEM; 472 473 sclk_table->count = (uint32_t)polaris_table->ucNumEntries; 474 475 for (i = 0; i < polaris_table->ucNumEntries; i++) { 476 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 477 ATOM_Polaris_SCLK_Dependency_Record, 478 entries, polaris_table, i); 479 sclk_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 480 phm_ppt_v1_clock_voltage_dependency_record, 481 entries, sclk_table, i); 482 sclk_table_record->vddInd = sclk_dep_record->ucVddInd; 483 sclk_table_record->vdd_offset = le16_to_cpu(sclk_dep_record->usVddcOffset); 484 sclk_table_record->clk = le32_to_cpu(sclk_dep_record->ulSclk); 485 sclk_table_record->cks_enable = 486 (((sclk_dep_record->ucCKSVOffsetandDisable & 0x80) >> 7) == 0) ? 1 : 0; 487 sclk_table_record->cks_voffset = (sclk_dep_record->ucCKSVOffsetandDisable & 0x7F); 488 sclk_table_record->sclk_offset = le32_to_cpu(sclk_dep_record->ulSclkOffset); 489 } 490 } 491 *pp_tonga_sclk_dep_table = sclk_table; 492 493 return 0; 494 } 495 496 static int get_pcie_table( 497 struct pp_hwmgr *hwmgr, 498 phm_ppt_v1_pcie_table **pp_tonga_pcie_table, 499 PPTable_Generic_SubTable_Header const *ptable 500 ) 501 { 502 uint32_t table_size, i, pcie_count; 503 phm_ppt_v1_pcie_table *pcie_table; 504 struct phm_ppt_v1_information *pp_table_information = 505 (struct phm_ppt_v1_information *)(hwmgr->pptable); 506 phm_ppt_v1_pcie_record *pcie_record; 507 508 if (ptable->ucRevId < 1) { 509 const ATOM_Tonga_PCIE_Table *atom_pcie_table = (const ATOM_Tonga_PCIE_Table *)ptable; 510 ATOM_Tonga_PCIE_Record *atom_pcie_record; 511 512 PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), 513 "Invalid PowerPlay Table!", return -1); 514 515 table_size = sizeof(uint32_t) + 516 sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries; 517 518 pcie_table = kzalloc(table_size, GFP_KERNEL); 519 520 if (pcie_table == NULL) 521 return -ENOMEM; 522 523 /* 524 * Make sure the number of pcie entries are less than or equal to sclk dpm levels. 525 * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1. 526 */ 527 pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1; 528 if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count) 529 pcie_count = (uint32_t)atom_pcie_table->ucNumEntries; 530 else 531 pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! Disregarding the excess entries...\n"); 532 533 pcie_table->count = pcie_count; 534 for (i = 0; i < pcie_count; i++) { 535 pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 536 phm_ppt_v1_pcie_record, 537 entries, pcie_table, i); 538 atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 539 ATOM_Tonga_PCIE_Record, 540 entries, atom_pcie_table, i); 541 pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed; 542 pcie_record->lane_width = le16_to_cpu(atom_pcie_record->usPCIELaneWidth); 543 } 544 545 *pp_tonga_pcie_table = pcie_table; 546 } else { 547 /* Polaris10/Polaris11 and newer. */ 548 const ATOM_Polaris10_PCIE_Table *atom_pcie_table = (const ATOM_Polaris10_PCIE_Table *)ptable; 549 ATOM_Polaris10_PCIE_Record *atom_pcie_record; 550 551 PP_ASSERT_WITH_CODE((atom_pcie_table->ucNumEntries != 0), 552 "Invalid PowerPlay Table!", return -1); 553 554 table_size = sizeof(uint32_t) + 555 sizeof(phm_ppt_v1_pcie_record) * atom_pcie_table->ucNumEntries; 556 557 pcie_table = kzalloc(table_size, GFP_KERNEL); 558 559 if (pcie_table == NULL) 560 return -ENOMEM; 561 562 /* 563 * Make sure the number of pcie entries are less than or equal to sclk dpm levels. 564 * Since first PCIE entry is for ULV, #pcie has to be <= SclkLevel + 1. 565 */ 566 pcie_count = (pp_table_information->vdd_dep_on_sclk->count) + 1; 567 if ((uint32_t)atom_pcie_table->ucNumEntries <= pcie_count) 568 pcie_count = (uint32_t)atom_pcie_table->ucNumEntries; 569 else 570 pr_err("Number of Pcie Entries exceed the number of SCLK Dpm Levels! Disregarding the excess entries...\n"); 571 572 pcie_table->count = pcie_count; 573 574 for (i = 0; i < pcie_count; i++) { 575 pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 576 phm_ppt_v1_pcie_record, 577 entries, pcie_table, i); 578 atom_pcie_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 579 ATOM_Polaris10_PCIE_Record, 580 entries, atom_pcie_table, i); 581 pcie_record->gen_speed = atom_pcie_record->ucPCIEGenSpeed; 582 pcie_record->lane_width = le16_to_cpu(atom_pcie_record->usPCIELaneWidth); 583 pcie_record->pcie_sclk = le32_to_cpu(atom_pcie_record->ulPCIE_Sclk); 584 } 585 586 *pp_tonga_pcie_table = pcie_table; 587 } 588 589 return 0; 590 } 591 592 static int get_cac_tdp_table( 593 struct pp_hwmgr *hwmgr, 594 struct phm_cac_tdp_table **cac_tdp_table, 595 const PPTable_Generic_SubTable_Header * table 596 ) 597 { 598 uint32_t table_size; 599 struct phm_cac_tdp_table *tdp_table; 600 601 table_size = sizeof(uint32_t) + sizeof(struct phm_cac_tdp_table); 602 tdp_table = kzalloc(table_size, GFP_KERNEL); 603 604 if (NULL == tdp_table) 605 return -ENOMEM; 606 607 hwmgr->dyn_state.cac_dtp_table = kzalloc(table_size, GFP_KERNEL); 608 609 if (NULL == hwmgr->dyn_state.cac_dtp_table) { 610 kfree(tdp_table); 611 return -ENOMEM; 612 } 613 614 if (table->ucRevId < 3) { 615 const ATOM_Tonga_PowerTune_Table *tonga_table = 616 (const ATOM_Tonga_PowerTune_Table *)table; 617 tdp_table->usTDP = le16_to_cpu(tonga_table->usTDP); 618 tdp_table->usConfigurableTDP = 619 le16_to_cpu(tonga_table->usConfigurableTDP); 620 tdp_table->usTDC = le16_to_cpu(tonga_table->usTDC); 621 tdp_table->usBatteryPowerLimit = 622 le16_to_cpu(tonga_table->usBatteryPowerLimit); 623 tdp_table->usSmallPowerLimit = 624 le16_to_cpu(tonga_table->usSmallPowerLimit); 625 tdp_table->usLowCACLeakage = 626 le16_to_cpu(tonga_table->usLowCACLeakage); 627 tdp_table->usHighCACLeakage = 628 le16_to_cpu(tonga_table->usHighCACLeakage); 629 tdp_table->usMaximumPowerDeliveryLimit = 630 le16_to_cpu(tonga_table->usMaximumPowerDeliveryLimit); 631 tdp_table->usDefaultTargetOperatingTemp = 632 le16_to_cpu(tonga_table->usTjMax); 633 tdp_table->usTargetOperatingTemp = 634 le16_to_cpu(tonga_table->usTjMax); /*Set the initial temp to the same as default */ 635 tdp_table->usPowerTuneDataSetID = 636 le16_to_cpu(tonga_table->usPowerTuneDataSetID); 637 tdp_table->usSoftwareShutdownTemp = 638 le16_to_cpu(tonga_table->usSoftwareShutdownTemp); 639 tdp_table->usClockStretchAmount = 640 le16_to_cpu(tonga_table->usClockStretchAmount); 641 } else { /* Fiji and newer */ 642 const ATOM_Fiji_PowerTune_Table *fijitable = 643 (const ATOM_Fiji_PowerTune_Table *)table; 644 tdp_table->usTDP = le16_to_cpu(fijitable->usTDP); 645 tdp_table->usConfigurableTDP = le16_to_cpu(fijitable->usConfigurableTDP); 646 tdp_table->usTDC = le16_to_cpu(fijitable->usTDC); 647 tdp_table->usBatteryPowerLimit = le16_to_cpu(fijitable->usBatteryPowerLimit); 648 tdp_table->usSmallPowerLimit = le16_to_cpu(fijitable->usSmallPowerLimit); 649 tdp_table->usLowCACLeakage = le16_to_cpu(fijitable->usLowCACLeakage); 650 tdp_table->usHighCACLeakage = le16_to_cpu(fijitable->usHighCACLeakage); 651 tdp_table->usMaximumPowerDeliveryLimit = 652 le16_to_cpu(fijitable->usMaximumPowerDeliveryLimit); 653 tdp_table->usDefaultTargetOperatingTemp = 654 le16_to_cpu(fijitable->usTjMax); 655 tdp_table->usTargetOperatingTemp = 656 le16_to_cpu(fijitable->usTjMax); /*Set the initial temp to the same as default */ 657 tdp_table->usPowerTuneDataSetID = 658 le16_to_cpu(fijitable->usPowerTuneDataSetID); 659 tdp_table->usSoftwareShutdownTemp = 660 le16_to_cpu(fijitable->usSoftwareShutdownTemp); 661 tdp_table->usClockStretchAmount = 662 le16_to_cpu(fijitable->usClockStretchAmount); 663 tdp_table->usTemperatureLimitHotspot = 664 le16_to_cpu(fijitable->usTemperatureLimitHotspot); 665 tdp_table->usTemperatureLimitLiquid1 = 666 le16_to_cpu(fijitable->usTemperatureLimitLiquid1); 667 tdp_table->usTemperatureLimitLiquid2 = 668 le16_to_cpu(fijitable->usTemperatureLimitLiquid2); 669 tdp_table->usTemperatureLimitVrVddc = 670 le16_to_cpu(fijitable->usTemperatureLimitVrVddc); 671 tdp_table->usTemperatureLimitVrMvdd = 672 le16_to_cpu(fijitable->usTemperatureLimitVrMvdd); 673 tdp_table->usTemperatureLimitPlx = 674 le16_to_cpu(fijitable->usTemperatureLimitPlx); 675 tdp_table->ucLiquid1_I2C_address = 676 fijitable->ucLiquid1_I2C_address; 677 tdp_table->ucLiquid2_I2C_address = 678 fijitable->ucLiquid2_I2C_address; 679 tdp_table->ucLiquid_I2C_Line = 680 fijitable->ucLiquid_I2C_Line; 681 tdp_table->ucVr_I2C_address = fijitable->ucVr_I2C_address; 682 tdp_table->ucVr_I2C_Line = fijitable->ucVr_I2C_Line; 683 tdp_table->ucPlx_I2C_address = fijitable->ucPlx_I2C_address; 684 tdp_table->ucPlx_I2C_Line = fijitable->ucPlx_I2C_Line; 685 } 686 687 *cac_tdp_table = tdp_table; 688 689 return 0; 690 } 691 692 static int get_mm_clock_voltage_table( 693 struct pp_hwmgr *hwmgr, 694 phm_ppt_v1_mm_clock_voltage_dependency_table **tonga_mm_table, 695 const ATOM_Tonga_MM_Dependency_Table * mm_dependency_table 696 ) 697 { 698 uint32_t table_size, i; 699 const ATOM_Tonga_MM_Dependency_Record *mm_dependency_record; 700 phm_ppt_v1_mm_clock_voltage_dependency_table *mm_table; 701 phm_ppt_v1_mm_clock_voltage_dependency_record *mm_table_record; 702 703 PP_ASSERT_WITH_CODE((0 != mm_dependency_table->ucNumEntries), 704 "Invalid PowerPlay Table!", return -1); 705 table_size = sizeof(uint32_t) + 706 sizeof(phm_ppt_v1_mm_clock_voltage_dependency_record) 707 * mm_dependency_table->ucNumEntries; 708 mm_table = kzalloc(table_size, GFP_KERNEL); 709 710 if (NULL == mm_table) 711 return -ENOMEM; 712 713 mm_table->count = mm_dependency_table->ucNumEntries; 714 715 for (i = 0; i < mm_dependency_table->ucNumEntries; i++) { 716 mm_dependency_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 717 ATOM_Tonga_MM_Dependency_Record, 718 entries, mm_dependency_table, i); 719 mm_table_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 720 phm_ppt_v1_mm_clock_voltage_dependency_record, 721 entries, mm_table, i); 722 mm_table_record->vddcInd = mm_dependency_record->ucVddcInd; 723 mm_table_record->vddgfx_offset = le16_to_cpu(mm_dependency_record->usVddgfxOffset); 724 mm_table_record->aclk = le32_to_cpu(mm_dependency_record->ulAClk); 725 mm_table_record->samclock = le32_to_cpu(mm_dependency_record->ulSAMUClk); 726 mm_table_record->eclk = le32_to_cpu(mm_dependency_record->ulEClk); 727 mm_table_record->vclk = le32_to_cpu(mm_dependency_record->ulVClk); 728 mm_table_record->dclk = le32_to_cpu(mm_dependency_record->ulDClk); 729 } 730 731 *tonga_mm_table = mm_table; 732 733 return 0; 734 } 735 736 static int get_gpio_table(struct pp_hwmgr *hwmgr, 737 struct phm_ppt_v1_gpio_table **pp_tonga_gpio_table, 738 const ATOM_Tonga_GPIO_Table *atom_gpio_table) 739 { 740 uint32_t table_size; 741 struct phm_ppt_v1_gpio_table *pp_gpio_table; 742 struct phm_ppt_v1_information *pp_table_information = 743 (struct phm_ppt_v1_information *)(hwmgr->pptable); 744 745 table_size = sizeof(struct phm_ppt_v1_gpio_table); 746 pp_gpio_table = kzalloc(table_size, GFP_KERNEL); 747 if (!pp_gpio_table) 748 return -ENOMEM; 749 750 if (pp_table_information->vdd_dep_on_sclk->count < 751 atom_gpio_table->ucVRHotTriggeredSclkDpmIndex) 752 PP_ASSERT_WITH_CODE(false, 753 "SCLK DPM index for VRHot cannot exceed the total sclk level count!",); 754 else 755 pp_gpio_table->vrhot_triggered_sclk_dpm_index = 756 atom_gpio_table->ucVRHotTriggeredSclkDpmIndex; 757 758 *pp_tonga_gpio_table = pp_gpio_table; 759 760 return 0; 761 } 762 /** 763 * Private Function used during initialization. 764 * Initialize clock voltage dependency 765 * @param hwmgr Pointer to the hardware manager. 766 * @param powerplay_table Pointer to the PowerPlay Table. 767 */ 768 static int init_clock_voltage_dependency( 769 struct pp_hwmgr *hwmgr, 770 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table 771 ) 772 { 773 int result = 0; 774 struct phm_ppt_v1_information *pp_table_information = 775 (struct phm_ppt_v1_information *)(hwmgr->pptable); 776 777 const ATOM_Tonga_MM_Dependency_Table *mm_dependency_table = 778 (const ATOM_Tonga_MM_Dependency_Table *)(((unsigned long) powerplay_table) + 779 le16_to_cpu(powerplay_table->usMMDependencyTableOffset)); 780 const PPTable_Generic_SubTable_Header *pPowerTuneTable = 781 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + 782 le16_to_cpu(powerplay_table->usPowerTuneTableOffset)); 783 const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = 784 (const ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long) powerplay_table) + 785 le16_to_cpu(powerplay_table->usMclkDependencyTableOffset)); 786 const PPTable_Generic_SubTable_Header *sclk_dep_table = 787 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + 788 le16_to_cpu(powerplay_table->usSclkDependencyTableOffset)); 789 const ATOM_Tonga_Hard_Limit_Table *pHardLimits = 790 (const ATOM_Tonga_Hard_Limit_Table *)(((unsigned long) powerplay_table) + 791 le16_to_cpu(powerplay_table->usHardLimitTableOffset)); 792 const PPTable_Generic_SubTable_Header *pcie_table = 793 (const PPTable_Generic_SubTable_Header *)(((unsigned long) powerplay_table) + 794 le16_to_cpu(powerplay_table->usPCIETableOffset)); 795 const ATOM_Tonga_GPIO_Table *gpio_table = 796 (const ATOM_Tonga_GPIO_Table *)(((unsigned long) powerplay_table) + 797 le16_to_cpu(powerplay_table->usGPIOTableOffset)); 798 799 pp_table_information->vdd_dep_on_sclk = NULL; 800 pp_table_information->vdd_dep_on_mclk = NULL; 801 pp_table_information->mm_dep_table = NULL; 802 pp_table_information->pcie_table = NULL; 803 pp_table_information->gpio_table = NULL; 804 805 if (powerplay_table->usMMDependencyTableOffset != 0) 806 result = get_mm_clock_voltage_table(hwmgr, 807 &pp_table_information->mm_dep_table, mm_dependency_table); 808 809 if (result == 0 && powerplay_table->usPowerTuneTableOffset != 0) 810 result = get_cac_tdp_table(hwmgr, 811 &pp_table_information->cac_dtp_table, pPowerTuneTable); 812 813 if (result == 0 && powerplay_table->usSclkDependencyTableOffset != 0) 814 result = get_sclk_voltage_dependency_table(hwmgr, 815 &pp_table_information->vdd_dep_on_sclk, sclk_dep_table); 816 817 if (result == 0 && powerplay_table->usMclkDependencyTableOffset != 0) 818 result = get_mclk_voltage_dependency_table(hwmgr, 819 &pp_table_information->vdd_dep_on_mclk, mclk_dep_table); 820 821 if (result == 0 && powerplay_table->usPCIETableOffset != 0) 822 result = get_pcie_table(hwmgr, 823 &pp_table_information->pcie_table, pcie_table); 824 825 if (result == 0 && powerplay_table->usHardLimitTableOffset != 0) 826 result = get_hard_limits(hwmgr, 827 &pp_table_information->max_clock_voltage_on_dc, pHardLimits); 828 829 hwmgr->dyn_state.max_clock_voltage_on_dc.sclk = 830 pp_table_information->max_clock_voltage_on_dc.sclk; 831 hwmgr->dyn_state.max_clock_voltage_on_dc.mclk = 832 pp_table_information->max_clock_voltage_on_dc.mclk; 833 hwmgr->dyn_state.max_clock_voltage_on_dc.vddc = 834 pp_table_information->max_clock_voltage_on_dc.vddc; 835 hwmgr->dyn_state.max_clock_voltage_on_dc.vddci = 836 pp_table_information->max_clock_voltage_on_dc.vddci; 837 838 if (result == 0 && (NULL != pp_table_information->vdd_dep_on_mclk) 839 && (0 != pp_table_information->vdd_dep_on_mclk->count)) 840 result = get_valid_clk(hwmgr, &pp_table_information->valid_mclk_values, 841 pp_table_information->vdd_dep_on_mclk); 842 843 if (result == 0 && (NULL != pp_table_information->vdd_dep_on_sclk) 844 && (0 != pp_table_information->vdd_dep_on_sclk->count)) 845 result = get_valid_clk(hwmgr, &pp_table_information->valid_sclk_values, 846 pp_table_information->vdd_dep_on_sclk); 847 848 if (!result && gpio_table) 849 result = get_gpio_table(hwmgr, &pp_table_information->gpio_table, 850 gpio_table); 851 852 return result; 853 } 854 855 /** Retrieves the (signed) Overdrive limits from VBIOS. 856 * The max engine clock, memory clock and max temperature come from the firmware info table. 857 * 858 * The information is placed into the platform descriptor. 859 * 860 * @param hwmgr source of the VBIOS table and owner of the platform descriptor to be updated. 861 * @param powerplay_table the address of the PowerPlay table. 862 * 863 * @return 1 as long as the firmware info table was present and of a supported version. 864 */ 865 static int init_over_drive_limits( 866 struct pp_hwmgr *hwmgr, 867 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table) 868 { 869 hwmgr->platform_descriptor.overdriveLimit.engineClock = 870 le32_to_cpu(powerplay_table->ulMaxODEngineClock); 871 hwmgr->platform_descriptor.overdriveLimit.memoryClock = 872 le32_to_cpu(powerplay_table->ulMaxODMemoryClock); 873 874 hwmgr->platform_descriptor.minOverdriveVDDC = 0; 875 hwmgr->platform_descriptor.maxOverdriveVDDC = 0; 876 hwmgr->platform_descriptor.overdriveVDDCStep = 0; 877 878 return 0; 879 } 880 881 /** 882 * Private Function used during initialization. 883 * Inspect the PowerPlay table for obvious signs of corruption. 884 * @param hwmgr Pointer to the hardware manager. 885 * @param powerplay_table Pointer to the PowerPlay Table. 886 * @exception This implementation always returns 1. 887 */ 888 static int init_thermal_controller( 889 struct pp_hwmgr *hwmgr, 890 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table 891 ) 892 { 893 const PPTable_Generic_SubTable_Header *fan_table; 894 ATOM_Tonga_Thermal_Controller *thermal_controller; 895 896 thermal_controller = (ATOM_Tonga_Thermal_Controller *) 897 (((unsigned long)powerplay_table) + 898 le16_to_cpu(powerplay_table->usThermalControllerOffset)); 899 PP_ASSERT_WITH_CODE((0 != powerplay_table->usThermalControllerOffset), 900 "Thermal controller table not set!", return -1); 901 902 hwmgr->thermal_controller.ucType = thermal_controller->ucType; 903 hwmgr->thermal_controller.ucI2cLine = thermal_controller->ucI2cLine; 904 hwmgr->thermal_controller.ucI2cAddress = thermal_controller->ucI2cAddress; 905 906 hwmgr->thermal_controller.fanInfo.bNoFan = 907 (0 != (thermal_controller->ucFanParameters & ATOM_TONGA_PP_FANPARAMETERS_NOFAN)); 908 909 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = 910 thermal_controller->ucFanParameters & 911 ATOM_TONGA_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; 912 913 hwmgr->thermal_controller.fanInfo.ulMinRPM 914 = thermal_controller->ucFanMinRPM * 100UL; 915 hwmgr->thermal_controller.fanInfo.ulMaxRPM 916 = thermal_controller->ucFanMaxRPM * 100UL; 917 918 set_hw_cap( 919 hwmgr, 920 ATOM_TONGA_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType, 921 PHM_PlatformCaps_ThermalController 922 ); 923 924 if (0 == powerplay_table->usFanTableOffset) { 925 hwmgr->thermal_controller.use_hw_fan_control = 1; 926 return 0; 927 } 928 929 fan_table = (const PPTable_Generic_SubTable_Header *) 930 (((unsigned long)powerplay_table) + 931 le16_to_cpu(powerplay_table->usFanTableOffset)); 932 933 PP_ASSERT_WITH_CODE((0 != powerplay_table->usFanTableOffset), 934 "Fan table not set!", return -1); 935 PP_ASSERT_WITH_CODE((0 < fan_table->ucRevId), 936 "Unsupported fan table format!", return -1); 937 938 hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay 939 = 100000; 940 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 941 PHM_PlatformCaps_MicrocodeFanControl); 942 943 if (fan_table->ucRevId < 8) { 944 const ATOM_Tonga_Fan_Table *tonga_fan_table = 945 (const ATOM_Tonga_Fan_Table *)fan_table; 946 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst 947 = tonga_fan_table->ucTHyst; 948 hwmgr->thermal_controller.advanceFanControlParameters.usTMin 949 = le16_to_cpu(tonga_fan_table->usTMin); 950 hwmgr->thermal_controller.advanceFanControlParameters.usTMed 951 = le16_to_cpu(tonga_fan_table->usTMed); 952 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh 953 = le16_to_cpu(tonga_fan_table->usTHigh); 954 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin 955 = le16_to_cpu(tonga_fan_table->usPWMMin); 956 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed 957 = le16_to_cpu(tonga_fan_table->usPWMMed); 958 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh 959 = le16_to_cpu(tonga_fan_table->usPWMHigh); 960 hwmgr->thermal_controller.advanceFanControlParameters.usTMax 961 = 10900; /* hard coded */ 962 hwmgr->thermal_controller.advanceFanControlParameters.usTMax 963 = le16_to_cpu(tonga_fan_table->usTMax); 964 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode 965 = tonga_fan_table->ucFanControlMode; 966 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM 967 = le16_to_cpu(tonga_fan_table->usFanPWMMax); 968 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity 969 = 4836; 970 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity 971 = le16_to_cpu(tonga_fan_table->usFanOutputSensitivity); 972 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM 973 = le16_to_cpu(tonga_fan_table->usFanRPMMax); 974 hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit 975 = (le32_to_cpu(tonga_fan_table->ulMinFanSCLKAcousticLimit) / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */ 976 hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature 977 = tonga_fan_table->ucTargetTemperature; 978 hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit 979 = tonga_fan_table->ucMinimumPWMLimit; 980 } else { 981 const ATOM_Fiji_Fan_Table *fiji_fan_table = 982 (const ATOM_Fiji_Fan_Table *)fan_table; 983 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst 984 = fiji_fan_table->ucTHyst; 985 hwmgr->thermal_controller.advanceFanControlParameters.usTMin 986 = le16_to_cpu(fiji_fan_table->usTMin); 987 hwmgr->thermal_controller.advanceFanControlParameters.usTMed 988 = le16_to_cpu(fiji_fan_table->usTMed); 989 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh 990 = le16_to_cpu(fiji_fan_table->usTHigh); 991 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin 992 = le16_to_cpu(fiji_fan_table->usPWMMin); 993 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed 994 = le16_to_cpu(fiji_fan_table->usPWMMed); 995 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh 996 = le16_to_cpu(fiji_fan_table->usPWMHigh); 997 hwmgr->thermal_controller.advanceFanControlParameters.usTMax 998 = le16_to_cpu(fiji_fan_table->usTMax); 999 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode 1000 = fiji_fan_table->ucFanControlMode; 1001 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM 1002 = le16_to_cpu(fiji_fan_table->usFanPWMMax); 1003 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity 1004 = 4836; 1005 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity 1006 = le16_to_cpu(fiji_fan_table->usFanOutputSensitivity); 1007 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM 1008 = le16_to_cpu(fiji_fan_table->usFanRPMMax); 1009 hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit 1010 = (le32_to_cpu(fiji_fan_table->ulMinFanSCLKAcousticLimit) / 100); /* PPTable stores it in 10Khz unit for 2 decimal places. SMC wants MHz. */ 1011 hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature 1012 = fiji_fan_table->ucTargetTemperature; 1013 hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit 1014 = fiji_fan_table->ucMinimumPWMLimit; 1015 1016 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainEdge 1017 = le16_to_cpu(fiji_fan_table->usFanGainEdge); 1018 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHotspot 1019 = le16_to_cpu(fiji_fan_table->usFanGainHotspot); 1020 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainLiquid 1021 = le16_to_cpu(fiji_fan_table->usFanGainLiquid); 1022 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrVddc 1023 = le16_to_cpu(fiji_fan_table->usFanGainVrVddc); 1024 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainVrMvdd 1025 = le16_to_cpu(fiji_fan_table->usFanGainVrMvdd); 1026 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainPlx 1027 = le16_to_cpu(fiji_fan_table->usFanGainPlx); 1028 hwmgr->thermal_controller.advanceFanControlParameters.usFanGainHbm 1029 = le16_to_cpu(fiji_fan_table->usFanGainHbm); 1030 } 1031 1032 return 0; 1033 } 1034 1035 /** 1036 * Private Function used during initialization. 1037 * Inspect the PowerPlay table for obvious signs of corruption. 1038 * @param hwmgr Pointer to the hardware manager. 1039 * @param powerplay_table Pointer to the PowerPlay Table. 1040 * @exception 2 if the powerplay table is incorrect. 1041 */ 1042 static int check_powerplay_tables( 1043 struct pp_hwmgr *hwmgr, 1044 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table 1045 ) 1046 { 1047 const ATOM_Tonga_State_Array *state_arrays; 1048 1049 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)powerplay_table) + 1050 le16_to_cpu(powerplay_table->usStateArrayOffset)); 1051 1052 PP_ASSERT_WITH_CODE((ATOM_Tonga_TABLE_REVISION_TONGA <= 1053 powerplay_table->sHeader.ucTableFormatRevision), 1054 "Unsupported PPTable format!", return -1); 1055 PP_ASSERT_WITH_CODE((0 != powerplay_table->usStateArrayOffset), 1056 "State table is not set!", return -1); 1057 PP_ASSERT_WITH_CODE((0 < powerplay_table->sHeader.usStructureSize), 1058 "Invalid PowerPlay Table!", return -1); 1059 PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), 1060 "Invalid PowerPlay Table!", return -1); 1061 1062 return 0; 1063 } 1064 1065 static int pp_tables_v1_0_initialize(struct pp_hwmgr *hwmgr) 1066 { 1067 int result = 0; 1068 const ATOM_Tonga_POWERPLAYTABLE *powerplay_table; 1069 1070 hwmgr->pptable = kzalloc(sizeof(struct phm_ppt_v1_information), GFP_KERNEL); 1071 1072 PP_ASSERT_WITH_CODE((NULL != hwmgr->pptable), 1073 "Failed to allocate hwmgr->pptable!", return -ENOMEM); 1074 1075 powerplay_table = get_powerplay_table(hwmgr); 1076 1077 PP_ASSERT_WITH_CODE((NULL != powerplay_table), 1078 "Missing PowerPlay Table!", return -1); 1079 1080 result = check_powerplay_tables(hwmgr, powerplay_table); 1081 1082 PP_ASSERT_WITH_CODE((result == 0), 1083 "check_powerplay_tables failed", return result); 1084 1085 result = set_platform_caps(hwmgr, 1086 le32_to_cpu(powerplay_table->ulPlatformCaps)); 1087 1088 PP_ASSERT_WITH_CODE((result == 0), 1089 "set_platform_caps failed", return result); 1090 1091 result = init_thermal_controller(hwmgr, powerplay_table); 1092 1093 PP_ASSERT_WITH_CODE((result == 0), 1094 "init_thermal_controller failed", return result); 1095 1096 result = init_over_drive_limits(hwmgr, powerplay_table); 1097 1098 PP_ASSERT_WITH_CODE((result == 0), 1099 "init_over_drive_limits failed", return result); 1100 1101 result = init_clock_voltage_dependency(hwmgr, powerplay_table); 1102 1103 PP_ASSERT_WITH_CODE((result == 0), 1104 "init_clock_voltage_dependency failed", return result); 1105 1106 result = init_dpm_2_parameters(hwmgr, powerplay_table); 1107 1108 PP_ASSERT_WITH_CODE((result == 0), 1109 "init_dpm_2_parameters failed", return result); 1110 1111 return result; 1112 } 1113 1114 static int pp_tables_v1_0_uninitialize(struct pp_hwmgr *hwmgr) 1115 { 1116 struct phm_ppt_v1_information *pp_table_information = 1117 (struct phm_ppt_v1_information *)(hwmgr->pptable); 1118 1119 kfree(pp_table_information->vdd_dep_on_sclk); 1120 pp_table_information->vdd_dep_on_sclk = NULL; 1121 1122 kfree(pp_table_information->vdd_dep_on_mclk); 1123 pp_table_information->vdd_dep_on_mclk = NULL; 1124 1125 kfree(pp_table_information->valid_mclk_values); 1126 pp_table_information->valid_mclk_values = NULL; 1127 1128 kfree(pp_table_information->valid_sclk_values); 1129 pp_table_information->valid_sclk_values = NULL; 1130 1131 kfree(pp_table_information->vddc_lookup_table); 1132 pp_table_information->vddc_lookup_table = NULL; 1133 1134 kfree(pp_table_information->vddgfx_lookup_table); 1135 pp_table_information->vddgfx_lookup_table = NULL; 1136 1137 kfree(pp_table_information->mm_dep_table); 1138 pp_table_information->mm_dep_table = NULL; 1139 1140 kfree(pp_table_information->cac_dtp_table); 1141 pp_table_information->cac_dtp_table = NULL; 1142 1143 kfree(hwmgr->dyn_state.cac_dtp_table); 1144 hwmgr->dyn_state.cac_dtp_table = NULL; 1145 1146 kfree(pp_table_information->ppm_parameter_table); 1147 pp_table_information->ppm_parameter_table = NULL; 1148 1149 kfree(pp_table_information->pcie_table); 1150 pp_table_information->pcie_table = NULL; 1151 1152 kfree(pp_table_information->gpio_table); 1153 pp_table_information->gpio_table = NULL; 1154 1155 kfree(hwmgr->pptable); 1156 hwmgr->pptable = NULL; 1157 1158 return 0; 1159 } 1160 1161 const struct pp_table_func pptable_v1_0_funcs = { 1162 .pptable_init = pp_tables_v1_0_initialize, 1163 .pptable_fini = pp_tables_v1_0_uninitialize, 1164 }; 1165 1166 int get_number_of_powerplay_table_entries_v1_0(struct pp_hwmgr *hwmgr) 1167 { 1168 ATOM_Tonga_State_Array const *state_arrays; 1169 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); 1170 1171 PP_ASSERT_WITH_CODE((NULL != pp_table), 1172 "Missing PowerPlay Table!", return -1); 1173 PP_ASSERT_WITH_CODE((pp_table->sHeader.ucTableFormatRevision >= 1174 ATOM_Tonga_TABLE_REVISION_TONGA), 1175 "Incorrect PowerPlay table revision!", return -1); 1176 1177 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + 1178 le16_to_cpu(pp_table->usStateArrayOffset)); 1179 1180 return (uint32_t)(state_arrays->ucNumEntries); 1181 } 1182 1183 /** 1184 * Private function to convert flags stored in the BIOS to software flags in PowerPlay. 1185 */ 1186 static uint32_t make_classification_flags(struct pp_hwmgr *hwmgr, 1187 uint16_t classification, uint16_t classification2) 1188 { 1189 uint32_t result = 0; 1190 1191 if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) 1192 result |= PP_StateClassificationFlag_Boot; 1193 1194 if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) 1195 result |= PP_StateClassificationFlag_Thermal; 1196 1197 if (classification & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) 1198 result |= PP_StateClassificationFlag_LimitedPowerSource; 1199 1200 if (classification & ATOM_PPLIB_CLASSIFICATION_REST) 1201 result |= PP_StateClassificationFlag_Rest; 1202 1203 if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) 1204 result |= PP_StateClassificationFlag_Forced; 1205 1206 if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) 1207 result |= PP_StateClassificationFlag_ACPI; 1208 1209 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) 1210 result |= PP_StateClassificationFlag_LimitedPowerSource_2; 1211 1212 return result; 1213 } 1214 1215 static int ppt_get_num_of_vce_state_table_entries_v1_0(struct pp_hwmgr *hwmgr) 1216 { 1217 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); 1218 const ATOM_Tonga_VCE_State_Table *vce_state_table; 1219 1220 1221 if (pp_table == NULL) 1222 return 0; 1223 1224 vce_state_table = (const void *)pp_table + 1225 le16_to_cpu(pp_table->usVCEStateTableOffset); 1226 1227 return vce_state_table->ucNumEntries; 1228 } 1229 1230 static int ppt_get_vce_state_table_entry_v1_0(struct pp_hwmgr *hwmgr, uint32_t i, 1231 struct amd_vce_state *vce_state, void **clock_info, uint32_t *flag) 1232 { 1233 const ATOM_Tonga_VCE_State_Record *vce_state_record; 1234 ATOM_Tonga_SCLK_Dependency_Record *sclk_dep_record; 1235 ATOM_Tonga_MCLK_Dependency_Record *mclk_dep_record; 1236 ATOM_Tonga_MM_Dependency_Record *mm_dep_record; 1237 const ATOM_Tonga_POWERPLAYTABLE *pptable = get_powerplay_table(hwmgr); 1238 const ATOM_Tonga_VCE_State_Table *vce_state_table = (ATOM_Tonga_VCE_State_Table *)(((unsigned long)pptable) 1239 + le16_to_cpu(pptable->usVCEStateTableOffset)); 1240 const ATOM_Tonga_SCLK_Dependency_Table *sclk_dep_table = (ATOM_Tonga_SCLK_Dependency_Table *)(((unsigned long)pptable) 1241 + le16_to_cpu(pptable->usSclkDependencyTableOffset)); 1242 const ATOM_Tonga_MCLK_Dependency_Table *mclk_dep_table = (ATOM_Tonga_MCLK_Dependency_Table *)(((unsigned long)pptable) 1243 + le16_to_cpu(pptable->usMclkDependencyTableOffset)); 1244 const ATOM_Tonga_MM_Dependency_Table *mm_dep_table = (ATOM_Tonga_MM_Dependency_Table *)(((unsigned long)pptable) 1245 + le16_to_cpu(pptable->usMMDependencyTableOffset)); 1246 1247 PP_ASSERT_WITH_CODE((i < vce_state_table->ucNumEntries), 1248 "Requested state entry ID is out of range!", 1249 return -EINVAL); 1250 1251 vce_state_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1252 ATOM_Tonga_VCE_State_Record, 1253 entries, vce_state_table, i); 1254 sclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1255 ATOM_Tonga_SCLK_Dependency_Record, 1256 entries, sclk_dep_table, 1257 vce_state_record->ucSCLKIndex); 1258 mm_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1259 ATOM_Tonga_MM_Dependency_Record, 1260 entries, mm_dep_table, 1261 vce_state_record->ucVCEClockIndex); 1262 *flag = vce_state_record->ucFlag; 1263 1264 vce_state->evclk = le32_to_cpu(mm_dep_record->ulEClk); 1265 vce_state->ecclk = le32_to_cpu(mm_dep_record->ulEClk); 1266 vce_state->sclk = le32_to_cpu(sclk_dep_record->ulSclk); 1267 1268 if (vce_state_record->ucMCLKIndex >= mclk_dep_table->ucNumEntries) 1269 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1270 ATOM_Tonga_MCLK_Dependency_Record, 1271 entries, mclk_dep_table, 1272 mclk_dep_table->ucNumEntries - 1); 1273 else 1274 mclk_dep_record = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1275 ATOM_Tonga_MCLK_Dependency_Record, 1276 entries, mclk_dep_table, 1277 vce_state_record->ucMCLKIndex); 1278 1279 vce_state->mclk = le32_to_cpu(mclk_dep_record->ulMclk); 1280 return 0; 1281 } 1282 1283 /** 1284 * Create a Power State out of an entry in the PowerPlay table. 1285 * This function is called by the hardware back-end. 1286 * @param hwmgr Pointer to the hardware manager. 1287 * @param entry_index The index of the entry to be extracted from the table. 1288 * @param power_state The address of the PowerState instance being created. 1289 * @return -1 if the entry cannot be retrieved. 1290 */ 1291 int get_powerplay_table_entry_v1_0(struct pp_hwmgr *hwmgr, 1292 uint32_t entry_index, struct pp_power_state *power_state, 1293 int (*call_back_func)(struct pp_hwmgr *, void *, 1294 struct pp_power_state *, void *, uint32_t)) 1295 { 1296 int result = 0; 1297 const ATOM_Tonga_State_Array *state_arrays; 1298 const ATOM_Tonga_State *state_entry; 1299 const ATOM_Tonga_POWERPLAYTABLE *pp_table = get_powerplay_table(hwmgr); 1300 int i, j; 1301 uint32_t flags = 0; 1302 1303 PP_ASSERT_WITH_CODE((NULL != pp_table), "Missing PowerPlay Table!", return -1;); 1304 power_state->classification.bios_index = entry_index; 1305 1306 if (pp_table->sHeader.ucTableFormatRevision >= 1307 ATOM_Tonga_TABLE_REVISION_TONGA) { 1308 state_arrays = (ATOM_Tonga_State_Array *)(((unsigned long)pp_table) + 1309 le16_to_cpu(pp_table->usStateArrayOffset)); 1310 1311 PP_ASSERT_WITH_CODE((0 < pp_table->usStateArrayOffset), 1312 "Invalid PowerPlay Table State Array Offset.", return -1); 1313 PP_ASSERT_WITH_CODE((0 < state_arrays->ucNumEntries), 1314 "Invalid PowerPlay Table State Array.", return -1); 1315 PP_ASSERT_WITH_CODE((entry_index <= state_arrays->ucNumEntries), 1316 "Invalid PowerPlay Table State Array Entry.", return -1); 1317 1318 state_entry = GET_FLEXIBLE_ARRAY_MEMBER_ADDR( 1319 ATOM_Tonga_State, entries, 1320 state_arrays, entry_index); 1321 1322 result = call_back_func(hwmgr, __UNCONST(state_entry), power_state, 1323 __UNCONST(pp_table), 1324 make_classification_flags(hwmgr, 1325 le16_to_cpu(state_entry->usClassification), 1326 le16_to_cpu(state_entry->usClassification2))); 1327 } 1328 1329 if (!result && (power_state->classification.flags & 1330 PP_StateClassificationFlag_Boot)) 1331 result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(power_state->hardware)); 1332 1333 hwmgr->num_vce_state_tables = i = ppt_get_num_of_vce_state_table_entries_v1_0(hwmgr); 1334 1335 if ((i != 0) && (i <= AMD_MAX_VCE_LEVELS)) { 1336 for (j = 0; j < i; j++) 1337 ppt_get_vce_state_table_entry_v1_0(hwmgr, j, &(hwmgr->vce_states[j]), NULL, &flags); 1338 } 1339 1340 return result; 1341 } 1342 1343