Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2015 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
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     /* We assume here that fw_info is unchanged if this call fails.*/
1185     fw_info = smu_atom_get_data_table(hwmgr->adev,
1186              GetIndexIntoMasterTable(DATA, FirmwareInfo),
1187              &size, &frev, &crev);
1188 
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