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