cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

processpptables.c (61215B)


      1/*
      2 * Copyright 2015 Advanced Micro Devices, Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 *
     22 */
     23#include "pp_debug.h"
     24#include <linux/types.h>
     25#include <linux/kernel.h>
     26#include <linux/slab.h>
     27#include <linux/pci.h>
     28
     29#include <drm/amdgpu_drm.h>
     30#include "processpptables.h"
     31#include <atom-types.h>
     32#include <atombios.h>
     33#include "pptable.h"
     34#include "power_state.h"
     35#include "hwmgr.h"
     36#include "hardwaremanager.h"
     37
     38
     39#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
     40#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
     41#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
     42#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
     43#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
     44#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
     45#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
     46#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
     47
     48#define NUM_BITS_CLOCK_INFO_ARRAY_INDEX 6
     49
     50static uint16_t get_vce_table_offset(struct pp_hwmgr *hwmgr,
     51			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
     52{
     53	uint16_t vce_table_offset = 0;
     54
     55	if (le16_to_cpu(powerplay_table->usTableSize) >=
     56	   sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
     57		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
     58			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
     59
     60		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
     61			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
     62						(const ATOM_PPLIB_EXTENDEDHEADER *)
     63						(((unsigned long)powerplay_table3) +
     64						le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
     65			if (le16_to_cpu(extended_header->usSize) >=
     66			   SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2)
     67				vce_table_offset = le16_to_cpu(extended_header->usVCETableOffset);
     68		}
     69	}
     70
     71	return vce_table_offset;
     72}
     73
     74static uint16_t get_vce_clock_info_array_offset(struct pp_hwmgr *hwmgr,
     75			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
     76{
     77	uint16_t table_offset = get_vce_table_offset(hwmgr,
     78						powerplay_table);
     79
     80	if (table_offset > 0)
     81		return table_offset + 1;
     82
     83	return 0;
     84}
     85
     86static uint16_t get_vce_clock_info_array_size(struct pp_hwmgr *hwmgr,
     87			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
     88{
     89	uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
     90							powerplay_table);
     91	uint16_t table_size = 0;
     92
     93	if (table_offset > 0) {
     94		const VCEClockInfoArray *p = (const VCEClockInfoArray *)
     95			(((unsigned long) powerplay_table) + table_offset);
     96		table_size = sizeof(uint8_t) + p->ucNumEntries * sizeof(VCEClockInfo);
     97	}
     98
     99	return table_size;
    100}
    101
    102static uint16_t get_vce_clock_voltage_limit_table_offset(struct pp_hwmgr *hwmgr,
    103				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    104{
    105	uint16_t table_offset = get_vce_clock_info_array_offset(hwmgr,
    106							powerplay_table);
    107
    108	if (table_offset > 0)
    109		return table_offset + get_vce_clock_info_array_size(hwmgr,
    110							powerplay_table);
    111
    112	return 0;
    113}
    114
    115static uint16_t get_vce_clock_voltage_limit_table_size(struct pp_hwmgr *hwmgr,
    116							const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    117{
    118	uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
    119	uint16_t table_size = 0;
    120
    121	if (table_offset > 0) {
    122		const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *ptable =
    123			(const ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)(((unsigned long) powerplay_table) + table_offset);
    124
    125		table_size = sizeof(uint8_t) + ptable->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record);
    126	}
    127	return table_size;
    128}
    129
    130static uint16_t get_vce_state_table_offset(struct pp_hwmgr *hwmgr, const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    131{
    132	uint16_t table_offset = get_vce_clock_voltage_limit_table_offset(hwmgr, powerplay_table);
    133
    134	if (table_offset > 0)
    135		return table_offset + get_vce_clock_voltage_limit_table_size(hwmgr, powerplay_table);
    136
    137	return 0;
    138}
    139
    140static const ATOM_PPLIB_VCE_State_Table *get_vce_state_table(
    141						struct pp_hwmgr *hwmgr,
    142						const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    143{
    144	uint16_t table_offset = get_vce_state_table_offset(hwmgr, powerplay_table);
    145
    146	if (table_offset > 0)
    147		return (const ATOM_PPLIB_VCE_State_Table *)(((unsigned long) powerplay_table) + table_offset);
    148
    149	return NULL;
    150}
    151
    152static uint16_t get_uvd_table_offset(struct pp_hwmgr *hwmgr,
    153			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    154{
    155	uint16_t uvd_table_offset = 0;
    156
    157	if (le16_to_cpu(powerplay_table->usTableSize) >=
    158	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
    159		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
    160			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
    161		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
    162			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
    163					(const ATOM_PPLIB_EXTENDEDHEADER *)
    164					(((unsigned long)powerplay_table3) +
    165				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
    166			if (le16_to_cpu(extended_header->usSize) >=
    167			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3)
    168				uvd_table_offset = le16_to_cpu(extended_header->usUVDTableOffset);
    169		}
    170	}
    171	return uvd_table_offset;
    172}
    173
    174static uint16_t get_uvd_clock_info_array_offset(struct pp_hwmgr *hwmgr,
    175			 const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    176{
    177	uint16_t table_offset = get_uvd_table_offset(hwmgr,
    178						    powerplay_table);
    179
    180	if (table_offset > 0)
    181		return table_offset + 1;
    182	return 0;
    183}
    184
    185static uint16_t get_uvd_clock_info_array_size(struct pp_hwmgr *hwmgr,
    186			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    187{
    188	uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
    189						    powerplay_table);
    190	uint16_t table_size = 0;
    191
    192	if (table_offset > 0) {
    193		const UVDClockInfoArray *p = (const UVDClockInfoArray *)
    194					(((unsigned long) powerplay_table)
    195					+ table_offset);
    196		table_size = sizeof(UCHAR) +
    197			     p->ucNumEntries * sizeof(UVDClockInfo);
    198	}
    199
    200	return table_size;
    201}
    202
    203static uint16_t get_uvd_clock_voltage_limit_table_offset(
    204			struct pp_hwmgr *hwmgr,
    205			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    206{
    207	uint16_t table_offset = get_uvd_clock_info_array_offset(hwmgr,
    208						     powerplay_table);
    209
    210	if (table_offset > 0)
    211		return table_offset +
    212			get_uvd_clock_info_array_size(hwmgr, powerplay_table);
    213
    214	return 0;
    215}
    216
    217static uint16_t get_samu_table_offset(struct pp_hwmgr *hwmgr,
    218			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    219{
    220	uint16_t samu_table_offset = 0;
    221
    222	if (le16_to_cpu(powerplay_table->usTableSize) >=
    223	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
    224		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
    225			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
    226		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
    227			const ATOM_PPLIB_EXTENDEDHEADER  *extended_header =
    228				(const ATOM_PPLIB_EXTENDEDHEADER *)
    229				(((unsigned long)powerplay_table3) +
    230				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
    231			if (le16_to_cpu(extended_header->usSize) >=
    232			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4)
    233				samu_table_offset = le16_to_cpu(extended_header->usSAMUTableOffset);
    234		}
    235	}
    236
    237	return samu_table_offset;
    238}
    239
    240static uint16_t get_samu_clock_voltage_limit_table_offset(
    241			struct pp_hwmgr *hwmgr,
    242			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    243{
    244	uint16_t table_offset = get_samu_table_offset(hwmgr,
    245					    powerplay_table);
    246
    247	if (table_offset > 0)
    248		return table_offset + 1;
    249
    250	return 0;
    251}
    252
    253static uint16_t get_acp_table_offset(struct pp_hwmgr *hwmgr,
    254				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    255{
    256	uint16_t acp_table_offset = 0;
    257
    258	if (le16_to_cpu(powerplay_table->usTableSize) >=
    259	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
    260		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
    261			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
    262		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
    263			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
    264				(const ATOM_PPLIB_EXTENDEDHEADER *)
    265				(((unsigned long)powerplay_table3) +
    266				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
    267			if (le16_to_cpu(pExtendedHeader->usSize) >=
    268			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6)
    269				acp_table_offset = le16_to_cpu(pExtendedHeader->usACPTableOffset);
    270		}
    271	}
    272
    273	return acp_table_offset;
    274}
    275
    276static uint16_t get_acp_clock_voltage_limit_table_offset(
    277				struct pp_hwmgr *hwmgr,
    278				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    279{
    280	uint16_t tableOffset = get_acp_table_offset(hwmgr, powerplay_table);
    281
    282	if (tableOffset > 0)
    283		return tableOffset + 1;
    284
    285	return 0;
    286}
    287
    288static uint16_t get_cacp_tdp_table_offset(
    289				struct pp_hwmgr *hwmgr,
    290				const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    291{
    292	uint16_t cacTdpTableOffset = 0;
    293
    294	if (le16_to_cpu(powerplay_table->usTableSize) >=
    295	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
    296		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
    297				(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
    298		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
    299			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
    300					(const ATOM_PPLIB_EXTENDEDHEADER *)
    301					(((unsigned long)powerplay_table3) +
    302				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
    303			if (le16_to_cpu(pExtendedHeader->usSize) >=
    304			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7)
    305				cacTdpTableOffset = le16_to_cpu(pExtendedHeader->usPowerTuneTableOffset);
    306		}
    307	}
    308
    309	return cacTdpTableOffset;
    310}
    311
    312static int get_cac_tdp_table(struct pp_hwmgr *hwmgr,
    313				struct phm_cac_tdp_table **ptable,
    314				const ATOM_PowerTune_Table *table,
    315				uint16_t us_maximum_power_delivery_limit)
    316{
    317	unsigned long table_size;
    318	struct phm_cac_tdp_table *tdp_table;
    319
    320	table_size = sizeof(unsigned long) + sizeof(struct phm_cac_tdp_table);
    321
    322	tdp_table = kzalloc(table_size, GFP_KERNEL);
    323	if (NULL == tdp_table)
    324		return -ENOMEM;
    325
    326	tdp_table->usTDP = le16_to_cpu(table->usTDP);
    327	tdp_table->usConfigurableTDP = le16_to_cpu(table->usConfigurableTDP);
    328	tdp_table->usTDC = le16_to_cpu(table->usTDC);
    329	tdp_table->usBatteryPowerLimit = le16_to_cpu(table->usBatteryPowerLimit);
    330	tdp_table->usSmallPowerLimit = le16_to_cpu(table->usSmallPowerLimit);
    331	tdp_table->usLowCACLeakage = le16_to_cpu(table->usLowCACLeakage);
    332	tdp_table->usHighCACLeakage = le16_to_cpu(table->usHighCACLeakage);
    333	tdp_table->usMaximumPowerDeliveryLimit = us_maximum_power_delivery_limit;
    334
    335	*ptable = tdp_table;
    336
    337	return 0;
    338}
    339
    340static uint16_t get_sclk_vdd_gfx_table_offset(struct pp_hwmgr *hwmgr,
    341			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    342{
    343	uint16_t sclk_vdd_gfx_table_offset = 0;
    344
    345	if (le16_to_cpu(powerplay_table->usTableSize) >=
    346	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
    347		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
    348				(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
    349		if (powerplay_table3->usExtendendedHeaderOffset > 0) {
    350			const ATOM_PPLIB_EXTENDEDHEADER  *pExtendedHeader =
    351				(const ATOM_PPLIB_EXTENDEDHEADER *)
    352				(((unsigned long)powerplay_table3) +
    353				le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
    354			if (le16_to_cpu(pExtendedHeader->usSize) >=
    355			    SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8)
    356				sclk_vdd_gfx_table_offset =
    357					le16_to_cpu(pExtendedHeader->usSclkVddgfxTableOffset);
    358		}
    359	}
    360
    361	return sclk_vdd_gfx_table_offset;
    362}
    363
    364static uint16_t get_sclk_vdd_gfx_clock_voltage_dependency_table_offset(
    365			struct pp_hwmgr *hwmgr,
    366			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    367{
    368	uint16_t tableOffset = get_sclk_vdd_gfx_table_offset(hwmgr, powerplay_table);
    369
    370	if (tableOffset > 0)
    371		return tableOffset;
    372
    373	return 0;
    374}
    375
    376
    377static int get_clock_voltage_dependency_table(struct pp_hwmgr *hwmgr,
    378		struct phm_clock_voltage_dependency_table **ptable,
    379		const ATOM_PPLIB_Clock_Voltage_Dependency_Table *table)
    380{
    381
    382	unsigned long i;
    383	struct phm_clock_voltage_dependency_table *dep_table;
    384
    385	dep_table = kzalloc(struct_size(dep_table, entries, table->ucNumEntries),
    386			    GFP_KERNEL);
    387	if (NULL == dep_table)
    388		return -ENOMEM;
    389
    390	dep_table->count = (unsigned long)table->ucNumEntries;
    391
    392	for (i = 0; i < dep_table->count; i++) {
    393		dep_table->entries[i].clk =
    394			((unsigned long)table->entries[i].ucClockHigh << 16) |
    395			le16_to_cpu(table->entries[i].usClockLow);
    396		dep_table->entries[i].v =
    397			(unsigned long)le16_to_cpu(table->entries[i].usVoltage);
    398	}
    399
    400	*ptable = dep_table;
    401
    402	return 0;
    403}
    404
    405static int get_valid_clk(struct pp_hwmgr *hwmgr,
    406			struct phm_clock_array **ptable,
    407			const struct phm_clock_voltage_dependency_table *table)
    408{
    409	unsigned long i;
    410	struct phm_clock_array *clock_table;
    411
    412	clock_table = kzalloc(struct_size(clock_table, values, table->count), GFP_KERNEL);
    413	if (!clock_table)
    414		return -ENOMEM;
    415
    416	clock_table->count = (unsigned long)table->count;
    417
    418	for (i = 0; i < clock_table->count; i++)
    419		clock_table->values[i] = (unsigned long)table->entries[i].clk;
    420
    421	*ptable = clock_table;
    422
    423	return 0;
    424}
    425
    426static int get_clock_voltage_limit(struct pp_hwmgr *hwmgr,
    427			struct phm_clock_and_voltage_limits *limits,
    428			const ATOM_PPLIB_Clock_Voltage_Limit_Table *table)
    429{
    430	limits->sclk = ((unsigned long)table->entries[0].ucSclkHigh << 16) |
    431			le16_to_cpu(table->entries[0].usSclkLow);
    432	limits->mclk = ((unsigned long)table->entries[0].ucMclkHigh << 16) |
    433			le16_to_cpu(table->entries[0].usMclkLow);
    434	limits->vddc = (unsigned long)le16_to_cpu(table->entries[0].usVddc);
    435	limits->vddci = (unsigned long)le16_to_cpu(table->entries[0].usVddci);
    436
    437	return 0;
    438}
    439
    440
    441static void set_hw_cap(struct pp_hwmgr *hwmgr, bool enable,
    442		       enum phm_platform_caps cap)
    443{
    444	if (enable)
    445		phm_cap_set(hwmgr->platform_descriptor.platformCaps, cap);
    446	else
    447		phm_cap_unset(hwmgr->platform_descriptor.platformCaps, cap);
    448}
    449
    450static int set_platform_caps(struct pp_hwmgr *hwmgr,
    451			unsigned long powerplay_caps)
    452{
    453	set_hw_cap(
    454		hwmgr,
    455		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_POWERPLAY),
    456		PHM_PlatformCaps_PowerPlaySupport
    457	);
    458
    459	set_hw_cap(
    460		hwmgr,
    461		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SBIOSPOWERSOURCE),
    462		PHM_PlatformCaps_BiosPowerSourceControl
    463	);
    464
    465	set_hw_cap(
    466		hwmgr,
    467		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L0s),
    468		PHM_PlatformCaps_EnableASPML0s
    469	);
    470
    471	set_hw_cap(
    472		hwmgr,
    473		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_ASPM_L1),
    474		PHM_PlatformCaps_EnableASPML1
    475	);
    476
    477	set_hw_cap(
    478		hwmgr,
    479		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACKBIAS),
    480		PHM_PlatformCaps_EnableBackbias
    481	);
    482
    483	set_hw_cap(
    484		hwmgr,
    485		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HARDWAREDC),
    486		PHM_PlatformCaps_AutomaticDCTransition
    487	);
    488
    489	set_hw_cap(
    490		hwmgr,
    491		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GEMINIPRIMARY),
    492		PHM_PlatformCaps_GeminiPrimary
    493	);
    494
    495	set_hw_cap(
    496		hwmgr,
    497		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_STEPVDDC),
    498		PHM_PlatformCaps_StepVddc
    499	);
    500
    501	set_hw_cap(
    502		hwmgr,
    503		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VOLTAGECONTROL),
    504		PHM_PlatformCaps_EnableVoltageControl
    505	);
    506
    507	set_hw_cap(
    508		hwmgr,
    509		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_SIDEPORTCONTROL),
    510		PHM_PlatformCaps_EnableSideportControl
    511	);
    512
    513	set_hw_cap(
    514		hwmgr,
    515		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TURNOFFPLL_ASPML1),
    516		PHM_PlatformCaps_TurnOffPll_ASPML1
    517	);
    518
    519	set_hw_cap(
    520		hwmgr,
    521		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_HTLINKCONTROL),
    522		PHM_PlatformCaps_EnableHTLinkControl
    523	);
    524
    525	set_hw_cap(
    526		hwmgr,
    527		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_MVDDCONTROL),
    528		PHM_PlatformCaps_EnableMVDDControl
    529	);
    530
    531	set_hw_cap(
    532		hwmgr,
    533		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VDDCI_CONTROL),
    534		PHM_PlatformCaps_ControlVDDCI
    535	);
    536
    537	set_hw_cap(
    538		hwmgr,
    539		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REGULATOR_HOT),
    540		PHM_PlatformCaps_RegulatorHot
    541	);
    542
    543	set_hw_cap(
    544		hwmgr,
    545		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_GOTO_BOOT_ON_ALERT),
    546		PHM_PlatformCaps_BootStateOnAlert
    547	);
    548
    549	set_hw_cap(
    550		hwmgr,
    551		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DONT_WAIT_FOR_VBLANK_ON_ALERT),
    552		PHM_PlatformCaps_DontWaitForVBlankOnAlert
    553	);
    554
    555	set_hw_cap(
    556		hwmgr,
    557		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_BACO),
    558		PHM_PlatformCaps_BACO
    559	);
    560
    561	set_hw_cap(
    562		hwmgr,
    563		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_NEW_CAC_VOLTAGE),
    564		PHM_PlatformCaps_NewCACVoltage
    565	);
    566
    567	set_hw_cap(
    568		hwmgr,
    569		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_REVERT_GPIO5_POLARITY),
    570		PHM_PlatformCaps_RevertGPIO5Polarity
    571	);
    572
    573	set_hw_cap(
    574		hwmgr,
    575		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_OUTPUT_THERMAL2GPIO17),
    576		PHM_PlatformCaps_Thermal2GPIO17
    577	);
    578
    579	set_hw_cap(
    580		hwmgr,
    581		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_VRHOT_GPIO_CONFIGURABLE),
    582		PHM_PlatformCaps_VRHotGPIOConfigurable
    583	);
    584
    585	set_hw_cap(
    586		hwmgr,
    587		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_TEMP_INVERSION),
    588		PHM_PlatformCaps_TempInversion
    589	);
    590
    591	set_hw_cap(
    592		hwmgr,
    593		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_EVV),
    594		PHM_PlatformCaps_EVV
    595	);
    596
    597	set_hw_cap(
    598		hwmgr,
    599		0 != (powerplay_caps & ATOM_PP_PLATFORM_COMBINE_PCC_WITH_THERMAL_SIGNAL),
    600		PHM_PlatformCaps_CombinePCCWithThermalSignal
    601	);
    602
    603	set_hw_cap(
    604		hwmgr,
    605		0 != (powerplay_caps & ATOM_PP_PLATFORM_LOAD_POST_PRODUCTION_FIRMWARE),
    606		PHM_PlatformCaps_LoadPostProductionFirmware
    607	);
    608
    609	set_hw_cap(
    610		hwmgr,
    611		0 != (powerplay_caps & ATOM_PP_PLATFORM_CAP_DISABLE_USING_ACTUAL_TEMPERATURE_FOR_POWER_CALC),
    612		PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc
    613	);
    614
    615	return 0;
    616}
    617
    618static PP_StateClassificationFlags make_classification_flags(
    619						   struct pp_hwmgr *hwmgr,
    620						    USHORT classification,
    621						   USHORT classification2)
    622{
    623	PP_StateClassificationFlags result = 0;
    624
    625	if (classification & ATOM_PPLIB_CLASSIFICATION_BOOT)
    626		result |= PP_StateClassificationFlag_Boot;
    627
    628	if (classification & ATOM_PPLIB_CLASSIFICATION_THERMAL)
    629		result |= PP_StateClassificationFlag_Thermal;
    630
    631	if (classification &
    632			ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE)
    633		result |= PP_StateClassificationFlag_LimitedPowerSource;
    634
    635	if (classification & ATOM_PPLIB_CLASSIFICATION_REST)
    636		result |= PP_StateClassificationFlag_Rest;
    637
    638	if (classification & ATOM_PPLIB_CLASSIFICATION_FORCED)
    639		result |= PP_StateClassificationFlag_Forced;
    640
    641	if (classification & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
    642		result |= PP_StateClassificationFlag_3DPerformance;
    643
    644
    645	if (classification & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE)
    646		result |= PP_StateClassificationFlag_ACOverdriveTemplate;
    647
    648	if (classification & ATOM_PPLIB_CLASSIFICATION_UVDSTATE)
    649		result |= PP_StateClassificationFlag_Uvd;
    650
    651	if (classification & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
    652		result |= PP_StateClassificationFlag_UvdHD;
    653
    654	if (classification & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
    655		result |= PP_StateClassificationFlag_UvdSD;
    656
    657	if (classification & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
    658		result |= PP_StateClassificationFlag_HD2;
    659
    660	if (classification & ATOM_PPLIB_CLASSIFICATION_ACPI)
    661		result |= PP_StateClassificationFlag_ACPI;
    662
    663	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2)
    664		result |= PP_StateClassificationFlag_LimitedPowerSource_2;
    665
    666
    667	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
    668		result |= PP_StateClassificationFlag_ULV;
    669
    670	if (classification2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
    671		result |= PP_StateClassificationFlag_UvdMVC;
    672
    673	return result;
    674}
    675
    676static int init_non_clock_fields(struct pp_hwmgr *hwmgr,
    677						struct pp_power_state *ps,
    678							    uint8_t version,
    679			 const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info) {
    680	unsigned long rrr_index;
    681	unsigned long tmp;
    682
    683	ps->classification.ui_label = (le16_to_cpu(pnon_clock_info->usClassification) &
    684					ATOM_PPLIB_CLASSIFICATION_UI_MASK) >> ATOM_PPLIB_CLASSIFICATION_UI_SHIFT;
    685	ps->classification.flags = make_classification_flags(hwmgr,
    686				le16_to_cpu(pnon_clock_info->usClassification),
    687				le16_to_cpu(pnon_clock_info->usClassification2));
    688
    689	ps->classification.temporary_state = false;
    690	ps->classification.to_be_deleted = false;
    691	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    692		ATOM_PPLIB_SINGLE_DISPLAY_ONLY;
    693
    694	ps->validation.singleDisplayOnly = (0 != tmp);
    695
    696	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    697		ATOM_PPLIB_DISALLOW_ON_DC;
    698
    699	ps->validation.disallowOnDC = (0 != tmp);
    700
    701	ps->pcie.lanes = ((le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    702				ATOM_PPLIB_PCIE_LINK_WIDTH_MASK) >>
    703				ATOM_PPLIB_PCIE_LINK_WIDTH_SHIFT) + 1;
    704
    705	ps->pcie.lanes = 0;
    706
    707	ps->display.disableFrameModulation = false;
    708
    709	rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    710			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
    711			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
    712
    713	if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
    714		static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
    715								{ 0, 50, 0 };
    716
    717		ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
    718		ps->display.explicitRefreshrate = look_up[rrr_index];
    719		ps->display.limitRefreshrate = true;
    720
    721		if (ps->display.explicitRefreshrate == 0)
    722			ps->display.limitRefreshrate = false;
    723	} else
    724		ps->display.limitRefreshrate = false;
    725
    726	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    727		ATOM_PPLIB_ENABLE_VARIBRIGHT;
    728
    729	ps->display.enableVariBright = (0 != tmp);
    730
    731	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    732		ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
    733
    734	ps->memory.dllOff = (0 != tmp);
    735
    736	ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    737			    ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
    738
    739	ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
    740				     pnon_clock_info->ucMinTemperature;
    741
    742	ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
    743				     pnon_clock_info->ucMaxTemperature;
    744
    745	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    746		ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
    747
    748	ps->software.disableLoadBalancing = tmp;
    749
    750	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
    751		ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
    752
    753	ps->software.enableSleepForTimestamps = (0 != tmp);
    754
    755	ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
    756
    757	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
    758		ps->uvd_clocks.VCLK = le32_to_cpu(pnon_clock_info->ulVCLK);
    759		ps->uvd_clocks.DCLK = le32_to_cpu(pnon_clock_info->ulDCLK);
    760	} else {
    761		ps->uvd_clocks.VCLK = 0;
    762		ps->uvd_clocks.DCLK = 0;
    763	}
    764
    765	return 0;
    766}
    767
    768static ULONG size_of_entry_v2(ULONG num_dpm_levels)
    769{
    770	return (sizeof(UCHAR) + sizeof(UCHAR) +
    771			(num_dpm_levels * sizeof(UCHAR)));
    772}
    773
    774static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
    775					const StateArray * pstate_arrays,
    776							 ULONG entry_index)
    777{
    778	ULONG i;
    779	const ATOM_PPLIB_STATE_V2 *pstate;
    780
    781	pstate = pstate_arrays->states;
    782	if (entry_index <= pstate_arrays->ucNumEntries) {
    783		for (i = 0; i < entry_index; i++)
    784			pstate = (ATOM_PPLIB_STATE_V2 *)(
    785						  (unsigned long)pstate +
    786			     size_of_entry_v2(pstate->ucNumDPMLevels));
    787	}
    788	return pstate;
    789}
    790
    791static const unsigned char soft_dummy_pp_table[] = {
    792	0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00,
    793	0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
    794	0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
    795	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    796	0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
    797	0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
    798	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00,
    799	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    800	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    801	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00,
    802	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00,
    803	0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
    804	0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00,
    805	0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
    806	0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59,
    807	0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28,
    808	0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01,
    809	0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01,
    810	0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a,
    811	0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
    812	0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c,
    813	0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01,
    814	0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e,
    815	0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70,
    816	0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08,
    817	0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70,
    818	0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00,
    819	0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
    820	0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00,
    821	0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
    822	0x00
    823};
    824
    825static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
    826				     struct pp_hwmgr *hwmgr)
    827{
    828	const void *table_addr = hwmgr->soft_pp_table;
    829	uint8_t frev, crev;
    830	uint16_t size;
    831
    832	if (!table_addr) {
    833		if (hwmgr->chip_id == CHIP_RAVEN) {
    834			table_addr = &soft_dummy_pp_table[0];
    835			hwmgr->soft_pp_table = &soft_dummy_pp_table[0];
    836			hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table);
    837		} else {
    838			table_addr = smu_atom_get_data_table(hwmgr->adev,
    839					GetIndexIntoMasterTable(DATA, PowerPlayInfo),
    840					&size, &frev, &crev);
    841			hwmgr->soft_pp_table = table_addr;
    842			hwmgr->soft_pp_table_size = size;
    843		}
    844	}
    845
    846	return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
    847}
    848
    849int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
    850				uint32_t *vol_rep_time, uint32_t *bb_rep_time)
    851{
    852	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr);
    853
    854	PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
    855			    "Missing PowerPlay Table!", return -EINVAL);
    856
    857	*vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
    858	*bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
    859
    860	return 0;
    861}
    862
    863int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
    864				     unsigned long *num_of_entries)
    865{
    866	const StateArray *pstate_arrays;
    867	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
    868
    869	if (powerplay_table == NULL)
    870		return -1;
    871
    872	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
    873		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
    874					le16_to_cpu(powerplay_table->usStateArrayOffset));
    875
    876		*num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
    877	} else
    878		*num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
    879
    880	return 0;
    881}
    882
    883int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
    884				unsigned long entry_index,
    885				struct pp_power_state *ps,
    886			 pp_tables_hw_clock_info_callback func)
    887{
    888	int i;
    889	const StateArray *pstate_arrays;
    890	const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
    891	const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
    892	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
    893	int result = 0;
    894	int res = 0;
    895
    896	const ClockInfoArray *pclock_arrays;
    897
    898	const NonClockInfoArray *pnon_clock_arrays;
    899
    900	const ATOM_PPLIB_STATE *pstate_entry;
    901
    902	if (powerplay_table == NULL)
    903		return -1;
    904
    905	ps->classification.bios_index = entry_index;
    906
    907	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
    908		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
    909					le16_to_cpu(powerplay_table->usStateArrayOffset));
    910
    911		if (entry_index > pstate_arrays->ucNumEntries)
    912			return -1;
    913
    914		pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
    915		pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
    916					le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
    917
    918		pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
    919						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
    920
    921		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
    922					(pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
    923
    924		result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
    925
    926		for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
    927			const void *pclock_info = (const void *)(
    928							(unsigned long)(pclock_arrays->clockInfo) +
    929							(pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
    930			res = func(hwmgr, &ps->hardware, i, pclock_info);
    931			if ((0 == result) && (0 != res))
    932				result = res;
    933		}
    934	} else {
    935		if (entry_index > powerplay_table->ucNumStates)
    936			return -1;
    937
    938		pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table +
    939						    le16_to_cpu(powerplay_table->usStateArrayOffset) +
    940						    entry_index * powerplay_table->ucStateEntrySize);
    941
    942		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
    943						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
    944						pstate_entry->ucNonClockStateIndex *
    945						powerplay_table->ucNonClockSize);
    946
    947		result = init_non_clock_fields(hwmgr, ps,
    948							powerplay_table->ucNonClockSize,
    949							pnon_clock_info);
    950
    951		for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
    952			const void *pclock_info = (const void *)((unsigned long)powerplay_table +
    953						le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
    954						pstate_entry->ucClockStateIndices[i] *
    955						powerplay_table->ucClockInfoSize);
    956
    957			int res = func(hwmgr, &ps->hardware, i, pclock_info);
    958
    959			if ((0 == result) && (0 != res))
    960					result = res;
    961		}
    962	}
    963
    964	if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
    965		if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
    966			result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
    967	}
    968
    969	return result;
    970}
    971
    972static int init_powerplay_tables(
    973			struct pp_hwmgr *hwmgr,
    974			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
    975)
    976{
    977	return 0;
    978}
    979
    980
    981static int init_thermal_controller(
    982			struct pp_hwmgr *hwmgr,
    983			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
    984{
    985	struct amdgpu_device *adev = hwmgr->adev;
    986
    987	hwmgr->thermal_controller.ucType =
    988			powerplay_table->sThermalController.ucType;
    989	hwmgr->thermal_controller.ucI2cLine =
    990			powerplay_table->sThermalController.ucI2cLine;
    991	hwmgr->thermal_controller.ucI2cAddress =
    992			powerplay_table->sThermalController.ucI2cAddress;
    993
    994	hwmgr->thermal_controller.fanInfo.bNoFan =
    995		(0 != (powerplay_table->sThermalController.ucFanParameters &
    996			ATOM_PP_FANPARAMETERS_NOFAN));
    997
    998	hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
    999		powerplay_table->sThermalController.ucFanParameters &
   1000		ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
   1001
   1002	hwmgr->thermal_controller.fanInfo.ulMinRPM
   1003		= powerplay_table->sThermalController.ucFanMinRPM * 100UL;
   1004	hwmgr->thermal_controller.fanInfo.ulMaxRPM
   1005		= powerplay_table->sThermalController.ucFanMaxRPM * 100UL;
   1006
   1007	set_hw_cap(hwmgr,
   1008		   ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
   1009		   PHM_PlatformCaps_ThermalController);
   1010
   1011        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
   1113static 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
   1136static 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
   1166static 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
   1204static 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
   1234static 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
   1263static 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
   1288static 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
   1313static 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
   1480static 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
   1514static 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
   1537static 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
   1611static 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
   1649static 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
   1663static 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
   1697static 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
   1749static 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
   1802const 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