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/types.h> 25 #include <linux/kernel.h> 26 #include <linux/slab.h> 27 #include <linux/pci.h> 28 29 #include <drm/amdgpu_drm.h> 30 #include "processpptables.h" 31 #include <atom-types.h> 32 #include <atombios.h> 33 #include "pptable.h" 34 #include "power_state.h" 35 #include "hwmgr.h" 36 #include "hardwaremanager.h" 37 38 39 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12 40 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14 41 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16 42 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18 43 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20 44 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22 45 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24 46 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26 47 48 #define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6 49 50 static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr, 51 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 52 { 53 uint16_t vce_table_offset = 0; 54 55 if (le16_to_cpu(powerplay_table->usTableSize) >= 56 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 57 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 58 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 59 60 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 61 const ATOM_PPLIB_EXTENDEDHEADER *extended_header = 62 (const ATOM_PPLIB_EXTENDEDHEADER *) 63 (((unsigned long)powerplay_table3) + 64 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 65 if (le16_to_cpu(extended_header->usSize) >= 66 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) 67 vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset); 68 } 69 } 70 71 return vce_table_offset; 72 } 73 74 static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr, 75 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 76 { 77 uint16_t table_offset = get_vce_table_offset(hwmgr, 78 powerplay_table); 79 80 if (table_offset > 0) 81 return table_offset + 1; 82 83 return 0; 84 } 85 86 static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr, 87 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 88 { 89 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr, 90 powerplay_table); 91 uint16_t table_size = 0; 92 93 if (table_offset > 0) { 94 const VCEClockInfoArray *p = (const VCEClockInfoArray *) 95 (((unsigned long) powerplay_table) + table_offset); 96 table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo); 97 } 98 99 return table_size; 100 } 101 102 static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr, 103 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 104 { 105 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr, 106 powerplay_table); 107 108 if (table_offset > 0) 109 return table_offset + get_vce_clock_info_array_size(hwmgr, 110 powerplay_table); 111 112 return 0; 113 } 114 115 static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr, 116 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 117 { 118 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table); 119 uint16_t table_size = 0; 120 121 if (table_offset > 0) { 122 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable = 123 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset); 124 125 table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record); 126 } 127 return table_size; 128 } 129 130 static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 131 { 132 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table); 133 134 if (table_offset > 0) 135 return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table); 136 137 return 0; 138 } 139 140 static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table( 141 struct pp_hwmgr *hwmgr, 142 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 143 { 144 uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table); 145 146 if (table_offset > 0) 147 return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset); 148 149 return NULL; 150 } 151 152 static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr, 153 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 154 { 155 uint16_t uvd_table_offset = 0; 156 157 if (le16_to_cpu(powerplay_table->usTableSize) >= 158 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 159 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 160 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 161 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 162 const ATOM_PPLIB_EXTENDEDHEADER *extended_header = 163 (const ATOM_PPLIB_EXTENDEDHEADER *) 164 (((unsigned long)powerplay_table3) + 165 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 166 if (le16_to_cpu(extended_header->usSize) >= 167 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) 168 uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset); 169 } 170 } 171 return uvd_table_offset; 172 } 173 174 static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr, 175 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 176 { 177 uint16_t table_offset = get_uvd_table_offset(hwmgr, 178 powerplay_table); 179 180 if (table_offset > 0) 181 return table_offset + 1; 182 return 0; 183 } 184 185 static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr, 186 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 187 { 188 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr, 189 powerplay_table); 190 uint16_t table_size = 0; 191 192 if (table_offset > 0) { 193 const UVDClockInfoArray *p = (const UVDClockInfoArray *) 194 (((unsigned long) powerplay_table) 195 + table_offset); 196 table_size = sizeof(UCHAR) + 197 p->ucNumEntries * sizeof(UVDClockInfo); 198 } 199 200 return table_size; 201 } 202 203 static uint16_t get_uvd_clock_voltage_limit_table_offset( 204 struct pp_hwmgr *hwmgr, 205 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 206 { 207 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr, 208 powerplay_table); 209 210 if (table_offset > 0) 211 return table_offset + 212 get_uvd_clock_info_array_size(hwmgr, powerplay_table); 213 214 return 0; 215 } 216 217 static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr, 218 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 219 { 220 uint16_t samu_table_offset = 0; 221 222 if (le16_to_cpu(powerplay_table->usTableSize) >= 223 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 224 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 225 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 226 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 227 const ATOM_PPLIB_EXTENDEDHEADER *extended_header = 228 (const ATOM_PPLIB_EXTENDEDHEADER *) 229 (((unsigned long)powerplay_table3) + 230 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 231 if (le16_to_cpu(extended_header->usSize) >= 232 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) 233 samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset); 234 } 235 } 236 237 return samu_table_offset; 238 } 239 240 static uint16_t get_samu_clock_voltage_limit_table_offset( 241 struct pp_hwmgr *hwmgr, 242 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 243 { 244 uint16_t table_offset = get_samu_table_offset(hwmgr, 245 powerplay_table); 246 247 if (table_offset > 0) 248 return table_offset + 1; 249 250 return 0; 251 } 252 253 static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr, 254 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 255 { 256 uint16_t acp_table_offset = 0; 257 258 if (le16_to_cpu(powerplay_table->usTableSize) >= 259 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 260 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 261 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 262 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 263 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = 264 (const ATOM_PPLIB_EXTENDEDHEADER *) 265 (((unsigned long)powerplay_table3) + 266 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 267 if (le16_to_cpu(pExtendedHeader->usSize) >= 268 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) 269 acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset); 270 } 271 } 272 273 return acp_table_offset; 274 } 275 276 static uint16_t get_acp_clock_voltage_limit_table_offset( 277 struct pp_hwmgr *hwmgr, 278 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 279 { 280 uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table); 281 282 if (tableOffset > 0) 283 return tableOffset + 1; 284 285 return 0; 286 } 287 288 static uint16_t get_cacp_tdp_table_offset( 289 struct pp_hwmgr *hwmgr, 290 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 291 { 292 uint16_t cacTdpTableOffset = 0; 293 294 if (le16_to_cpu(powerplay_table->usTableSize) >= 295 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 296 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 297 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 298 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 299 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = 300 (const ATOM_PPLIB_EXTENDEDHEADER *) 301 (((unsigned long)powerplay_table3) + 302 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 303 if (le16_to_cpu(pExtendedHeader->usSize) >= 304 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) 305 cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset); 306 } 307 } 308 309 return cacTdpTableOffset; 310 } 311 312 static int get_cac_tdp_table(struct pp_hwmgr *hwmgr, 313 struct phm_cac_tdp_table **ptable, 314 const ATOM_PowerTune_Table *table, 315 uint16_t us_maximum_power_delivery_limit) 316 { 317 unsigned long table_size; 318 struct phm_cac_tdp_table *tdp_table; 319 320 table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table); 321 322 tdp_table = kzalloc(table_size, GFP_KERNEL); 323 if (NULL == tdp_table) 324 return -ENOMEM; 325 326 tdp_table->usTDP = le16_to_cpu(table->usTDP); 327 tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP); 328 tdp_table->usTDC = le16_to_cpu(table->usTDC); 329 tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit); 330 tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit); 331 tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage); 332 tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage); 333 tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit; 334 335 *ptable = tdp_table; 336 337 return 0; 338 } 339 340 static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr, 341 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 342 { 343 uint16_t sclk_vdd_gfx_table_offset = 0; 344 345 if (le16_to_cpu(powerplay_table->usTableSize) >= 346 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 347 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 348 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 349 if (powerplay_table3->usExtendendedHeaderOffset > 0) { 350 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader = 351 (const ATOM_PPLIB_EXTENDEDHEADER *) 352 (((unsigned long)powerplay_table3) + 353 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 354 if (le16_to_cpu(pExtendedHeader->usSize) >= 355 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) 356 sclk_vdd_gfx_table_offset = 357 le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset); 358 } 359 } 360 361 return sclk_vdd_gfx_table_offset; 362 } 363 364 static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset( 365 struct pp_hwmgr *hwmgr, 366 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 367 { 368 uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table); 369 370 if (tableOffset > 0) 371 return tableOffset; 372 373 return 0; 374 } 375 376 377 static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr, 378 struct phm_clock_voltage_dependency_table **ptable, 379 const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table) 380 { 381 382 unsigned long i; 383 struct phm_clock_voltage_dependency_table *dep_table; 384 385 dep_table = kzalloc(struct_size(dep_table, entries, table->ucNumEntries), 386 GFP_KERNEL); 387 if (NULL == dep_table) 388 return -ENOMEM; 389 390 dep_table->count = (unsigned long)table->ucNumEntries; 391 392 for (i = 0; i < dep_table->count; i++) { 393 dep_table->entries[i].clk = 394 ((unsigned long)table->entries[i].ucClockHigh << 16) | 395 le16_to_cpu(table->entries[i].usClockLow); 396 dep_table->entries[i].v = 397 (unsigned long)le16_to_cpu(table->entries[i].usVoltage); 398 } 399 400 *ptable = dep_table; 401 402 return 0; 403 } 404 405 static int get_valid_clk(struct pp_hwmgr *hwmgr, 406 struct phm_clock_array **ptable, 407 const struct phm_clock_voltage_dependency_table *table) 408 { 409 unsigned long i; 410 struct phm_clock_array *clock_table; 411 412 clock_table = kzalloc(struct_size(clock_table, values, table->count), GFP_KERNEL); 413 if (!clock_table) 414 return -ENOMEM; 415 416 clock_table->count = (unsigned long)table->count; 417 418 for (i = 0; i < clock_table->count; i++) 419 clock_table->values[i] = (unsigned long)table->entries[i].clk; 420 421 *ptable = clock_table; 422 423 return 0; 424 } 425 426 static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr, 427 struct phm_clock_and_voltage_limits *limits, 428 const ATOM_PPLIB_Clock_Voltage_Limit_Table *table) 429 { 430 limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) | 431 le16_to_cpu(table->entries[0].usSclkLow); 432 limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) | 433 le16_to_cpu(table->entries[0].usMclkLow); 434 limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc); 435 limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci); 436 437 return 0; 438 } 439 440 441 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable, 442 enum phm_platform_caps cap) 443 { 444 if (enable) 445 phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap); 446 else 447 phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap); 448 } 449 450 static int set_platform_caps(struct pp_hwmgr *hwmgr, 451 unsigned long powerplay_caps) 452 { 453 set_hw_cap( 454 hwmgr, 455 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY), 456 PHM_PlatformCaps_PowerPlaySupport 457 ); 458 459 set_hw_cap( 460 hwmgr, 461 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE), 462 PHM_PlatformCaps_BiosPowerSourceControl 463 ); 464 465 set_hw_cap( 466 hwmgr, 467 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s), 468 PHM_PlatformCaps_EnableASPML0s 469 ); 470 471 set_hw_cap( 472 hwmgr, 473 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1), 474 PHM_PlatformCaps_EnableASPML1 475 ); 476 477 set_hw_cap( 478 hwmgr, 479 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS), 480 PHM_PlatformCaps_EnableBackbias 481 ); 482 483 set_hw_cap( 484 hwmgr, 485 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC), 486 PHM_PlatformCaps_AutomaticDCTransition 487 ); 488 489 set_hw_cap( 490 hwmgr, 491 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY), 492 PHM_PlatformCaps_GeminiPrimary 493 ); 494 495 set_hw_cap( 496 hwmgr, 497 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC), 498 PHM_PlatformCaps_StepVddc 499 ); 500 501 set_hw_cap( 502 hwmgr, 503 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL), 504 PHM_PlatformCaps_EnableVoltageControl 505 ); 506 507 set_hw_cap( 508 hwmgr, 509 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL), 510 PHM_PlatformCaps_EnableSideportControl 511 ); 512 513 set_hw_cap( 514 hwmgr, 515 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1), 516 PHM_PlatformCaps_TurnOffPll_ASPML1 517 ); 518 519 set_hw_cap( 520 hwmgr, 521 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL), 522 PHM_PlatformCaps_EnableHTLinkControl 523 ); 524 525 set_hw_cap( 526 hwmgr, 527 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL), 528 PHM_PlatformCaps_EnableMVDDControl 529 ); 530 531 set_hw_cap( 532 hwmgr, 533 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL), 534 PHM_PlatformCaps_ControlVDDCI 535 ); 536 537 set_hw_cap( 538 hwmgr, 539 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT), 540 PHM_PlatformCaps_RegulatorHot 541 ); 542 543 set_hw_cap( 544 hwmgr, 545 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT), 546 PHM_PlatformCaps_BootStateOnAlert 547 ); 548 549 set_hw_cap( 550 hwmgr, 551 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT), 552 PHM_PlatformCaps_DontWaitForVBlankOnAlert 553 ); 554 555 set_hw_cap( 556 hwmgr, 557 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO), 558 PHM_PlatformCaps_BACO 559 ); 560 561 set_hw_cap( 562 hwmgr, 563 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE), 564 PHM_PlatformCaps_NewCACVoltage 565 ); 566 567 set_hw_cap( 568 hwmgr, 569 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY), 570 PHM_PlatformCaps_RevertGPIO5Polarity 571 ); 572 573 set_hw_cap( 574 hwmgr, 575 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17), 576 PHM_PlatformCaps_Thermal2GPIO17 577 ); 578 579 set_hw_cap( 580 hwmgr, 581 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE), 582 PHM_PlatformCaps_VRHotGPIOConfigurable 583 ); 584 585 set_hw_cap( 586 hwmgr, 587 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION), 588 PHM_PlatformCaps_TempInversion 589 ); 590 591 set_hw_cap( 592 hwmgr, 593 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV), 594 PHM_PlatformCaps_EVV 595 ); 596 597 set_hw_cap( 598 hwmgr, 599 0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL), 600 PHM_PlatformCaps_CombinePCCWithThermalSignal 601 ); 602 603 set_hw_cap( 604 hwmgr, 605 0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE), 606 PHM_PlatformCaps_LoadPostProductionFirmware 607 ); 608 609 set_hw_cap( 610 hwmgr, 611 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC), 612 PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc 613 ); 614 615 return 0; 616 } 617 618 static PP_StateClassificationFlags make_classification_flags( 619 struct pp_hwmgr *hwmgr, 620 USHORT classification, 621 USHORT classification2) 622 { 623 PP_StateClassificationFlags result = 0; 624 625 if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT) 626 result |= PP_StateClassificationFlag_Boot; 627 628 if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL) 629 result |= PP_StateClassificationFlag_Thermal; 630 631 if (classification & 632 ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) 633 result |= PP_StateClassificationFlag_LimitedPowerSource; 634 635 if (classification & ATOM_PPLIB_CLASSIFICATION_REST) 636 result |= PP_StateClassificationFlag_Rest; 637 638 if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED) 639 result |= PP_StateClassificationFlag_Forced; 640 641 if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) 642 result |= PP_StateClassificationFlag_3DPerformance; 643 644 645 if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) 646 result |= PP_StateClassificationFlag_ACOverdriveTemplate; 647 648 if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) 649 result |= PP_StateClassificationFlag_Uvd; 650 651 if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE) 652 result |= PP_StateClassificationFlag_UvdHD; 653 654 if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE) 655 result |= PP_StateClassificationFlag_UvdSD; 656 657 if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE) 658 result |= PP_StateClassificationFlag_HD2; 659 660 if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI) 661 result |= PP_StateClassificationFlag_ACPI; 662 663 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) 664 result |= PP_StateClassificationFlag_LimitedPowerSource_2; 665 666 667 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV) 668 result |= PP_StateClassificationFlag_ULV; 669 670 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC) 671 result |= PP_StateClassificationFlag_UvdMVC; 672 673 return result; 674 } 675 676 static int init_non_clock_fields(struct pp_hwmgr *hwmgr, 677 struct pp_power_state *ps, 678 uint8_t version, 679 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) { 680 unsigned long rrr_index; 681 unsigned long tmp; 682 683 ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) & 684 ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT; 685 ps->classification.flags = make_classification_flags(hwmgr, 686 le16_to_cpu(pnon_clock_info->usClassification), 687 le16_to_cpu(pnon_clock_info->usClassification2)); 688 689 ps->classification.temporary_state = false; 690 ps->classification.to_be_deleted = false; 691 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 692 ATOM_PPLIB_SINGLE_DISPLAY_ONLY; 693 694 ps->validation.singleDisplayOnly = (0 != tmp); 695 696 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 697 ATOM_PPLIB_DISALLOW_ON_DC; 698 699 ps->validation.disallowOnDC = (0 != tmp); 700 701 ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 702 ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >> 703 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1; 704 705 ps->pcie.lanes = 0; 706 707 ps->display.disableFrameModulation = false; 708 709 rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 710 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >> 711 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT; 712 713 if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) { 714 static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \ 715 { 0, 50, 0 }; 716 717 ps->display.refreshrateSource = PP_RefreshrateSource_Explicit; 718 ps->display.explicitRefreshrate = look_up[rrr_index]; 719 ps->display.limitRefreshrate = true; 720 721 if (ps->display.explicitRefreshrate == 0) 722 ps->display.limitRefreshrate = false; 723 } else 724 ps->display.limitRefreshrate = false; 725 726 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 727 ATOM_PPLIB_ENABLE_VARIBRIGHT; 728 729 ps->display.enableVariBright = (0 != tmp); 730 731 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 732 ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF; 733 734 ps->memory.dllOff = (0 != tmp); 735 736 ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 737 ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT; 738 739 ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES * 740 pnon_clock_info->ucMinTemperature; 741 742 ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES * 743 pnon_clock_info->ucMaxTemperature; 744 745 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 746 ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING; 747 748 ps->software.disableLoadBalancing = tmp; 749 750 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) & 751 ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS; 752 753 ps->software.enableSleepForTimestamps = (0 != tmp); 754 755 ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower; 756 757 if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) { 758 ps->uvd_clocks.VCLK = le32_to_cpu(pnon_clock_info->ulVCLK); 759 ps->uvd_clocks.DCLK = le32_to_cpu(pnon_clock_info->ulDCLK); 760 } else { 761 ps->uvd_clocks.VCLK = 0; 762 ps->uvd_clocks.DCLK = 0; 763 } 764 765 return 0; 766 } 767 768 static ULONG size_of_entry_v2(ULONG num_dpm_levels) 769 { 770 return (sizeof(UCHAR) + sizeof(UCHAR) + 771 (num_dpm_levels * sizeof(UCHAR))); 772 } 773 774 static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2( 775 const StateArray * pstate_arrays, 776 ULONG entry_index) 777 { 778 ULONG i; 779 const ATOM_PPLIB_STATE_V2 *pstate; 780 781 pstate = pstate_arrays->states; 782 if (entry_index <= pstate_arrays->ucNumEntries) { 783 for (i = 0; i < entry_index; i++) 784 pstate = (ATOM_PPLIB_STATE_V2 *)( 785 (unsigned long)pstate + 786 size_of_entry_v2(pstate->ucNumDPMLevels)); 787 } 788 return pstate; 789 } 790 791 static const unsigned char soft_dummy_pp_table[] = { 792 0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00, 793 0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 794 0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, 795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 796 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 797 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 798 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00, 799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00, 803 0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c, 804 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00, 805 0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a, 806 0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59, 807 0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28, 808 0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01, 809 0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 810 0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 811 0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03, 812 0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c, 813 0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01, 814 0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e, 815 0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70, 816 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08, 817 0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70, 818 0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00, 819 0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c, 820 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00, 821 0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a, 822 0x00 823 }; 824 825 static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table( 826 struct pp_hwmgr *hwmgr) 827 { 828 const void *table_addr = hwmgr->soft_pp_table; 829 uint8_t frev, crev; 830 uint16_t size; 831 832 if (!table_addr) { 833 if (hwmgr->chip_id == CHIP_RAVEN) { 834 table_addr = &soft_dummy_pp_table[0]; 835 hwmgr->soft_pp_table = &soft_dummy_pp_table[0]; 836 hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table); 837 } else { 838 table_addr = smu_atom_get_data_table(hwmgr->adev, 839 GetIndexIntoMasterTable(DATA, PowerPlayInfo), 840 &size, &frev, &crev); 841 hwmgr->soft_pp_table = table_addr; 842 hwmgr->soft_pp_table_size = size; 843 } 844 } 845 846 return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr; 847 } 848 849 int pp_tables_get_response_times(struct pp_hwmgr *hwmgr, 850 uint32_t *vol_rep_time, uint32_t *bb_rep_time) 851 { 852 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr); 853 854 PP_ASSERT_WITH_CODE(NULL != powerplay_tab, 855 "Missing PowerPlay Table!", return -EINVAL); 856 857 *vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime); 858 *bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime); 859 860 return 0; 861 } 862 863 int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr, 864 unsigned long *num_of_entries) 865 { 866 const StateArray *pstate_arrays; 867 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr); 868 869 if (powerplay_table == NULL) 870 return -1; 871 872 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) { 873 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) + 874 le16_to_cpu(powerplay_table->usStateArrayOffset)); 875 876 *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries); 877 } else 878 *num_of_entries = (unsigned long)(powerplay_table->ucNumStates); 879 880 return 0; 881 } 882 883 int pp_tables_get_entry(struct pp_hwmgr *hwmgr, 884 unsigned long entry_index, 885 struct pp_power_state *ps, 886 pp_tables_hw_clock_info_callback func) 887 { 888 int i; 889 const StateArray *pstate_arrays; 890 const ATOM_PPLIB_STATE_V2 *pstate_entry_v2; 891 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info; 892 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr); 893 int result = 0; 894 int res = 0; 895 896 const ClockInfoArray *pclock_arrays; 897 898 const NonClockInfoArray *pnon_clock_arrays; 899 900 const ATOM_PPLIB_STATE *pstate_entry; 901 902 if (powerplay_table == NULL) 903 return -1; 904 905 ps->classification.bios_index = entry_index; 906 907 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) { 908 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) + 909 le16_to_cpu(powerplay_table->usStateArrayOffset)); 910 911 if (entry_index > pstate_arrays->ucNumEntries) 912 return -1; 913 914 pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index); 915 pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + 916 le16_to_cpu(powerplay_table->usClockInfoArrayOffset)); 917 918 pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) + 919 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset)); 920 921 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) + 922 (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize)); 923 924 result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info); 925 926 for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) { 927 const void *pclock_info = (const void *)( 928 (unsigned long)(pclock_arrays->clockInfo) + 929 (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize)); 930 res = func(hwmgr, &ps->hardware, i, pclock_info); 931 if ((0 == result) && (0 != res)) 932 result = res; 933 } 934 } else { 935 if (entry_index > powerplay_table->ucNumStates) 936 return -1; 937 938 pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table + 939 le16_to_cpu(powerplay_table->usStateArrayOffset) + 940 entry_index * powerplay_table->ucStateEntrySize); 941 942 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table + 943 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) + 944 pstate_entry->ucNonClockStateIndex * 945 powerplay_table->ucNonClockSize); 946 947 result = init_non_clock_fields(hwmgr, ps, 948 powerplay_table->ucNonClockSize, 949 pnon_clock_info); 950 951 for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) { 952 const void *pclock_info = (const void *)((unsigned long)powerplay_table + 953 le16_to_cpu(powerplay_table->usClockInfoArrayOffset) + 954 pstate_entry->ucClockStateIndices[i] * 955 powerplay_table->ucClockInfoSize); 956 957 int res = func(hwmgr, &ps->hardware, i, pclock_info); 958 959 if ((0 == result) && (0 != res)) 960 result = res; 961 } 962 } 963 964 if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) { 965 if (hwmgr->chip_family < AMDGPU_FAMILY_RV) 966 result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware)); 967 } 968 969 return result; 970 } 971 972 static int init_powerplay_tables( 973 struct pp_hwmgr *hwmgr, 974 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table 975 ) 976 { 977 return 0; 978 } 979 980 981 static int init_thermal_controller( 982 struct pp_hwmgr *hwmgr, 983 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 984 { 985 struct amdgpu_device *adev = hwmgr->adev; 986 987 hwmgr->thermal_controller.ucType = 988 powerplay_table->sThermalController.ucType; 989 hwmgr->thermal_controller.ucI2cLine = 990 powerplay_table->sThermalController.ucI2cLine; 991 hwmgr->thermal_controller.ucI2cAddress = 992 powerplay_table->sThermalController.ucI2cAddress; 993 994 hwmgr->thermal_controller.fanInfo.bNoFan = 995 (0 != (powerplay_table->sThermalController.ucFanParameters & 996 ATOM_PP_FANPARAMETERS_NOFAN)); 997 998 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution = 999 powerplay_table->sThermalController.ucFanParameters & 1000 ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK; 1001 1002 hwmgr->thermal_controller.fanInfo.ulMinRPM 1003 = powerplay_table->sThermalController.ucFanMinRPM * 100UL; 1004 hwmgr->thermal_controller.fanInfo.ulMaxRPM 1005 = powerplay_table->sThermalController.ucFanMaxRPM * 100UL; 1006 1007 set_hw_cap(hwmgr, 1008 ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType, 1009 PHM_PlatformCaps_ThermalController); 1010 1011 if (powerplay_table->usTableSize >= sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) { 1012 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 = 1013 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 1014 1015 if (0 == le16_to_cpu(powerplay_table3->usFanTableOffset)) { 1016 hwmgr->thermal_controller.use_hw_fan_control = 1; 1017 return 0; 1018 } else { 1019 const ATOM_PPLIB_FANTABLE *fan_table = 1020 (const ATOM_PPLIB_FANTABLE *)(((unsigned long)powerplay_table) + 1021 le16_to_cpu(powerplay_table3->usFanTableOffset)); 1022 1023 if (1 <= fan_table->ucFanTableFormat) { 1024 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst = 1025 fan_table->ucTHyst; 1026 hwmgr->thermal_controller.advanceFanControlParameters.usTMin = 1027 le16_to_cpu(fan_table->usTMin); 1028 hwmgr->thermal_controller.advanceFanControlParameters.usTMed = 1029 le16_to_cpu(fan_table->usTMed); 1030 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh = 1031 le16_to_cpu(fan_table->usTHigh); 1032 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin = 1033 le16_to_cpu(fan_table->usPWMMin); 1034 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed = 1035 le16_to_cpu(fan_table->usPWMMed); 1036 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh = 1037 le16_to_cpu(fan_table->usPWMHigh); 1038 hwmgr->thermal_controller.advanceFanControlParameters.usTMax = 10900; 1039 hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay = 100000; 1040 1041 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 1042 PHM_PlatformCaps_MicrocodeFanControl); 1043 } 1044 1045 if (2 <= fan_table->ucFanTableFormat) { 1046 const ATOM_PPLIB_FANTABLE2 *fan_table2 = 1047 (const ATOM_PPLIB_FANTABLE2 *)(((unsigned long)powerplay_table) + 1048 le16_to_cpu(powerplay_table3->usFanTableOffset)); 1049 hwmgr->thermal_controller.advanceFanControlParameters.usTMax = 1050 le16_to_cpu(fan_table2->usTMax); 1051 } 1052 1053 if (3 <= fan_table->ucFanTableFormat) { 1054 const ATOM_PPLIB_FANTABLE3 *fan_table3 = 1055 (const ATOM_PPLIB_FANTABLE3 *) (((unsigned long)powerplay_table) + 1056 le16_to_cpu(powerplay_table3->usFanTableOffset)); 1057 1058 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode = 1059 fan_table3->ucFanControlMode; 1060 1061 if ((3 == fan_table->ucFanTableFormat) && 1062 (0x67B1 == adev->pdev->device)) 1063 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM = 1064 47; 1065 else 1066 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM = 1067 le16_to_cpu(fan_table3->usFanPWMMax); 1068 1069 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity = 1070 4836; 1071 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity = 1072 le16_to_cpu(fan_table3->usFanOutputSensitivity); 1073 } 1074 1075 if (6 <= fan_table->ucFanTableFormat) { 1076 const ATOM_PPLIB_FANTABLE4 *fan_table4 = 1077 (const ATOM_PPLIB_FANTABLE4 *)(((unsigned long)powerplay_table) + 1078 le16_to_cpu(powerplay_table3->usFanTableOffset)); 1079 1080 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 1081 PHM_PlatformCaps_FanSpeedInTableIsRPM); 1082 1083 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM = 1084 le16_to_cpu(fan_table4->usFanRPMMax); 1085 } 1086 1087 if (7 <= fan_table->ucFanTableFormat) { 1088 const ATOM_PPLIB_FANTABLE5 *fan_table5 = 1089 (const ATOM_PPLIB_FANTABLE5 *)(((unsigned long)powerplay_table) + 1090 le16_to_cpu(powerplay_table3->usFanTableOffset)); 1091 1092 if (0x67A2 == adev->pdev->device || 1093 0x67A9 == adev->pdev->device || 1094 0x67B9 == adev->pdev->device) { 1095 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 1096 PHM_PlatformCaps_GeminiRegulatorFanControlSupport); 1097 hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentLow = 1098 le16_to_cpu(fan_table5->usFanCurrentLow); 1099 hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentHigh = 1100 le16_to_cpu(fan_table5->usFanCurrentHigh); 1101 hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMLow = 1102 le16_to_cpu(fan_table5->usFanRPMLow); 1103 hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMHigh = 1104 le16_to_cpu(fan_table5->usFanRPMHigh); 1105 } 1106 } 1107 } 1108 } 1109 1110 return 0; 1111 } 1112 1113 static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr, 1114 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, 1115 const ATOM_FIRMWARE_INFO_V1_4 *fw_info) 1116 { 1117 hwmgr->platform_descriptor.overdriveLimit.engineClock = 1118 le32_to_cpu(fw_info->ulASICMaxEngineClock); 1119 1120 hwmgr->platform_descriptor.overdriveLimit.memoryClock = 1121 le32_to_cpu(fw_info->ulASICMaxMemoryClock); 1122 1123 hwmgr->platform_descriptor.maxOverdriveVDDC = 1124 le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF; 1125 1126 hwmgr->platform_descriptor.minOverdriveVDDC = 1127 le16_to_cpu(fw_info->usBootUpVDDCVoltage); 1128 1129 hwmgr->platform_descriptor.maxOverdriveVDDC = 1130 le16_to_cpu(fw_info->usBootUpVDDCVoltage); 1131 1132 hwmgr->platform_descriptor.overdriveVDDCStep = 0; 1133 return 0; 1134 } 1135 1136 static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr, 1137 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table, 1138 const ATOM_FIRMWARE_INFO_V2_1 *fw_info) 1139 { 1140 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3; 1141 const ATOM_PPLIB_EXTENDEDHEADER *header; 1142 1143 if (le16_to_cpu(powerplay_table->usTableSize) < 1144 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) 1145 return 0; 1146 1147 powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table; 1148 1149 if (0 == powerplay_table3->usExtendendedHeaderOffset) 1150 return 0; 1151 1152 header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) + 1153 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset)); 1154 1155 hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock); 1156 hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock); 1157 1158 1159 hwmgr->platform_descriptor.minOverdriveVDDC = 0; 1160 hwmgr->platform_descriptor.maxOverdriveVDDC = 0; 1161 hwmgr->platform_descriptor.overdriveVDDCStep = 0; 1162 1163 return 0; 1164 } 1165 1166 static int init_overdrive_limits(struct pp_hwmgr *hwmgr, 1167 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 1168 { 1169 int result = 0; 1170 uint8_t frev, crev; 1171 uint16_t size; 1172 1173 const ATOM_COMMON_TABLE_HEADER *fw_info = NULL; 1174 1175 hwmgr->platform_descriptor.overdriveLimit.engineClock = 0; 1176 hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0; 1177 hwmgr->platform_descriptor.minOverdriveVDDC = 0; 1178 hwmgr->platform_descriptor.maxOverdriveVDDC = 0; 1179 hwmgr->platform_descriptor.overdriveVDDCStep = 0; 1180 1181 if (hwmgr->chip_id == CHIP_RAVEN) 1182 return 0; 1183 1184 /* We assume here that fw_info is unchanged if this call fails.*/ 1185 fw_info = smu_atom_get_data_table(hwmgr->adev, 1186 GetIndexIntoMasterTable(DATA, FirmwareInfo), 1187 &size, &frev, &crev); 1188 PP_ASSERT_WITH_CODE(fw_info != NULL, 1189 "Missing firmware info!", return -EINVAL); 1190 1191 if ((fw_info->ucTableFormatRevision == 1) 1192 && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4))) 1193 result = init_overdrive_limits_V1_4(hwmgr, 1194 powerplay_table, 1195 (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info); 1196 1197 else if ((fw_info->ucTableFormatRevision == 2) 1198 && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1))) 1199 result = init_overdrive_limits_V2_1(hwmgr, 1200 powerplay_table, 1201 (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info); 1202 1203 return result; 1204 } 1205 1206 static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, 1207 struct phm_uvd_clock_voltage_dependency_table **ptable, 1208 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table, 1209 const UVDClockInfoArray *array) 1210 { 1211 unsigned long i; 1212 struct phm_uvd_clock_voltage_dependency_table *uvd_table; 1213 1214 uvd_table = kzalloc(struct_size(uvd_table, entries, table->numEntries), 1215 GFP_KERNEL); 1216 if (!uvd_table) 1217 return -ENOMEM; 1218 1219 uvd_table->count = table->numEntries; 1220 1221 for (i = 0; i < table->numEntries; i++) { 1222 const UVDClockInfo *entry = 1223 &array->entries[table->entries[i].ucUVDClockInfoIndex]; 1224 uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); 1225 uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16) 1226 | le16_to_cpu(entry->usVClkLow); 1227 uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16) 1228 | le16_to_cpu(entry->usDClkLow); 1229 } 1230 1231 *ptable = uvd_table; 1232 1233 return 0; 1234 } 1235 1236 static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, 1237 struct phm_vce_clock_voltage_dependency_table **ptable, 1238 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table, 1239 const VCEClockInfoArray *array) 1240 { 1241 unsigned long i; 1242 struct phm_vce_clock_voltage_dependency_table *vce_table; 1243 1244 vce_table = kzalloc(struct_size(vce_table, entries, table->numEntries), 1245 GFP_KERNEL); 1246 if (!vce_table) 1247 return -ENOMEM; 1248 1249 vce_table->count = table->numEntries; 1250 for (i = 0; i < table->numEntries; i++) { 1251 const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex]; 1252 1253 vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); 1254 vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16) 1255 | le16_to_cpu(entry->usEVClkLow); 1256 vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16) 1257 | le16_to_cpu(entry->usECClkLow); 1258 } 1259 1260 *ptable = vce_table; 1261 1262 return 0; 1263 } 1264 1265 static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, 1266 struct phm_samu_clock_voltage_dependency_table **ptable, 1267 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table) 1268 { 1269 unsigned long i; 1270 struct phm_samu_clock_voltage_dependency_table *samu_table; 1271 1272 samu_table = kzalloc(struct_size(samu_table, entries, table->numEntries), 1273 GFP_KERNEL); 1274 if (!samu_table) 1275 return -ENOMEM; 1276 1277 samu_table->count = table->numEntries; 1278 1279 for (i = 0; i < table->numEntries; i++) { 1280 samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); 1281 samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16) 1282 | le16_to_cpu(table->entries[i].usSAMClockLow); 1283 } 1284 1285 *ptable = samu_table; 1286 1287 return 0; 1288 } 1289 1290 static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr, 1291 struct phm_acp_clock_voltage_dependency_table **ptable, 1292 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table) 1293 { 1294 unsigned long i; 1295 struct phm_acp_clock_voltage_dependency_table *acp_table; 1296 1297 acp_table = kzalloc(struct_size(acp_table, entries, table->numEntries), 1298 GFP_KERNEL); 1299 if (!acp_table) 1300 return -ENOMEM; 1301 1302 acp_table->count = (unsigned long)table->numEntries; 1303 1304 for (i = 0; i < table->numEntries; i++) { 1305 acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage); 1306 acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16) 1307 | le16_to_cpu(table->entries[i].usACPClockLow); 1308 } 1309 1310 *ptable = acp_table; 1311 1312 return 0; 1313 } 1314 1315 static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr, 1316 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 1317 { 1318 ATOM_PPLIB_Clock_Voltage_Dependency_Table *table; 1319 ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table; 1320 int result = 0; 1321 1322 uint16_t vce_clock_info_array_offset; 1323 uint16_t uvd_clock_info_array_offset; 1324 uint16_t table_offset; 1325 1326 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL; 1327 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL; 1328 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL; 1329 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL; 1330 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL; 1331 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL; 1332 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL; 1333 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL; 1334 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL; 1335 hwmgr->dyn_state.ppm_parameter_table = NULL; 1336 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL; 1337 1338 vce_clock_info_array_offset = get_vce_clock_info_array_offset( 1339 hwmgr, powerplay_table); 1340 table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, 1341 powerplay_table); 1342 if (vce_clock_info_array_offset > 0 && table_offset > 0) { 1343 const VCEClockInfoArray *array = (const VCEClockInfoArray *) 1344 (((unsigned long) powerplay_table) + 1345 vce_clock_info_array_offset); 1346 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table = 1347 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *) 1348 (((unsigned long) powerplay_table) + table_offset); 1349 result = get_vce_clock_voltage_limit_table(hwmgr, 1350 &hwmgr->dyn_state.vce_clock_voltage_dependency_table, 1351 table, array); 1352 } 1353 1354 uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table); 1355 table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table); 1356 1357 if (uvd_clock_info_array_offset > 0 && table_offset > 0) { 1358 const UVDClockInfoArray *array = (const UVDClockInfoArray *) 1359 (((unsigned long) powerplay_table) + 1360 uvd_clock_info_array_offset); 1361 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable = 1362 (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *) 1363 (((unsigned long) powerplay_table) + table_offset); 1364 result = get_uvd_clock_voltage_limit_table(hwmgr, 1365 &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array); 1366 } 1367 1368 table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr, 1369 powerplay_table); 1370 1371 if (table_offset > 0) { 1372 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable = 1373 (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *) 1374 (((unsigned long) powerplay_table) + table_offset); 1375 result = get_samu_clock_voltage_limit_table(hwmgr, 1376 &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable); 1377 } 1378 1379 table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr, 1380 powerplay_table); 1381 1382 if (table_offset > 0) { 1383 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable = 1384 (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *) 1385 (((unsigned long) powerplay_table) + table_offset); 1386 result = get_acp_clock_voltage_limit_table(hwmgr, 1387 &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable); 1388 } 1389 1390 table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table); 1391 if (table_offset > 0) { 1392 UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset); 1393 1394 if (rev_id > 0) { 1395 const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table = 1396 (const ATOM_PPLIB_POWERTUNE_Table_V1 *) 1397 (((unsigned long) powerplay_table) + table_offset); 1398 result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table, 1399 &tune_table->power_tune_table, 1400 le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit)); 1401 hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp = 1402 le16_to_cpu(tune_table->usTjMax); 1403 } else { 1404 const ATOM_PPLIB_POWERTUNE_Table *tune_table = 1405 (const ATOM_PPLIB_POWERTUNE_Table *) 1406 (((unsigned long) powerplay_table) + table_offset); 1407 result = get_cac_tdp_table(hwmgr, 1408 &hwmgr->dyn_state.cac_dtp_table, 1409 &tune_table->power_tune_table, 255); 1410 } 1411 } 1412 1413 if (le16_to_cpu(powerplay_table->usTableSize) >= 1414 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) { 1415 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 = 1416 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table; 1417 if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) { 1418 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 1419 (((unsigned long) powerplay_table4) + 1420 le16_to_cpu(powerplay_table4->usVddcDependencyOnSCLKOffset)); 1421 result = get_clock_voltage_dependency_table(hwmgr, 1422 &hwmgr->dyn_state.vddc_dependency_on_sclk, table); 1423 } 1424 1425 if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) { 1426 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 1427 (((unsigned long) powerplay_table4) + 1428 le16_to_cpu(powerplay_table4->usVddciDependencyOnMCLKOffset)); 1429 result = get_clock_voltage_dependency_table(hwmgr, 1430 &hwmgr->dyn_state.vddci_dependency_on_mclk, table); 1431 } 1432 1433 if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) { 1434 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 1435 (((unsigned long) powerplay_table4) + 1436 le16_to_cpu(powerplay_table4->usVddcDependencyOnMCLKOffset)); 1437 result = get_clock_voltage_dependency_table(hwmgr, 1438 &hwmgr->dyn_state.vddc_dependency_on_mclk, table); 1439 } 1440 1441 if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) { 1442 limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *) 1443 (((unsigned long) powerplay_table4) + 1444 le16_to_cpu(powerplay_table4->usMaxClockVoltageOnDCOffset)); 1445 result = get_clock_voltage_limit(hwmgr, 1446 &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table); 1447 } 1448 1449 if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) && 1450 (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count)) 1451 result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values, 1452 hwmgr->dyn_state.vddc_dependency_on_mclk); 1453 1454 if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) && 1455 (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count)) 1456 result = get_valid_clk(hwmgr, 1457 &hwmgr->dyn_state.valid_sclk_values, 1458 hwmgr->dyn_state.vddc_dependency_on_sclk); 1459 1460 if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) { 1461 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 1462 (((unsigned long) powerplay_table4) + 1463 le16_to_cpu(powerplay_table4->usMvddDependencyOnMCLKOffset)); 1464 result = get_clock_voltage_dependency_table(hwmgr, 1465 &hwmgr->dyn_state.mvdd_dependency_on_mclk, table); 1466 } 1467 } 1468 1469 table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr, 1470 powerplay_table); 1471 1472 if (table_offset > 0) { 1473 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *) 1474 (((unsigned long) powerplay_table) + table_offset); 1475 result = get_clock_voltage_dependency_table(hwmgr, 1476 &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table); 1477 } 1478 1479 return result; 1480 } 1481 1482 static int get_cac_leakage_table(struct pp_hwmgr *hwmgr, 1483 struct phm_cac_leakage_table **ptable, 1484 const ATOM_PPLIB_CAC_Leakage_Table *table) 1485 { 1486 struct phm_cac_leakage_table *cac_leakage_table; 1487 unsigned long i; 1488 1489 if (!hwmgr || !table || !ptable) 1490 return -EINVAL; 1491 1492 cac_leakage_table = kzalloc(struct_size(cac_leakage_table, entries, table->ucNumEntries), 1493 GFP_KERNEL); 1494 if (!cac_leakage_table) 1495 return -ENOMEM; 1496 1497 cac_leakage_table->count = (ULONG)table->ucNumEntries; 1498 1499 for (i = 0; i < cac_leakage_table->count; i++) { 1500 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, 1501 PHM_PlatformCaps_EVV)) { 1502 cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1); 1503 cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2); 1504 cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3); 1505 } else { 1506 cac_leakage_table->entries[i].Vddc = le16_to_cpu(table->entries[i].usVddc); 1507 cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue); 1508 } 1509 } 1510 1511 *ptable = cac_leakage_table; 1512 1513 return 0; 1514 } 1515 1516 static int get_platform_power_management_table(struct pp_hwmgr *hwmgr, 1517 ATOM_PPLIB_PPM_Table *atom_ppm_table) 1518 { 1519 struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL); 1520 1521 if (NULL == ptr) 1522 return -ENOMEM; 1523 1524 ptr->ppm_design = atom_ppm_table->ucPpmDesign; 1525 ptr->cpu_core_number = le16_to_cpu(atom_ppm_table->usCpuCoreNumber); 1526 ptr->platform_tdp = le32_to_cpu(atom_ppm_table->ulPlatformTDP); 1527 ptr->small_ac_platform_tdp = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP); 1528 ptr->platform_tdc = le32_to_cpu(atom_ppm_table->ulPlatformTDC); 1529 ptr->small_ac_platform_tdc = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC); 1530 ptr->apu_tdp = le32_to_cpu(atom_ppm_table->ulApuTDP); 1531 ptr->dgpu_tdp = le32_to_cpu(atom_ppm_table->ulDGpuTDP); 1532 ptr->dgpu_ulv_power = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower); 1533 ptr->tj_max = le32_to_cpu(atom_ppm_table->ulTjmax); 1534 hwmgr->dyn_state.ppm_parameter_table = ptr; 1535 1536 return 0; 1537 } 1538 1539 static int init_dpm2_parameters(struct pp_hwmgr *hwmgr, 1540 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 1541 { 1542 int result = 0; 1543 1544 if (le16_to_cpu(powerplay_table->usTableSize) >= 1545 sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) { 1546 const ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 = 1547 (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table; 1548 const ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 = 1549 (const ATOM_PPLIB_POWERPLAYTABLE4 *) 1550 (&ptable5->basicTable4); 1551 const ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 = 1552 (const ATOM_PPLIB_POWERPLAYTABLE3 *) 1553 (&ptable4->basicTable3); 1554 const ATOM_PPLIB_EXTENDEDHEADER *extended_header; 1555 uint16_t table_offset; 1556 ATOM_PPLIB_PPM_Table *atom_ppm_table; 1557 1558 hwmgr->platform_descriptor.TDPLimit = le32_to_cpu(ptable5->ulTDPLimit); 1559 hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit); 1560 1561 hwmgr->platform_descriptor.TDPODLimit = le16_to_cpu(ptable5->usTDPODLimit); 1562 hwmgr->platform_descriptor.TDPAdjustment = 0; 1563 1564 hwmgr->platform_descriptor.VidAdjustment = 0; 1565 hwmgr->platform_descriptor.VidAdjustmentPolarity = 0; 1566 hwmgr->platform_descriptor.VidMinLimit = 0; 1567 hwmgr->platform_descriptor.VidMaxLimit = 1500000; 1568 hwmgr->platform_descriptor.VidStep = 6250; 1569 1570 hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit); 1571 1572 if (hwmgr->platform_descriptor.TDPODLimit != 0) 1573 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 1574 PHM_PlatformCaps_PowerControl); 1575 1576 hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold); 1577 1578 hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage); 1579 1580 hwmgr->dyn_state.cac_leakage_table = NULL; 1581 1582 if (0 != ptable5->usCACLeakageTableOffset) { 1583 const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table = 1584 (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) + 1585 le16_to_cpu(ptable5->usCACLeakageTableOffset)); 1586 result = get_cac_leakage_table(hwmgr, 1587 &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table); 1588 } 1589 1590 hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope); 1591 1592 hwmgr->dyn_state.ppm_parameter_table = NULL; 1593 1594 if (0 != ptable3->usExtendendedHeaderOffset) { 1595 extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *) 1596 (((unsigned long)powerplay_table) + 1597 le16_to_cpu(ptable3->usExtendendedHeaderOffset)); 1598 if ((extended_header->usPPMTableOffset > 0) && 1599 le16_to_cpu(extended_header->usSize) >= 1600 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) { 1601 table_offset = le16_to_cpu(extended_header->usPPMTableOffset); 1602 atom_ppm_table = (ATOM_PPLIB_PPM_Table *) 1603 (((unsigned long)powerplay_table) + table_offset); 1604 if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table)) 1605 phm_cap_set(hwmgr->platform_descriptor.platformCaps, 1606 PHM_PlatformCaps_EnablePlatformPowerManagement); 1607 } 1608 } 1609 } 1610 return result; 1611 } 1612 1613 static int init_phase_shedding_table(struct pp_hwmgr *hwmgr, 1614 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table) 1615 { 1616 if (le16_to_cpu(powerplay_table->usTableSize) >= 1617 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) { 1618 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 = 1619 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table; 1620 1621 if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) { 1622 const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable = 1623 (ATOM_PPLIB_PhaseSheddingLimits_Table *) 1624 (((unsigned long)powerplay_table4) + 1625 le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset)); 1626 struct phm_phase_shedding_limits_table *table; 1627 unsigned long i; 1628 1629 1630 table = kzalloc(struct_size(table, entries, ptable->ucNumEntries), 1631 GFP_KERNEL); 1632 if (!table) 1633 return -ENOMEM; 1634 1635 table->count = (unsigned long)ptable->ucNumEntries; 1636 1637 for (i = 0; i < table->count; i++) { 1638 table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage); 1639 table->entries[i].Sclk = ((unsigned long)ptable->entries[i].ucSclkHigh << 16) 1640 | le16_to_cpu(ptable->entries[i].usSclkLow); 1641 table->entries[i].Mclk = ((unsigned long)ptable->entries[i].ucMclkHigh << 16) 1642 | le16_to_cpu(ptable->entries[i].usMclkLow); 1643 } 1644 hwmgr->dyn_state.vddc_phase_shed_limits_table = table; 1645 } 1646 } 1647 1648 return 0; 1649 } 1650 1651 static int get_number_of_vce_state_table_entries( 1652 struct pp_hwmgr *hwmgr) 1653 { 1654 const ATOM_PPLIB_POWERPLAYTABLE *table = 1655 get_powerplay_table(hwmgr); 1656 const ATOM_PPLIB_VCE_State_Table *vce_table = 1657 get_vce_state_table(hwmgr, table); 1658 1659 if (vce_table) 1660 return vce_table->numEntries; 1661 1662 return 0; 1663 } 1664 1665 static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr, 1666 unsigned long i, 1667 struct amd_vce_state *vce_state, 1668 void **clock_info, 1669 unsigned long *flag) 1670 { 1671 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr); 1672 1673 const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table); 1674 1675 unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table); 1676 1677 const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset); 1678 1679 const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) + 1680 le16_to_cpu(powerplay_table->usClockInfoArrayOffset)); 1681 1682 const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i]; 1683 1684 const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex]; 1685 1686 unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F; 1687 1688 *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX); 1689 1690 vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | le16_to_cpu(vce_clock_info->usEVClkLow); 1691 vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | le16_to_cpu(vce_clock_info->usECClkLow); 1692 1693 *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize)); 1694 1695 return 0; 1696 } 1697 1698 1699 static int pp_tables_initialize(struct pp_hwmgr *hwmgr) 1700 { 1701 int result; 1702 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table; 1703 1704 if (hwmgr->chip_id == CHIP_RAVEN) 1705 return 0; 1706 1707 hwmgr->need_pp_table_upload = true; 1708 1709 powerplay_table = get_powerplay_table(hwmgr); 1710 1711 result = init_powerplay_tables(hwmgr, powerplay_table); 1712 1713 PP_ASSERT_WITH_CODE((result == 0), 1714 "init_powerplay_tables failed", return result); 1715 1716 result = set_platform_caps(hwmgr, 1717 le32_to_cpu(powerplay_table->ulPlatformCaps)); 1718 1719 PP_ASSERT_WITH_CODE((result == 0), 1720 "set_platform_caps failed", return result); 1721 1722 result = init_thermal_controller(hwmgr, powerplay_table); 1723 1724 PP_ASSERT_WITH_CODE((result == 0), 1725 "init_thermal_controller failed", return result); 1726 1727 result = init_overdrive_limits(hwmgr, powerplay_table); 1728 1729 PP_ASSERT_WITH_CODE((result == 0), 1730 "init_overdrive_limits failed", return result); 1731 1732 result = init_clock_voltage_dependency(hwmgr, 1733 powerplay_table); 1734 1735 PP_ASSERT_WITH_CODE((result == 0), 1736 "init_clock_voltage_dependency failed", return result); 1737 1738 result = init_dpm2_parameters(hwmgr, powerplay_table); 1739 1740 PP_ASSERT_WITH_CODE((result == 0), 1741 "init_dpm2_parameters failed", return result); 1742 1743 result = init_phase_shedding_table(hwmgr, powerplay_table); 1744 1745 PP_ASSERT_WITH_CODE((result == 0), 1746 "init_phase_shedding_table failed", return result); 1747 1748 return result; 1749 } 1750 1751 static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr) 1752 { 1753 if (hwmgr->chip_id == CHIP_RAVEN) 1754 return 0; 1755 1756 kfree(hwmgr->dyn_state.vddc_dependency_on_sclk); 1757 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL; 1758 1759 kfree(hwmgr->dyn_state.vddci_dependency_on_mclk); 1760 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL; 1761 1762 kfree(hwmgr->dyn_state.vddc_dependency_on_mclk); 1763 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL; 1764 1765 kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk); 1766 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL; 1767 1768 kfree(hwmgr->dyn_state.valid_mclk_values); 1769 hwmgr->dyn_state.valid_mclk_values = NULL; 1770 1771 kfree(hwmgr->dyn_state.valid_sclk_values); 1772 hwmgr->dyn_state.valid_sclk_values = NULL; 1773 1774 kfree(hwmgr->dyn_state.cac_leakage_table); 1775 hwmgr->dyn_state.cac_leakage_table = NULL; 1776 1777 kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table); 1778 hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL; 1779 1780 kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table); 1781 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL; 1782 1783 kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table); 1784 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL; 1785 1786 kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table); 1787 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL; 1788 1789 kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table); 1790 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL; 1791 1792 kfree(hwmgr->dyn_state.cac_dtp_table); 1793 hwmgr->dyn_state.cac_dtp_table = NULL; 1794 1795 kfree(hwmgr->dyn_state.ppm_parameter_table); 1796 hwmgr->dyn_state.ppm_parameter_table = NULL; 1797 1798 kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk); 1799 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL; 1800 1801 return 0; 1802 } 1803 1804 const struct pp_table_func pptable_funcs = { 1805 .pptable_init = pp_tables_initialize, 1806 .pptable_fini = pp_tables_uninitialize, 1807 .pptable_get_number_of_vce_state_table_entries = 1808 get_number_of_vce_state_table_entries, 1809 .pptable_get_vce_state_table_entry = 1810 get_vce_state_table_entry, 1811 }; 1812 1813