Linux Audio

Check our new training course

Embedded Linux training

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