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