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