Linux Audio

Check our new training course

Linux debugging, profiling, tracing and performance analysis training

Apr 14-17, 2025
Register
Loading...
Note: File does not exist in v3.1.
   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;
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