0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023 #include "pp_debug.h"
0024 #include <linux/types.h>
0025 #include <linux/kernel.h>
0026 #include <linux/slab.h>
0027 #include <linux/pci.h>
0028
0029 #include <drm/amdgpu_drm.h>
0030 #include "processpptables.h"
0031 #include <atom-types.h>
0032 #include <atombios.h>
0033 #include "pptable.h"
0034 #include "power_state.h"
0035 #include "hwmgr.h"
0036 #include "hardwaremanager.h"
0037
0038
0039 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
0040 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
0041 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
0042 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
0043 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
0044 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
0045 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
0046 #define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
0047
0048 #define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
0049
0050 static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
0051 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0052 {
0053 uint16_t vce_table_offset = 0;
0054
0055 if (le16_to_cpu(powerplay_table->usTableSize) >=
0056 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0057 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0058 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0059
0060 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0061 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
0062 (const ATOM_PPLIB_EXTENDEDHEADER *)
0063 (((unsigned long)powerplay_table3) +
0064 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0065 if (le16_to_cpu(extended_header->usSize) >=
0066 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
0067 vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
0068 }
0069 }
0070
0071 return vce_table_offset;
0072 }
0073
0074 static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
0075 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0076 {
0077 uint16_t table_offset = get_vce_table_offset(hwmgr,
0078 powerplay_table);
0079
0080 if (table_offset > 0)
0081 return table_offset + 1;
0082
0083 return 0;
0084 }
0085
0086 static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
0087 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0088 {
0089 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
0090 powerplay_table);
0091 uint16_t table_size = 0;
0092
0093 if (table_offset > 0) {
0094 const VCEClockInfoArray *p = (const VCEClockInfoArray *)
0095 (((unsigned long) powerplay_table) + table_offset);
0096 table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
0097 }
0098
0099 return table_size;
0100 }
0101
0102 static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
0103 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0104 {
0105 uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
0106 powerplay_table);
0107
0108 if (table_offset > 0)
0109 return table_offset + get_vce_clock_info_array_size(hwmgr,
0110 powerplay_table);
0111
0112 return 0;
0113 }
0114
0115 static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
0116 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0117 {
0118 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
0119 uint16_t table_size = 0;
0120
0121 if (table_offset > 0) {
0122 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
0123 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
0124
0125 table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
0126 }
0127 return table_size;
0128 }
0129
0130 static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0131 {
0132 uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
0133
0134 if (table_offset > 0)
0135 return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
0136
0137 return 0;
0138 }
0139
0140 static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
0141 struct pp_hwmgr *hwmgr,
0142 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0143 {
0144 uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
0145
0146 if (table_offset > 0)
0147 return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
0148
0149 return NULL;
0150 }
0151
0152 static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
0153 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0154 {
0155 uint16_t uvd_table_offset = 0;
0156
0157 if (le16_to_cpu(powerplay_table->usTableSize) >=
0158 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0159 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0160 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0161 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0162 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
0163 (const ATOM_PPLIB_EXTENDEDHEADER *)
0164 (((unsigned long)powerplay_table3) +
0165 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0166 if (le16_to_cpu(extended_header->usSize) >=
0167 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
0168 uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
0169 }
0170 }
0171 return uvd_table_offset;
0172 }
0173
0174 static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
0175 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0176 {
0177 uint16_t table_offset = get_uvd_table_offset(hwmgr,
0178 powerplay_table);
0179
0180 if (table_offset > 0)
0181 return table_offset + 1;
0182 return 0;
0183 }
0184
0185 static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
0186 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0187 {
0188 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
0189 powerplay_table);
0190 uint16_t table_size = 0;
0191
0192 if (table_offset > 0) {
0193 const UVDClockInfoArray *p = (const UVDClockInfoArray *)
0194 (((unsigned long) powerplay_table)
0195 + table_offset);
0196 table_size = sizeof(UCHAR) +
0197 p->ucNumEntries * sizeof(UVDClockInfo);
0198 }
0199
0200 return table_size;
0201 }
0202
0203 static uint16_t get_uvd_clock_voltage_limit_table_offset(
0204 struct pp_hwmgr *hwmgr,
0205 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0206 {
0207 uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
0208 powerplay_table);
0209
0210 if (table_offset > 0)
0211 return table_offset +
0212 get_uvd_clock_info_array_size(hwmgr, powerplay_table);
0213
0214 return 0;
0215 }
0216
0217 static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
0218 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0219 {
0220 uint16_t samu_table_offset = 0;
0221
0222 if (le16_to_cpu(powerplay_table->usTableSize) >=
0223 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0224 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0225 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0226 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0227 const ATOM_PPLIB_EXTENDEDHEADER *extended_header =
0228 (const ATOM_PPLIB_EXTENDEDHEADER *)
0229 (((unsigned long)powerplay_table3) +
0230 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0231 if (le16_to_cpu(extended_header->usSize) >=
0232 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
0233 samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
0234 }
0235 }
0236
0237 return samu_table_offset;
0238 }
0239
0240 static uint16_t get_samu_clock_voltage_limit_table_offset(
0241 struct pp_hwmgr *hwmgr,
0242 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0243 {
0244 uint16_t table_offset = get_samu_table_offset(hwmgr,
0245 powerplay_table);
0246
0247 if (table_offset > 0)
0248 return table_offset + 1;
0249
0250 return 0;
0251 }
0252
0253 static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
0254 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0255 {
0256 uint16_t acp_table_offset = 0;
0257
0258 if (le16_to_cpu(powerplay_table->usTableSize) >=
0259 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0260 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0261 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0262 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0263 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
0264 (const ATOM_PPLIB_EXTENDEDHEADER *)
0265 (((unsigned long)powerplay_table3) +
0266 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0267 if (le16_to_cpu(pExtendedHeader->usSize) >=
0268 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
0269 acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
0270 }
0271 }
0272
0273 return acp_table_offset;
0274 }
0275
0276 static uint16_t get_acp_clock_voltage_limit_table_offset(
0277 struct pp_hwmgr *hwmgr,
0278 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0279 {
0280 uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
0281
0282 if (tableOffset > 0)
0283 return tableOffset + 1;
0284
0285 return 0;
0286 }
0287
0288 static uint16_t get_cacp_tdp_table_offset(
0289 struct pp_hwmgr *hwmgr,
0290 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0291 {
0292 uint16_t cacTdpTableOffset = 0;
0293
0294 if (le16_to_cpu(powerplay_table->usTableSize) >=
0295 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0296 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0297 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0298 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0299 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
0300 (const ATOM_PPLIB_EXTENDEDHEADER *)
0301 (((unsigned long)powerplay_table3) +
0302 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0303 if (le16_to_cpu(pExtendedHeader->usSize) >=
0304 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
0305 cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
0306 }
0307 }
0308
0309 return cacTdpTableOffset;
0310 }
0311
0312 static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
0313 struct phm_cac_tdp_table **ptable,
0314 const ATOM_PowerTune_Table *table,
0315 uint16_t us_maximum_power_delivery_limit)
0316 {
0317 unsigned long table_size;
0318 struct phm_cac_tdp_table *tdp_table;
0319
0320 table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
0321
0322 tdp_table = kzalloc(table_size, GFP_KERNEL);
0323 if (NULL == tdp_table)
0324 return -ENOMEM;
0325
0326 tdp_table->usTDP = le16_to_cpu(table->usTDP);
0327 tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
0328 tdp_table->usTDC = le16_to_cpu(table->usTDC);
0329 tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
0330 tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
0331 tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
0332 tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
0333 tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
0334
0335 *ptable = tdp_table;
0336
0337 return 0;
0338 }
0339
0340 static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
0341 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0342 {
0343 uint16_t sclk_vdd_gfx_table_offset = 0;
0344
0345 if (le16_to_cpu(powerplay_table->usTableSize) >=
0346 sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
0347 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
0348 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
0349 if (powerplay_table3->usExtendendedHeaderOffset > 0) {
0350 const ATOM_PPLIB_EXTENDEDHEADER *pExtendedHeader =
0351 (const ATOM_PPLIB_EXTENDEDHEADER *)
0352 (((unsigned long)powerplay_table3) +
0353 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
0354 if (le16_to_cpu(pExtendedHeader->usSize) >=
0355 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
0356 sclk_vdd_gfx_table_offset =
0357 le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
0358 }
0359 }
0360
0361 return sclk_vdd_gfx_table_offset;
0362 }
0363
0364 static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
0365 struct pp_hwmgr *hwmgr,
0366 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0367 {
0368 uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
0369
0370 if (tableOffset > 0)
0371 return tableOffset;
0372
0373 return 0;
0374 }
0375
0376
0377 static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
0378 struct phm_clock_voltage_dependency_table **ptable,
0379 const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
0380 {
0381
0382 unsigned long i;
0383 struct phm_clock_voltage_dependency_table *dep_table;
0384
0385 dep_table = kzalloc(struct_size(dep_table, entries, table->ucNumEntries),
0386 GFP_KERNEL);
0387 if (NULL == dep_table)
0388 return -ENOMEM;
0389
0390 dep_table->count = (unsigned long)table->ucNumEntries;
0391
0392 for (i = 0; i < dep_table->count; i++) {
0393 dep_table->entries[i].clk =
0394 ((unsigned long)table->entries[i].ucClockHigh << 16) |
0395 le16_to_cpu(table->entries[i].usClockLow);
0396 dep_table->entries[i].v =
0397 (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
0398 }
0399
0400 *ptable = dep_table;
0401
0402 return 0;
0403 }
0404
0405 static int get_valid_clk(struct pp_hwmgr *hwmgr,
0406 struct phm_clock_array **ptable,
0407 const struct phm_clock_voltage_dependency_table *table)
0408 {
0409 unsigned long i;
0410 struct phm_clock_array *clock_table;
0411
0412 clock_table = kzalloc(struct_size(clock_table, values, table->count), GFP_KERNEL);
0413 if (!clock_table)
0414 return -ENOMEM;
0415
0416 clock_table->count = (unsigned long)table->count;
0417
0418 for (i = 0; i < clock_table->count; i++)
0419 clock_table->values[i] = (unsigned long)table->entries[i].clk;
0420
0421 *ptable = clock_table;
0422
0423 return 0;
0424 }
0425
0426 static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
0427 struct phm_clock_and_voltage_limits *limits,
0428 const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
0429 {
0430 limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
0431 le16_to_cpu(table->entries[0].usSclkLow);
0432 limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
0433 le16_to_cpu(table->entries[0].usMclkLow);
0434 limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
0435 limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
0436
0437 return 0;
0438 }
0439
0440
0441 static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
0442 enum phm_platform_caps cap)
0443 {
0444 if (enable)
0445 phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
0446 else
0447 phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
0448 }
0449
0450 static int set_platform_caps(struct pp_hwmgr *hwmgr,
0451 unsigned long powerplay_caps)
0452 {
0453 set_hw_cap(
0454 hwmgr,
0455 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
0456 PHM_PlatformCaps_PowerPlaySupport
0457 );
0458
0459 set_hw_cap(
0460 hwmgr,
0461 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
0462 PHM_PlatformCaps_BiosPowerSourceControl
0463 );
0464
0465 set_hw_cap(
0466 hwmgr,
0467 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
0468 PHM_PlatformCaps_EnableASPML0s
0469 );
0470
0471 set_hw_cap(
0472 hwmgr,
0473 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
0474 PHM_PlatformCaps_EnableASPML1
0475 );
0476
0477 set_hw_cap(
0478 hwmgr,
0479 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
0480 PHM_PlatformCaps_EnableBackbias
0481 );
0482
0483 set_hw_cap(
0484 hwmgr,
0485 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
0486 PHM_PlatformCaps_AutomaticDCTransition
0487 );
0488
0489 set_hw_cap(
0490 hwmgr,
0491 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
0492 PHM_PlatformCaps_GeminiPrimary
0493 );
0494
0495 set_hw_cap(
0496 hwmgr,
0497 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
0498 PHM_PlatformCaps_StepVddc
0499 );
0500
0501 set_hw_cap(
0502 hwmgr,
0503 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
0504 PHM_PlatformCaps_EnableVoltageControl
0505 );
0506
0507 set_hw_cap(
0508 hwmgr,
0509 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
0510 PHM_PlatformCaps_EnableSideportControl
0511 );
0512
0513 set_hw_cap(
0514 hwmgr,
0515 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
0516 PHM_PlatformCaps_TurnOffPll_ASPML1
0517 );
0518
0519 set_hw_cap(
0520 hwmgr,
0521 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
0522 PHM_PlatformCaps_EnableHTLinkControl
0523 );
0524
0525 set_hw_cap(
0526 hwmgr,
0527 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
0528 PHM_PlatformCaps_EnableMVDDControl
0529 );
0530
0531 set_hw_cap(
0532 hwmgr,
0533 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
0534 PHM_PlatformCaps_ControlVDDCI
0535 );
0536
0537 set_hw_cap(
0538 hwmgr,
0539 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
0540 PHM_PlatformCaps_RegulatorHot
0541 );
0542
0543 set_hw_cap(
0544 hwmgr,
0545 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
0546 PHM_PlatformCaps_BootStateOnAlert
0547 );
0548
0549 set_hw_cap(
0550 hwmgr,
0551 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
0552 PHM_PlatformCaps_DontWaitForVBlankOnAlert
0553 );
0554
0555 set_hw_cap(
0556 hwmgr,
0557 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
0558 PHM_PlatformCaps_BACO
0559 );
0560
0561 set_hw_cap(
0562 hwmgr,
0563 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
0564 PHM_PlatformCaps_NewCACVoltage
0565 );
0566
0567 set_hw_cap(
0568 hwmgr,
0569 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
0570 PHM_PlatformCaps_RevertGPIO5Polarity
0571 );
0572
0573 set_hw_cap(
0574 hwmgr,
0575 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
0576 PHM_PlatformCaps_Thermal2GPIO17
0577 );
0578
0579 set_hw_cap(
0580 hwmgr,
0581 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
0582 PHM_PlatformCaps_VRHotGPIOConfigurable
0583 );
0584
0585 set_hw_cap(
0586 hwmgr,
0587 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
0588 PHM_PlatformCaps_TempInversion
0589 );
0590
0591 set_hw_cap(
0592 hwmgr,
0593 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
0594 PHM_PlatformCaps_EVV
0595 );
0596
0597 set_hw_cap(
0598 hwmgr,
0599 0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
0600 PHM_PlatformCaps_CombinePCCWithThermalSignal
0601 );
0602
0603 set_hw_cap(
0604 hwmgr,
0605 0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
0606 PHM_PlatformCaps_LoadPostProductionFirmware
0607 );
0608
0609 set_hw_cap(
0610 hwmgr,
0611 0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
0612 PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
0613 );
0614
0615 return 0;
0616 }
0617
0618 static PP_StateClassificationFlags make_classification_flags(
0619 struct pp_hwmgr *hwmgr,
0620 USHORT classification,
0621 USHORT classification2)
0622 {
0623 PP_StateClassificationFlags result = 0;
0624
0625 if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
0626 result |= PP_StateClassificationFlag_Boot;
0627
0628 if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
0629 result |= PP_StateClassificationFlag_Thermal;
0630
0631 if (classification &
0632 ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
0633 result |= PP_StateClassificationFlag_LimitedPowerSource;
0634
0635 if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
0636 result |= PP_StateClassificationFlag_Rest;
0637
0638 if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
0639 result |= PP_StateClassificationFlag_Forced;
0640
0641 if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
0642 result |= PP_StateClassificationFlag_3DPerformance;
0643
0644
0645 if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
0646 result |= PP_StateClassificationFlag_ACOverdriveTemplate;
0647
0648 if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
0649 result |= PP_StateClassificationFlag_Uvd;
0650
0651 if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
0652 result |= PP_StateClassificationFlag_UvdHD;
0653
0654 if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
0655 result |= PP_StateClassificationFlag_UvdSD;
0656
0657 if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
0658 result |= PP_StateClassificationFlag_HD2;
0659
0660 if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
0661 result |= PP_StateClassificationFlag_ACPI;
0662
0663 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
0664 result |= PP_StateClassificationFlag_LimitedPowerSource_2;
0665
0666
0667 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
0668 result |= PP_StateClassificationFlag_ULV;
0669
0670 if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
0671 result |= PP_StateClassificationFlag_UvdMVC;
0672
0673 return result;
0674 }
0675
0676 static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
0677 struct pp_power_state *ps,
0678 uint8_t version,
0679 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
0680 unsigned long rrr_index;
0681 unsigned long tmp;
0682
0683 ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
0684 ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
0685 ps->classification.flags = make_classification_flags(hwmgr,
0686 le16_to_cpu(pnon_clock_info->usClassification),
0687 le16_to_cpu(pnon_clock_info->usClassification2));
0688
0689 ps->classification.temporary_state = false;
0690 ps->classification.to_be_deleted = false;
0691 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0692 ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
0693
0694 ps->validation.singleDisplayOnly = (0 != tmp);
0695
0696 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0697 ATOM_PPLIB_DISALLOW_ON_DC;
0698
0699 ps->validation.disallowOnDC = (0 != tmp);
0700
0701 ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0702 ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
0703 ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
0704
0705 ps->pcie.lanes = 0;
0706
0707 ps->display.disableFrameModulation = false;
0708
0709 rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0710 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
0711 ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
0712
0713 if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
0714 static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
0715 { 0, 50, 0 };
0716
0717 ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
0718 ps->display.explicitRefreshrate = look_up[rrr_index];
0719 ps->display.limitRefreshrate = true;
0720
0721 if (ps->display.explicitRefreshrate == 0)
0722 ps->display.limitRefreshrate = false;
0723 } else
0724 ps->display.limitRefreshrate = false;
0725
0726 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0727 ATOM_PPLIB_ENABLE_VARIBRIGHT;
0728
0729 ps->display.enableVariBright = (0 != tmp);
0730
0731 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0732 ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
0733
0734 ps->memory.dllOff = (0 != tmp);
0735
0736 ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0737 ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
0738
0739 ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
0740 pnon_clock_info->ucMinTemperature;
0741
0742 ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
0743 pnon_clock_info->ucMaxTemperature;
0744
0745 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0746 ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
0747
0748 ps->software.disableLoadBalancing = tmp;
0749
0750 tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
0751 ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
0752
0753 ps->software.enableSleepForTimestamps = (0 != tmp);
0754
0755 ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
0756
0757 if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
0758 ps->uvd_clocks.VCLK = le32_to_cpu(pnon_clock_info->ulVCLK);
0759 ps->uvd_clocks.DCLK = le32_to_cpu(pnon_clock_info->ulDCLK);
0760 } else {
0761 ps->uvd_clocks.VCLK = 0;
0762 ps->uvd_clocks.DCLK = 0;
0763 }
0764
0765 return 0;
0766 }
0767
0768 static ULONG size_of_entry_v2(ULONG num_dpm_levels)
0769 {
0770 return (sizeof(UCHAR) + sizeof(UCHAR) +
0771 (num_dpm_levels * sizeof(UCHAR)));
0772 }
0773
0774 static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
0775 const StateArray * pstate_arrays,
0776 ULONG entry_index)
0777 {
0778 ULONG i;
0779 const ATOM_PPLIB_STATE_V2 *pstate;
0780
0781 pstate = pstate_arrays->states;
0782 if (entry_index <= pstate_arrays->ucNumEntries) {
0783 for (i = 0; i < entry_index; i++)
0784 pstate = (ATOM_PPLIB_STATE_V2 *)(
0785 (unsigned long)pstate +
0786 size_of_entry_v2(pstate->ucNumDPMLevels));
0787 }
0788 return pstate;
0789 }
0790
0791 static const unsigned char soft_dummy_pp_table[] = {
0792 0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00,
0793 0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
0794 0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
0795 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0796 0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
0797 0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0798 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00,
0799 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0800 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0801 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00,
0802 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00,
0803 0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
0804 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00,
0805 0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
0806 0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59,
0807 0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28,
0808 0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01,
0809 0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01,
0810 0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a,
0811 0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
0812 0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c,
0813 0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01,
0814 0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e,
0815 0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70,
0816 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08,
0817 0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70,
0818 0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00,
0819 0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
0820 0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00,
0821 0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
0822 0x00
0823 };
0824
0825 static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
0826 struct pp_hwmgr *hwmgr)
0827 {
0828 const void *table_addr = hwmgr->soft_pp_table;
0829 uint8_t frev, crev;
0830 uint16_t size;
0831
0832 if (!table_addr) {
0833 if (hwmgr->chip_id == CHIP_RAVEN) {
0834 table_addr = &soft_dummy_pp_table[0];
0835 hwmgr->soft_pp_table = &soft_dummy_pp_table[0];
0836 hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table);
0837 } else {
0838 table_addr = smu_atom_get_data_table(hwmgr->adev,
0839 GetIndexIntoMasterTable(DATA, PowerPlayInfo),
0840 &size, &frev, &crev);
0841 hwmgr->soft_pp_table = table_addr;
0842 hwmgr->soft_pp_table_size = size;
0843 }
0844 }
0845
0846 return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
0847 }
0848
0849 int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
0850 uint32_t *vol_rep_time, uint32_t *bb_rep_time)
0851 {
0852 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr);
0853
0854 PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
0855 "Missing PowerPlay Table!", return -EINVAL);
0856
0857 *vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
0858 *bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
0859
0860 return 0;
0861 }
0862
0863 int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
0864 unsigned long *num_of_entries)
0865 {
0866 const StateArray *pstate_arrays;
0867 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
0868
0869 if (powerplay_table == NULL)
0870 return -1;
0871
0872 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
0873 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
0874 le16_to_cpu(powerplay_table->usStateArrayOffset));
0875
0876 *num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
0877 } else
0878 *num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
0879
0880 return 0;
0881 }
0882
0883 int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
0884 unsigned long entry_index,
0885 struct pp_power_state *ps,
0886 pp_tables_hw_clock_info_callback func)
0887 {
0888 int i;
0889 const StateArray *pstate_arrays;
0890 const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
0891 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
0892 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
0893 int result = 0;
0894 int res = 0;
0895
0896 const ClockInfoArray *pclock_arrays;
0897
0898 const NonClockInfoArray *pnon_clock_arrays;
0899
0900 const ATOM_PPLIB_STATE *pstate_entry;
0901
0902 if (powerplay_table == NULL)
0903 return -1;
0904
0905 ps->classification.bios_index = entry_index;
0906
0907 if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
0908 pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
0909 le16_to_cpu(powerplay_table->usStateArrayOffset));
0910
0911 if (entry_index > pstate_arrays->ucNumEntries)
0912 return -1;
0913
0914 pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
0915 pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
0916 le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
0917
0918 pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
0919 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
0920
0921 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
0922 (pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
0923
0924 result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
0925
0926 for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
0927 const void *pclock_info = (const void *)(
0928 (unsigned long)(pclock_arrays->clockInfo) +
0929 (pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
0930 res = func(hwmgr, &ps->hardware, i, pclock_info);
0931 if ((0 == result) && (0 != res))
0932 result = res;
0933 }
0934 } else {
0935 if (entry_index > powerplay_table->ucNumStates)
0936 return -1;
0937
0938 pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table +
0939 le16_to_cpu(powerplay_table->usStateArrayOffset) +
0940 entry_index * powerplay_table->ucStateEntrySize);
0941
0942 pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
0943 le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
0944 pstate_entry->ucNonClockStateIndex *
0945 powerplay_table->ucNonClockSize);
0946
0947 result = init_non_clock_fields(hwmgr, ps,
0948 powerplay_table->ucNonClockSize,
0949 pnon_clock_info);
0950
0951 for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
0952 const void *pclock_info = (const void *)((unsigned long)powerplay_table +
0953 le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
0954 pstate_entry->ucClockStateIndices[i] *
0955 powerplay_table->ucClockInfoSize);
0956
0957 int res = func(hwmgr, &ps->hardware, i, pclock_info);
0958
0959 if ((0 == result) && (0 != res))
0960 result = res;
0961 }
0962 }
0963
0964 if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
0965 if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
0966 result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
0967 }
0968
0969 return result;
0970 }
0971
0972 static int init_powerplay_tables(
0973 struct pp_hwmgr *hwmgr,
0974 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
0975 )
0976 {
0977 return 0;
0978 }
0979
0980
0981 static int init_thermal_controller(
0982 struct pp_hwmgr *hwmgr,
0983 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
0984 {
0985 struct amdgpu_device *adev = hwmgr->adev;
0986
0987 hwmgr->thermal_controller.ucType =
0988 powerplay_table->sThermalController.ucType;
0989 hwmgr->thermal_controller.ucI2cLine =
0990 powerplay_table->sThermalController.ucI2cLine;
0991 hwmgr->thermal_controller.ucI2cAddress =
0992 powerplay_table->sThermalController.ucI2cAddress;
0993
0994 hwmgr->thermal_controller.fanInfo.bNoFan =
0995 (0 != (powerplay_table->sThermalController.ucFanParameters &
0996 ATOM_PP_FANPARAMETERS_NOFAN));
0997
0998 hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
0999 powerplay_table->sThermalController.ucFanParameters &
1000 ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
1001
1002 hwmgr->thermal_controller.fanInfo.ulMinRPM
1003 = powerplay_table->sThermalController.ucFanMinRPM * 100UL;
1004 hwmgr->thermal_controller.fanInfo.ulMaxRPM
1005 = powerplay_table->sThermalController.ucFanMaxRPM * 100UL;
1006
1007 set_hw_cap(hwmgr,
1008 ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
1009 PHM_PlatformCaps_ThermalController);
1010
1011 if (powerplay_table->usTableSize >= sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
1012 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
1013 (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1014
1015 if (0 == le16_to_cpu(powerplay_table3->usFanTableOffset)) {
1016 hwmgr->thermal_controller.use_hw_fan_control = 1;
1017 return 0;
1018 } else {
1019 const ATOM_PPLIB_FANTABLE *fan_table =
1020 (const ATOM_PPLIB_FANTABLE *)(((unsigned long)powerplay_table) +
1021 le16_to_cpu(powerplay_table3->usFanTableOffset));
1022
1023 if (1 <= fan_table->ucFanTableFormat) {
1024 hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst =
1025 fan_table->ucTHyst;
1026 hwmgr->thermal_controller.advanceFanControlParameters.usTMin =
1027 le16_to_cpu(fan_table->usTMin);
1028 hwmgr->thermal_controller.advanceFanControlParameters.usTMed =
1029 le16_to_cpu(fan_table->usTMed);
1030 hwmgr->thermal_controller.advanceFanControlParameters.usTHigh =
1031 le16_to_cpu(fan_table->usTHigh);
1032 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin =
1033 le16_to_cpu(fan_table->usPWMMin);
1034 hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed =
1035 le16_to_cpu(fan_table->usPWMMed);
1036 hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh =
1037 le16_to_cpu(fan_table->usPWMHigh);
1038 hwmgr->thermal_controller.advanceFanControlParameters.usTMax = 10900;
1039 hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay = 100000;
1040
1041 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1042 PHM_PlatformCaps_MicrocodeFanControl);
1043 }
1044
1045 if (2 <= fan_table->ucFanTableFormat) {
1046 const ATOM_PPLIB_FANTABLE2 *fan_table2 =
1047 (const ATOM_PPLIB_FANTABLE2 *)(((unsigned long)powerplay_table) +
1048 le16_to_cpu(powerplay_table3->usFanTableOffset));
1049 hwmgr->thermal_controller.advanceFanControlParameters.usTMax =
1050 le16_to_cpu(fan_table2->usTMax);
1051 }
1052
1053 if (3 <= fan_table->ucFanTableFormat) {
1054 const ATOM_PPLIB_FANTABLE3 *fan_table3 =
1055 (const ATOM_PPLIB_FANTABLE3 *) (((unsigned long)powerplay_table) +
1056 le16_to_cpu(powerplay_table3->usFanTableOffset));
1057
1058 hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode =
1059 fan_table3->ucFanControlMode;
1060
1061 if ((3 == fan_table->ucFanTableFormat) &&
1062 (0x67B1 == adev->pdev->device))
1063 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM =
1064 47;
1065 else
1066 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM =
1067 le16_to_cpu(fan_table3->usFanPWMMax);
1068
1069 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity =
1070 4836;
1071 hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
1072 le16_to_cpu(fan_table3->usFanOutputSensitivity);
1073 }
1074
1075 if (6 <= fan_table->ucFanTableFormat) {
1076 const ATOM_PPLIB_FANTABLE4 *fan_table4 =
1077 (const ATOM_PPLIB_FANTABLE4 *)(((unsigned long)powerplay_table) +
1078 le16_to_cpu(powerplay_table3->usFanTableOffset));
1079
1080 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1081 PHM_PlatformCaps_FanSpeedInTableIsRPM);
1082
1083 hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM =
1084 le16_to_cpu(fan_table4->usFanRPMMax);
1085 }
1086
1087 if (7 <= fan_table->ucFanTableFormat) {
1088 const ATOM_PPLIB_FANTABLE5 *fan_table5 =
1089 (const ATOM_PPLIB_FANTABLE5 *)(((unsigned long)powerplay_table) +
1090 le16_to_cpu(powerplay_table3->usFanTableOffset));
1091
1092 if (0x67A2 == adev->pdev->device ||
1093 0x67A9 == adev->pdev->device ||
1094 0x67B9 == adev->pdev->device) {
1095 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1096 PHM_PlatformCaps_GeminiRegulatorFanControlSupport);
1097 hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentLow =
1098 le16_to_cpu(fan_table5->usFanCurrentLow);
1099 hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentHigh =
1100 le16_to_cpu(fan_table5->usFanCurrentHigh);
1101 hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMLow =
1102 le16_to_cpu(fan_table5->usFanRPMLow);
1103 hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMHigh =
1104 le16_to_cpu(fan_table5->usFanRPMHigh);
1105 }
1106 }
1107 }
1108 }
1109
1110 return 0;
1111 }
1112
1113 static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
1114 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1115 const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
1116 {
1117 hwmgr->platform_descriptor.overdriveLimit.engineClock =
1118 le32_to_cpu(fw_info->ulASICMaxEngineClock);
1119
1120 hwmgr->platform_descriptor.overdriveLimit.memoryClock =
1121 le32_to_cpu(fw_info->ulASICMaxMemoryClock);
1122
1123 hwmgr->platform_descriptor.maxOverdriveVDDC =
1124 le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
1125
1126 hwmgr->platform_descriptor.minOverdriveVDDC =
1127 le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1128
1129 hwmgr->platform_descriptor.maxOverdriveVDDC =
1130 le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1131
1132 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1133 return 0;
1134 }
1135
1136 static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
1137 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1138 const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
1139 {
1140 const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
1141 const ATOM_PPLIB_EXTENDEDHEADER *header;
1142
1143 if (le16_to_cpu(powerplay_table->usTableSize) <
1144 sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
1145 return 0;
1146
1147 powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1148
1149 if (0 == powerplay_table3->usExtendendedHeaderOffset)
1150 return 0;
1151
1152 header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
1153 le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
1154
1155 hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
1156 hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
1157
1158
1159 hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1160 hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1161 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1162
1163 return 0;
1164 }
1165
1166 static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
1167 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1168 {
1169 int result = 0;
1170 uint8_t frev, crev;
1171 uint16_t size;
1172
1173 const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
1174
1175 hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
1176 hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
1177 hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1178 hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1179 hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1180
1181 if (hwmgr->chip_id == CHIP_RAVEN)
1182 return 0;
1183
1184
1185 fw_info = smu_atom_get_data_table(hwmgr->adev,
1186 GetIndexIntoMasterTable(DATA, FirmwareInfo),
1187 &size, &frev, &crev);
1188
1189 if ((fw_info->ucTableFormatRevision == 1)
1190 && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V1_4)))
1191 result = init_overdrive_limits_V1_4(hwmgr,
1192 powerplay_table,
1193 (const ATOM_FIRMWARE_INFO_V1_4 *)fw_info);
1194
1195 else if ((fw_info->ucTableFormatRevision == 2)
1196 && (le16_to_cpu(fw_info->usStructureSize) >= sizeof(ATOM_FIRMWARE_INFO_V2_1)))
1197 result = init_overdrive_limits_V2_1(hwmgr,
1198 powerplay_table,
1199 (const ATOM_FIRMWARE_INFO_V2_1 *)fw_info);
1200
1201 return result;
1202 }
1203
1204 static int get_uvd_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1205 struct phm_uvd_clock_voltage_dependency_table **ptable,
1206 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *table,
1207 const UVDClockInfoArray *array)
1208 {
1209 unsigned long i;
1210 struct phm_uvd_clock_voltage_dependency_table *uvd_table;
1211
1212 uvd_table = kzalloc(struct_size(uvd_table, entries, table->numEntries),
1213 GFP_KERNEL);
1214 if (!uvd_table)
1215 return -ENOMEM;
1216
1217 uvd_table->count = table->numEntries;
1218
1219 for (i = 0; i < table->numEntries; i++) {
1220 const UVDClockInfo *entry =
1221 &array->entries[table->entries[i].ucUVDClockInfoIndex];
1222 uvd_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1223 uvd_table->entries[i].vclk = ((unsigned long)entry->ucVClkHigh << 16)
1224 | le16_to_cpu(entry->usVClkLow);
1225 uvd_table->entries[i].dclk = ((unsigned long)entry->ucDClkHigh << 16)
1226 | le16_to_cpu(entry->usDClkLow);
1227 }
1228
1229 *ptable = uvd_table;
1230
1231 return 0;
1232 }
1233
1234 static int get_vce_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1235 struct phm_vce_clock_voltage_dependency_table **ptable,
1236 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table,
1237 const VCEClockInfoArray *array)
1238 {
1239 unsigned long i;
1240 struct phm_vce_clock_voltage_dependency_table *vce_table = NULL;
1241
1242 vce_table = kzalloc(struct_size(vce_table, entries, table->numEntries),
1243 GFP_KERNEL);
1244 if (!vce_table)
1245 return -ENOMEM;
1246
1247 vce_table->count = table->numEntries;
1248 for (i = 0; i < table->numEntries; i++) {
1249 const VCEClockInfo *entry = &array->entries[table->entries[i].ucVCEClockInfoIndex];
1250
1251 vce_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1252 vce_table->entries[i].evclk = ((unsigned long)entry->ucEVClkHigh << 16)
1253 | le16_to_cpu(entry->usEVClkLow);
1254 vce_table->entries[i].ecclk = ((unsigned long)entry->ucECClkHigh << 16)
1255 | le16_to_cpu(entry->usECClkLow);
1256 }
1257
1258 *ptable = vce_table;
1259
1260 return 0;
1261 }
1262
1263 static int get_samu_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1264 struct phm_samu_clock_voltage_dependency_table **ptable,
1265 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *table)
1266 {
1267 unsigned long i;
1268 struct phm_samu_clock_voltage_dependency_table *samu_table;
1269
1270 samu_table = kzalloc(struct_size(samu_table, entries, table->numEntries),
1271 GFP_KERNEL);
1272 if (!samu_table)
1273 return -ENOMEM;
1274
1275 samu_table->count = table->numEntries;
1276
1277 for (i = 0; i < table->numEntries; i++) {
1278 samu_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1279 samu_table->entries[i].samclk = ((unsigned long)table->entries[i].ucSAMClockHigh << 16)
1280 | le16_to_cpu(table->entries[i].usSAMClockLow);
1281 }
1282
1283 *ptable = samu_table;
1284
1285 return 0;
1286 }
1287
1288 static int get_acp_clock_voltage_limit_table(struct pp_hwmgr *hwmgr,
1289 struct phm_acp_clock_voltage_dependency_table **ptable,
1290 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *table)
1291 {
1292 unsigned long i;
1293 struct phm_acp_clock_voltage_dependency_table *acp_table;
1294
1295 acp_table = kzalloc(struct_size(acp_table, entries, table->numEntries),
1296 GFP_KERNEL);
1297 if (!acp_table)
1298 return -ENOMEM;
1299
1300 acp_table->count = (unsigned long)table->numEntries;
1301
1302 for (i = 0; i < table->numEntries; i++) {
1303 acp_table->entries[i].v = (unsigned long)le16_to_cpu(table->entries[i].usVoltage);
1304 acp_table->entries[i].acpclk = ((unsigned long)table->entries[i].ucACPClockHigh << 16)
1305 | le16_to_cpu(table->entries[i].usACPClockLow);
1306 }
1307
1308 *ptable = acp_table;
1309
1310 return 0;
1311 }
1312
1313 static int init_clock_voltage_dependency(struct pp_hwmgr *hwmgr,
1314 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1315 {
1316 ATOM_PPLIB_Clock_Voltage_Dependency_Table *table;
1317 ATOM_PPLIB_Clock_Voltage_Limit_Table *limit_table;
1318 int result = 0;
1319
1320 uint16_t vce_clock_info_array_offset;
1321 uint16_t uvd_clock_info_array_offset;
1322 uint16_t table_offset;
1323
1324 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1325 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1326 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1327 hwmgr->dyn_state.vddc_dep_on_dal_pwrl = NULL;
1328 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1329 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1330 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1331 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1332 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1333 hwmgr->dyn_state.ppm_parameter_table = NULL;
1334 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1335
1336 vce_clock_info_array_offset = get_vce_clock_info_array_offset(
1337 hwmgr, powerplay_table);
1338 table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr,
1339 powerplay_table);
1340 if (vce_clock_info_array_offset > 0 && table_offset > 0) {
1341 const VCEClockInfoArray *array = (const VCEClockInfoArray *)
1342 (((unsigned long) powerplay_table) +
1343 vce_clock_info_array_offset);
1344 const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *table =
1345 (const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
1346 (((unsigned long) powerplay_table) + table_offset);
1347 result = get_vce_clock_voltage_limit_table(hwmgr,
1348 &hwmgr->dyn_state.vce_clock_voltage_dependency_table,
1349 table, array);
1350 }
1351
1352 uvd_clock_info_array_offset = get_uvd_clock_info_array_offset(hwmgr, powerplay_table);
1353 table_offset = get_uvd_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
1354
1355 if (uvd_clock_info_array_offset > 0 && table_offset > 0) {
1356 const UVDClockInfoArray *array = (const UVDClockInfoArray *)
1357 (((unsigned long) powerplay_table) +
1358 uvd_clock_info_array_offset);
1359 const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *ptable =
1360 (const ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
1361 (((unsigned long) powerplay_table) + table_offset);
1362 result = get_uvd_clock_voltage_limit_table(hwmgr,
1363 &hwmgr->dyn_state.uvd_clock_voltage_dependency_table, ptable, array);
1364 }
1365
1366 table_offset = get_samu_clock_voltage_limit_table_offset(hwmgr,
1367 powerplay_table);
1368
1369 if (table_offset > 0) {
1370 const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *ptable =
1371 (const ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
1372 (((unsigned long) powerplay_table) + table_offset);
1373 result = get_samu_clock_voltage_limit_table(hwmgr,
1374 &hwmgr->dyn_state.samu_clock_voltage_dependency_table, ptable);
1375 }
1376
1377 table_offset = get_acp_clock_voltage_limit_table_offset(hwmgr,
1378 powerplay_table);
1379
1380 if (table_offset > 0) {
1381 const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *ptable =
1382 (const ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
1383 (((unsigned long) powerplay_table) + table_offset);
1384 result = get_acp_clock_voltage_limit_table(hwmgr,
1385 &hwmgr->dyn_state.acp_clock_voltage_dependency_table, ptable);
1386 }
1387
1388 table_offset = get_cacp_tdp_table_offset(hwmgr, powerplay_table);
1389 if (table_offset > 0) {
1390 UCHAR rev_id = *(UCHAR *)(((unsigned long)powerplay_table) + table_offset);
1391
1392 if (rev_id > 0) {
1393 const ATOM_PPLIB_POWERTUNE_Table_V1 *tune_table =
1394 (const ATOM_PPLIB_POWERTUNE_Table_V1 *)
1395 (((unsigned long) powerplay_table) + table_offset);
1396 result = get_cac_tdp_table(hwmgr, &hwmgr->dyn_state.cac_dtp_table,
1397 &tune_table->power_tune_table,
1398 le16_to_cpu(tune_table->usMaximumPowerDeliveryLimit));
1399 hwmgr->dyn_state.cac_dtp_table->usDefaultTargetOperatingTemp =
1400 le16_to_cpu(tune_table->usTjMax);
1401 } else {
1402 const ATOM_PPLIB_POWERTUNE_Table *tune_table =
1403 (const ATOM_PPLIB_POWERTUNE_Table *)
1404 (((unsigned long) powerplay_table) + table_offset);
1405 result = get_cac_tdp_table(hwmgr,
1406 &hwmgr->dyn_state.cac_dtp_table,
1407 &tune_table->power_tune_table, 255);
1408 }
1409 }
1410
1411 if (le16_to_cpu(powerplay_table->usTableSize) >=
1412 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1413 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1414 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1415 if (0 != powerplay_table4->usVddcDependencyOnSCLKOffset) {
1416 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1417 (((unsigned long) powerplay_table4) +
1418 le16_to_cpu(powerplay_table4->usVddcDependencyOnSCLKOffset));
1419 result = get_clock_voltage_dependency_table(hwmgr,
1420 &hwmgr->dyn_state.vddc_dependency_on_sclk, table);
1421 }
1422
1423 if (result == 0 && (0 != powerplay_table4->usVddciDependencyOnMCLKOffset)) {
1424 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1425 (((unsigned long) powerplay_table4) +
1426 le16_to_cpu(powerplay_table4->usVddciDependencyOnMCLKOffset));
1427 result = get_clock_voltage_dependency_table(hwmgr,
1428 &hwmgr->dyn_state.vddci_dependency_on_mclk, table);
1429 }
1430
1431 if (result == 0 && (0 != powerplay_table4->usVddcDependencyOnMCLKOffset)) {
1432 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1433 (((unsigned long) powerplay_table4) +
1434 le16_to_cpu(powerplay_table4->usVddcDependencyOnMCLKOffset));
1435 result = get_clock_voltage_dependency_table(hwmgr,
1436 &hwmgr->dyn_state.vddc_dependency_on_mclk, table);
1437 }
1438
1439 if (result == 0 && (0 != powerplay_table4->usMaxClockVoltageOnDCOffset)) {
1440 limit_table = (ATOM_PPLIB_Clock_Voltage_Limit_Table *)
1441 (((unsigned long) powerplay_table4) +
1442 le16_to_cpu(powerplay_table4->usMaxClockVoltageOnDCOffset));
1443 result = get_clock_voltage_limit(hwmgr,
1444 &hwmgr->dyn_state.max_clock_voltage_on_dc, limit_table);
1445 }
1446
1447 if (result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_mclk) &&
1448 (0 != hwmgr->dyn_state.vddc_dependency_on_mclk->count))
1449 result = get_valid_clk(hwmgr, &hwmgr->dyn_state.valid_mclk_values,
1450 hwmgr->dyn_state.vddc_dependency_on_mclk);
1451
1452 if(result == 0 && (NULL != hwmgr->dyn_state.vddc_dependency_on_sclk) &&
1453 (0 != hwmgr->dyn_state.vddc_dependency_on_sclk->count))
1454 result = get_valid_clk(hwmgr,
1455 &hwmgr->dyn_state.valid_sclk_values,
1456 hwmgr->dyn_state.vddc_dependency_on_sclk);
1457
1458 if (result == 0 && (0 != powerplay_table4->usMvddDependencyOnMCLKOffset)) {
1459 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1460 (((unsigned long) powerplay_table4) +
1461 le16_to_cpu(powerplay_table4->usMvddDependencyOnMCLKOffset));
1462 result = get_clock_voltage_dependency_table(hwmgr,
1463 &hwmgr->dyn_state.mvdd_dependency_on_mclk, table);
1464 }
1465 }
1466
1467 table_offset = get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(hwmgr,
1468 powerplay_table);
1469
1470 if (table_offset > 0) {
1471 table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
1472 (((unsigned long) powerplay_table) + table_offset);
1473 result = get_clock_voltage_dependency_table(hwmgr,
1474 &hwmgr->dyn_state.vdd_gfx_dependency_on_sclk, table);
1475 }
1476
1477 return result;
1478 }
1479
1480 static int get_cac_leakage_table(struct pp_hwmgr *hwmgr,
1481 struct phm_cac_leakage_table **ptable,
1482 const ATOM_PPLIB_CAC_Leakage_Table *table)
1483 {
1484 struct phm_cac_leakage_table *cac_leakage_table;
1485 unsigned long i;
1486
1487 if (!hwmgr || !table || !ptable)
1488 return -EINVAL;
1489
1490 cac_leakage_table = kzalloc(struct_size(cac_leakage_table, entries, table->ucNumEntries),
1491 GFP_KERNEL);
1492 if (!cac_leakage_table)
1493 return -ENOMEM;
1494
1495 cac_leakage_table->count = (ULONG)table->ucNumEntries;
1496
1497 for (i = 0; i < cac_leakage_table->count; i++) {
1498 if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
1499 PHM_PlatformCaps_EVV)) {
1500 cac_leakage_table->entries[i].Vddc1 = le16_to_cpu(table->entries[i].usVddc1);
1501 cac_leakage_table->entries[i].Vddc2 = le16_to_cpu(table->entries[i].usVddc2);
1502 cac_leakage_table->entries[i].Vddc3 = le16_to_cpu(table->entries[i].usVddc3);
1503 } else {
1504 cac_leakage_table->entries[i].Vddc = le16_to_cpu(table->entries[i].usVddc);
1505 cac_leakage_table->entries[i].Leakage = le32_to_cpu(table->entries[i].ulLeakageValue);
1506 }
1507 }
1508
1509 *ptable = cac_leakage_table;
1510
1511 return 0;
1512 }
1513
1514 static int get_platform_power_management_table(struct pp_hwmgr *hwmgr,
1515 ATOM_PPLIB_PPM_Table *atom_ppm_table)
1516 {
1517 struct phm_ppm_table *ptr = kzalloc(sizeof(struct phm_ppm_table), GFP_KERNEL);
1518
1519 if (NULL == ptr)
1520 return -ENOMEM;
1521
1522 ptr->ppm_design = atom_ppm_table->ucPpmDesign;
1523 ptr->cpu_core_number = le16_to_cpu(atom_ppm_table->usCpuCoreNumber);
1524 ptr->platform_tdp = le32_to_cpu(atom_ppm_table->ulPlatformTDP);
1525 ptr->small_ac_platform_tdp = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDP);
1526 ptr->platform_tdc = le32_to_cpu(atom_ppm_table->ulPlatformTDC);
1527 ptr->small_ac_platform_tdc = le32_to_cpu(atom_ppm_table->ulSmallACPlatformTDC);
1528 ptr->apu_tdp = le32_to_cpu(atom_ppm_table->ulApuTDP);
1529 ptr->dgpu_tdp = le32_to_cpu(atom_ppm_table->ulDGpuTDP);
1530 ptr->dgpu_ulv_power = le32_to_cpu(atom_ppm_table->ulDGpuUlvPower);
1531 ptr->tj_max = le32_to_cpu(atom_ppm_table->ulTjmax);
1532 hwmgr->dyn_state.ppm_parameter_table = ptr;
1533
1534 return 0;
1535 }
1536
1537 static int init_dpm2_parameters(struct pp_hwmgr *hwmgr,
1538 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1539 {
1540 int result = 0;
1541
1542 if (le16_to_cpu(powerplay_table->usTableSize) >=
1543 sizeof(ATOM_PPLIB_POWERPLAYTABLE5)) {
1544 const ATOM_PPLIB_POWERPLAYTABLE5 *ptable5 =
1545 (const ATOM_PPLIB_POWERPLAYTABLE5 *)powerplay_table;
1546 const ATOM_PPLIB_POWERPLAYTABLE4 *ptable4 =
1547 (const ATOM_PPLIB_POWERPLAYTABLE4 *)
1548 (&ptable5->basicTable4);
1549 const ATOM_PPLIB_POWERPLAYTABLE3 *ptable3 =
1550 (const ATOM_PPLIB_POWERPLAYTABLE3 *)
1551 (&ptable4->basicTable3);
1552 const ATOM_PPLIB_EXTENDEDHEADER *extended_header;
1553 uint16_t table_offset;
1554 ATOM_PPLIB_PPM_Table *atom_ppm_table;
1555
1556 hwmgr->platform_descriptor.TDPLimit = le32_to_cpu(ptable5->ulTDPLimit);
1557 hwmgr->platform_descriptor.nearTDPLimit = le32_to_cpu(ptable5->ulNearTDPLimit);
1558
1559 hwmgr->platform_descriptor.TDPODLimit = le16_to_cpu(ptable5->usTDPODLimit);
1560 hwmgr->platform_descriptor.TDPAdjustment = 0;
1561
1562 hwmgr->platform_descriptor.VidAdjustment = 0;
1563 hwmgr->platform_descriptor.VidAdjustmentPolarity = 0;
1564 hwmgr->platform_descriptor.VidMinLimit = 0;
1565 hwmgr->platform_descriptor.VidMaxLimit = 1500000;
1566 hwmgr->platform_descriptor.VidStep = 6250;
1567
1568 hwmgr->platform_descriptor.nearTDPLimitAdjusted = le32_to_cpu(ptable5->ulNearTDPLimit);
1569
1570 if (hwmgr->platform_descriptor.TDPODLimit != 0)
1571 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1572 PHM_PlatformCaps_PowerControl);
1573
1574 hwmgr->platform_descriptor.SQRampingThreshold = le32_to_cpu(ptable5->ulSQRampingThreshold);
1575
1576 hwmgr->platform_descriptor.CACLeakage = le32_to_cpu(ptable5->ulCACLeakage);
1577
1578 hwmgr->dyn_state.cac_leakage_table = NULL;
1579
1580 if (0 != ptable5->usCACLeakageTableOffset) {
1581 const ATOM_PPLIB_CAC_Leakage_Table *pCAC_leakage_table =
1582 (ATOM_PPLIB_CAC_Leakage_Table *)(((unsigned long)ptable5) +
1583 le16_to_cpu(ptable5->usCACLeakageTableOffset));
1584 result = get_cac_leakage_table(hwmgr,
1585 &hwmgr->dyn_state.cac_leakage_table, pCAC_leakage_table);
1586 }
1587
1588 hwmgr->platform_descriptor.LoadLineSlope = le16_to_cpu(ptable5->usLoadLineSlope);
1589
1590 hwmgr->dyn_state.ppm_parameter_table = NULL;
1591
1592 if (0 != ptable3->usExtendendedHeaderOffset) {
1593 extended_header = (const ATOM_PPLIB_EXTENDEDHEADER *)
1594 (((unsigned long)powerplay_table) +
1595 le16_to_cpu(ptable3->usExtendendedHeaderOffset));
1596 if ((extended_header->usPPMTableOffset > 0) &&
1597 le16_to_cpu(extended_header->usSize) >=
1598 SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) {
1599 table_offset = le16_to_cpu(extended_header->usPPMTableOffset);
1600 atom_ppm_table = (ATOM_PPLIB_PPM_Table *)
1601 (((unsigned long)powerplay_table) + table_offset);
1602 if (0 == get_platform_power_management_table(hwmgr, atom_ppm_table))
1603 phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1604 PHM_PlatformCaps_EnablePlatformPowerManagement);
1605 }
1606 }
1607 }
1608 return result;
1609 }
1610
1611 static int init_phase_shedding_table(struct pp_hwmgr *hwmgr,
1612 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1613 {
1614 if (le16_to_cpu(powerplay_table->usTableSize) >=
1615 sizeof(ATOM_PPLIB_POWERPLAYTABLE4)) {
1616 const ATOM_PPLIB_POWERPLAYTABLE4 *powerplay_table4 =
1617 (const ATOM_PPLIB_POWERPLAYTABLE4 *)powerplay_table;
1618
1619 if (0 != powerplay_table4->usVddcPhaseShedLimitsTableOffset) {
1620 const ATOM_PPLIB_PhaseSheddingLimits_Table *ptable =
1621 (ATOM_PPLIB_PhaseSheddingLimits_Table *)
1622 (((unsigned long)powerplay_table4) +
1623 le16_to_cpu(powerplay_table4->usVddcPhaseShedLimitsTableOffset));
1624 struct phm_phase_shedding_limits_table *table;
1625 unsigned long i;
1626
1627
1628 table = kzalloc(struct_size(table, entries, ptable->ucNumEntries),
1629 GFP_KERNEL);
1630 if (!table)
1631 return -ENOMEM;
1632
1633 table->count = (unsigned long)ptable->ucNumEntries;
1634
1635 for (i = 0; i < table->count; i++) {
1636 table->entries[i].Voltage = (unsigned long)le16_to_cpu(ptable->entries[i].usVoltage);
1637 table->entries[i].Sclk = ((unsigned long)ptable->entries[i].ucSclkHigh << 16)
1638 | le16_to_cpu(ptable->entries[i].usSclkLow);
1639 table->entries[i].Mclk = ((unsigned long)ptable->entries[i].ucMclkHigh << 16)
1640 | le16_to_cpu(ptable->entries[i].usMclkLow);
1641 }
1642 hwmgr->dyn_state.vddc_phase_shed_limits_table = table;
1643 }
1644 }
1645
1646 return 0;
1647 }
1648
1649 static int get_number_of_vce_state_table_entries(
1650 struct pp_hwmgr *hwmgr)
1651 {
1652 const ATOM_PPLIB_POWERPLAYTABLE *table =
1653 get_powerplay_table(hwmgr);
1654 const ATOM_PPLIB_VCE_State_Table *vce_table =
1655 get_vce_state_table(hwmgr, table);
1656
1657 if (vce_table)
1658 return vce_table->numEntries;
1659
1660 return 0;
1661 }
1662
1663 static int get_vce_state_table_entry(struct pp_hwmgr *hwmgr,
1664 unsigned long i,
1665 struct amd_vce_state *vce_state,
1666 void **clock_info,
1667 unsigned long *flag)
1668 {
1669 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
1670
1671 const ATOM_PPLIB_VCE_State_Table *vce_state_table = get_vce_state_table(hwmgr, powerplay_table);
1672
1673 unsigned short vce_clock_info_array_offset = get_vce_clock_info_array_offset(hwmgr, powerplay_table);
1674
1675 const VCEClockInfoArray *vce_clock_info_array = (const VCEClockInfoArray *)(((unsigned long) powerplay_table) + vce_clock_info_array_offset);
1676
1677 const ClockInfoArray *clock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
1678 le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
1679
1680 const ATOM_PPLIB_VCE_State_Record *record = &vce_state_table->entries[i];
1681
1682 const VCEClockInfo *vce_clock_info = &vce_clock_info_array->entries[record->ucVCEClockInfoIndex];
1683
1684 unsigned long clockInfoIndex = record->ucClockInfoIndex & 0x3F;
1685
1686 *flag = (record->ucClockInfoIndex >> NUM_BITS_CLOCK_INFO_ARRAY_INDEX);
1687
1688 vce_state->evclk = ((uint32_t)vce_clock_info->ucEVClkHigh << 16) | le16_to_cpu(vce_clock_info->usEVClkLow);
1689 vce_state->ecclk = ((uint32_t)vce_clock_info->ucECClkHigh << 16) | le16_to_cpu(vce_clock_info->usECClkLow);
1690
1691 *clock_info = (void *)((unsigned long)(clock_arrays->clockInfo) + (clockInfoIndex * clock_arrays->ucEntrySize));
1692
1693 return 0;
1694 }
1695
1696
1697 static int pp_tables_initialize(struct pp_hwmgr *hwmgr)
1698 {
1699 int result;
1700 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table;
1701
1702 if (hwmgr->chip_id == CHIP_RAVEN)
1703 return 0;
1704
1705 hwmgr->need_pp_table_upload = true;
1706
1707 powerplay_table = get_powerplay_table(hwmgr);
1708
1709 result = init_powerplay_tables(hwmgr, powerplay_table);
1710
1711 PP_ASSERT_WITH_CODE((result == 0),
1712 "init_powerplay_tables failed", return result);
1713
1714 result = set_platform_caps(hwmgr,
1715 le32_to_cpu(powerplay_table->ulPlatformCaps));
1716
1717 PP_ASSERT_WITH_CODE((result == 0),
1718 "set_platform_caps failed", return result);
1719
1720 result = init_thermal_controller(hwmgr, powerplay_table);
1721
1722 PP_ASSERT_WITH_CODE((result == 0),
1723 "init_thermal_controller failed", return result);
1724
1725 result = init_overdrive_limits(hwmgr, powerplay_table);
1726
1727 PP_ASSERT_WITH_CODE((result == 0),
1728 "init_overdrive_limits failed", return result);
1729
1730 result = init_clock_voltage_dependency(hwmgr,
1731 powerplay_table);
1732
1733 PP_ASSERT_WITH_CODE((result == 0),
1734 "init_clock_voltage_dependency failed", return result);
1735
1736 result = init_dpm2_parameters(hwmgr, powerplay_table);
1737
1738 PP_ASSERT_WITH_CODE((result == 0),
1739 "init_dpm2_parameters failed", return result);
1740
1741 result = init_phase_shedding_table(hwmgr, powerplay_table);
1742
1743 PP_ASSERT_WITH_CODE((result == 0),
1744 "init_phase_shedding_table failed", return result);
1745
1746 return result;
1747 }
1748
1749 static int pp_tables_uninitialize(struct pp_hwmgr *hwmgr)
1750 {
1751 if (hwmgr->chip_id == CHIP_RAVEN)
1752 return 0;
1753
1754 kfree(hwmgr->dyn_state.vddc_dependency_on_sclk);
1755 hwmgr->dyn_state.vddc_dependency_on_sclk = NULL;
1756
1757 kfree(hwmgr->dyn_state.vddci_dependency_on_mclk);
1758 hwmgr->dyn_state.vddci_dependency_on_mclk = NULL;
1759
1760 kfree(hwmgr->dyn_state.vddc_dependency_on_mclk);
1761 hwmgr->dyn_state.vddc_dependency_on_mclk = NULL;
1762
1763 kfree(hwmgr->dyn_state.mvdd_dependency_on_mclk);
1764 hwmgr->dyn_state.mvdd_dependency_on_mclk = NULL;
1765
1766 kfree(hwmgr->dyn_state.valid_mclk_values);
1767 hwmgr->dyn_state.valid_mclk_values = NULL;
1768
1769 kfree(hwmgr->dyn_state.valid_sclk_values);
1770 hwmgr->dyn_state.valid_sclk_values = NULL;
1771
1772 kfree(hwmgr->dyn_state.cac_leakage_table);
1773 hwmgr->dyn_state.cac_leakage_table = NULL;
1774
1775 kfree(hwmgr->dyn_state.vddc_phase_shed_limits_table);
1776 hwmgr->dyn_state.vddc_phase_shed_limits_table = NULL;
1777
1778 kfree(hwmgr->dyn_state.vce_clock_voltage_dependency_table);
1779 hwmgr->dyn_state.vce_clock_voltage_dependency_table = NULL;
1780
1781 kfree(hwmgr->dyn_state.uvd_clock_voltage_dependency_table);
1782 hwmgr->dyn_state.uvd_clock_voltage_dependency_table = NULL;
1783
1784 kfree(hwmgr->dyn_state.samu_clock_voltage_dependency_table);
1785 hwmgr->dyn_state.samu_clock_voltage_dependency_table = NULL;
1786
1787 kfree(hwmgr->dyn_state.acp_clock_voltage_dependency_table);
1788 hwmgr->dyn_state.acp_clock_voltage_dependency_table = NULL;
1789
1790 kfree(hwmgr->dyn_state.cac_dtp_table);
1791 hwmgr->dyn_state.cac_dtp_table = NULL;
1792
1793 kfree(hwmgr->dyn_state.ppm_parameter_table);
1794 hwmgr->dyn_state.ppm_parameter_table = NULL;
1795
1796 kfree(hwmgr->dyn_state.vdd_gfx_dependency_on_sclk);
1797 hwmgr->dyn_state.vdd_gfx_dependency_on_sclk = NULL;
1798
1799 return 0;
1800 }
1801
1802 const struct pp_table_func pptable_funcs = {
1803 .pptable_init = pp_tables_initialize,
1804 .pptable_fini = pp_tables_uninitialize,
1805 .pptable_get_number_of_vce_state_table_entries =
1806 get_number_of_vce_state_table_entries,
1807 .pptable_get_vce_state_table_entry =
1808 get_vce_state_table_entry,
1809 };
1810