File Index
Files and directories
Sign in
FILE

processpptables.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/pm/powerplay/hwmgr/processpptables.c C
   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->display.disableFrameModulation = false;
 706
 707	rrr_index = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 708			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK) >>
 709			ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT;
 710
 711	if (rrr_index != ATOM_PPLIB_LIMITED_REFRESHRATE_UNLIMITED) {
 712		static const uint8_t look_up[(ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_MASK >> ATOM_PPLIB_LIMITED_REFRESHRATE_VALUE_SHIFT) + 1] = \
 713								{ 0, 50, 0 };
 714
 715		ps->display.refreshrateSource = PP_RefreshrateSource_Explicit;
 716		ps->display.explicitRefreshrate = look_up[rrr_index];
 717		ps->display.limitRefreshrate = true;
 718
 719		if (ps->display.explicitRefreshrate == 0)
 720			ps->display.limitRefreshrate = false;
 721	} else
 722		ps->display.limitRefreshrate = false;
 723
 724	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 725		ATOM_PPLIB_ENABLE_VARIBRIGHT;
 726
 727	ps->display.enableVariBright = (0 != tmp);
 728
 729	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 730		ATOM_PPLIB_SWSTATE_MEMORY_DLL_OFF;
 731
 732	ps->memory.dllOff = (0 != tmp);
 733
 734	ps->memory.m3arb = (le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 735			    ATOM_PPLIB_M3ARB_MASK) >> ATOM_PPLIB_M3ARB_SHIFT;
 736
 737	ps->temperatures.min = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
 738				     pnon_clock_info->ucMinTemperature;
 739
 740	ps->temperatures.max = PP_TEMPERATURE_UNITS_PER_CENTIGRADES *
 741				     pnon_clock_info->ucMaxTemperature;
 742
 743	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 744		ATOM_PPLIB_SOFTWARE_DISABLE_LOADBALANCING;
 745
 746	ps->software.disableLoadBalancing = tmp;
 747
 748	tmp = le32_to_cpu(pnon_clock_info->ulCapsAndSettings) &
 749		ATOM_PPLIB_SOFTWARE_ENABLE_SLEEP_FOR_TIMESTAMPS;
 750
 751	ps->software.enableSleepForTimestamps = (0 != tmp);
 752
 753	ps->validation.supportedPowerLevels = pnon_clock_info->ucRequiredPower;
 754
 755	if (ATOM_PPLIB_NONCLOCKINFO_VER1 < version) {
 756		ps->uvd_clocks.VCLK = le32_to_cpu(pnon_clock_info->ulVCLK);
 757		ps->uvd_clocks.DCLK = le32_to_cpu(pnon_clock_info->ulDCLK);
 758	} else {
 759		ps->uvd_clocks.VCLK = 0;
 760		ps->uvd_clocks.DCLK = 0;
 761	}
 762
 763	return 0;
 764}
 765
 766static ULONG size_of_entry_v2(ULONG num_dpm_levels)
 767{
 768	return (sizeof(UCHAR) + sizeof(UCHAR) +
 769			(num_dpm_levels * sizeof(UCHAR)));
 770}
 771
 772static const ATOM_PPLIB_STATE_V2 *get_state_entry_v2(
 773					const StateArray * pstate_arrays,
 774							 ULONG entry_index)
 775{
 776	ULONG i;
 777	const ATOM_PPLIB_STATE_V2 *pstate;
 778
 779	pstate = pstate_arrays->states;
 780	if (entry_index <= pstate_arrays->ucNumEntries) {
 781		for (i = 0; i < entry_index; i++)
 782			pstate = (ATOM_PPLIB_STATE_V2 *)(
 783						  (unsigned long)pstate +
 784			     size_of_entry_v2(pstate->ucNumDPMLevels));
 785	}
 786	return pstate;
 787}
 788
 789static const unsigned char soft_dummy_pp_table[] = {
 790	0xe1, 0x01, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x4a, 0x00, 0x6c, 0x00, 0x00,
 791	0x00, 0x00, 0x00, 0x42, 0x00, 0x02, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00,
 792	0x00, 0x4e, 0x00, 0x88, 0x00, 0x00, 0x9e, 0x00, 0x17, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00,
 793	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 794	0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00,
 795	0x07, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
 796	0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x18, 0x05, 0x00,
 797	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 798	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 799	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00,
 800	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe1, 0x00, 0x43, 0x01, 0x00, 0x00, 0x00, 0x00,
 801	0x8e, 0x01, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
 802	0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x70, 0x00, 0x91, 0xf4, 0x00,
 803	0x64, 0x00, 0x40, 0x19, 0x01, 0x5a, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
 804	0x00, 0x00, 0x09, 0x30, 0x75, 0x00, 0x30, 0x75, 0x00, 0x40, 0x9c, 0x00, 0x40, 0x9c, 0x00, 0x59,
 805	0xd8, 0x00, 0x59, 0xd8, 0x00, 0x91, 0xf4, 0x00, 0x91, 0xf4, 0x00, 0x0e, 0x28, 0x01, 0x0e, 0x28,
 806	0x01, 0x90, 0x5f, 0x01, 0x90, 0x5f, 0x01, 0x00, 0x77, 0x01, 0x00, 0x77, 0x01, 0xca, 0x91, 0x01,
 807	0xca, 0x91, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01,
 808	0x7c, 0x00, 0x02, 0x70, 0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a,
 809	0x00, 0x07, 0x08, 0x08, 0x00, 0x08, 0x00, 0x01, 0x02, 0x02, 0x02, 0x01, 0x02, 0x02, 0x02, 0x03,
 810	0x02, 0x04, 0x02, 0x00, 0x08, 0x40, 0x9c, 0x00, 0x30, 0x75, 0x00, 0x74, 0xb5, 0x00, 0xa0, 0x8c,
 811	0x00, 0x60, 0xea, 0x00, 0x74, 0xb5, 0x00, 0x0e, 0x28, 0x01, 0x60, 0xea, 0x00, 0x90, 0x5f, 0x01,
 812	0x40, 0x19, 0x01, 0xb2, 0xb0, 0x01, 0x90, 0x5f, 0x01, 0xc0, 0xd4, 0x01, 0x00, 0x77, 0x01, 0x5e,
 813	0xff, 0x01, 0xca, 0x91, 0x01, 0x08, 0x80, 0x00, 0x00, 0x7e, 0x00, 0x01, 0x7c, 0x00, 0x02, 0x70,
 814	0x00, 0x03, 0x64, 0x00, 0x04, 0x5a, 0x00, 0x05, 0x52, 0x00, 0x06, 0x4a, 0x00, 0x07, 0x00, 0x08,
 815	0x80, 0x00, 0x30, 0x75, 0x00, 0x7e, 0x00, 0x40, 0x9c, 0x00, 0x7c, 0x00, 0x59, 0xd8, 0x00, 0x70,
 816	0x00, 0xdc, 0x0b, 0x01, 0x64, 0x00, 0x80, 0x38, 0x01, 0x5a, 0x00, 0x80, 0x38, 0x01, 0x52, 0x00,
 817	0x80, 0x38, 0x01, 0x4a, 0x00, 0x80, 0x38, 0x01, 0x08, 0x30, 0x75, 0x00, 0x80, 0x00, 0xa0, 0x8c,
 818	0x00, 0x7e, 0x00, 0x71, 0xa5, 0x00, 0x7c, 0x00, 0xe5, 0xc8, 0x00, 0x74, 0x00, 0x91, 0xf4, 0x00,
 819	0x66, 0x00, 0x40, 0x19, 0x01, 0x58, 0x00, 0x0e, 0x28, 0x01, 0x52, 0x00, 0x80, 0x38, 0x01, 0x4a,
 820	0x00
 821};
 822
 823static const ATOM_PPLIB_POWERPLAYTABLE *get_powerplay_table(
 824				     struct pp_hwmgr *hwmgr)
 825{
 826	const void *table_addr = hwmgr->soft_pp_table;
 827	uint8_t frev, crev;
 828	uint16_t size;
 829
 830	if (!table_addr) {
 831		if (hwmgr->chip_id == CHIP_RAVEN) {
 832			table_addr = &soft_dummy_pp_table[0];
 833			hwmgr->soft_pp_table = &soft_dummy_pp_table[0];
 834			hwmgr->soft_pp_table_size = sizeof(soft_dummy_pp_table);
 835		} else {
 836			table_addr = smu_atom_get_data_table(hwmgr->adev,
 837					GetIndexIntoMasterTable(DATA, PowerPlayInfo),
 838					&size, &frev, &crev);
 839			hwmgr->soft_pp_table = table_addr;
 840			hwmgr->soft_pp_table_size = size;
 841		}
 842	}
 843
 844	return (const ATOM_PPLIB_POWERPLAYTABLE *)table_addr;
 845}
 846
 847int pp_tables_get_response_times(struct pp_hwmgr *hwmgr,
 848				uint32_t *vol_rep_time, uint32_t *bb_rep_time)
 849{
 850	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_tab = get_powerplay_table(hwmgr);
 851
 852	PP_ASSERT_WITH_CODE(NULL != powerplay_tab,
 853			    "Missing PowerPlay Table!", return -EINVAL);
 854
 855	*vol_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usVoltageTime);
 856	*bb_rep_time = (uint32_t)le16_to_cpu(powerplay_tab->usBackbiasTime);
 857
 858	return 0;
 859}
 860
 861int pp_tables_get_num_of_entries(struct pp_hwmgr *hwmgr,
 862				     unsigned long *num_of_entries)
 863{
 864	const StateArray *pstate_arrays;
 865	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
 866
 867	if (powerplay_table == NULL)
 868		return -1;
 869
 870	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
 871		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
 872					le16_to_cpu(powerplay_table->usStateArrayOffset));
 873
 874		*num_of_entries = (unsigned long)(pstate_arrays->ucNumEntries);
 875	} else
 876		*num_of_entries = (unsigned long)(powerplay_table->ucNumStates);
 877
 878	return 0;
 879}
 880
 881int pp_tables_get_entry(struct pp_hwmgr *hwmgr,
 882				unsigned long entry_index,
 883				struct pp_power_state *ps,
 884			 pp_tables_hw_clock_info_callback func)
 885{
 886	int i;
 887	const StateArray *pstate_arrays;
 888	const ATOM_PPLIB_STATE_V2 *pstate_entry_v2;
 889	const ATOM_PPLIB_NONCLOCK_INFO *pnon_clock_info;
 890	const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table = get_powerplay_table(hwmgr);
 891	int result = 0;
 892	int res = 0;
 893
 894	const ClockInfoArray *pclock_arrays;
 895
 896	const NonClockInfoArray *pnon_clock_arrays;
 897
 898	const ATOM_PPLIB_STATE *pstate_entry;
 899
 900	if (powerplay_table == NULL)
 901		return -1;
 902
 903	ps->classification.bios_index = entry_index;
 904
 905	if (powerplay_table->sHeader.ucTableFormatRevision >= 6) {
 906		pstate_arrays = (StateArray *)(((unsigned long)powerplay_table) +
 907					le16_to_cpu(powerplay_table->usStateArrayOffset));
 908
 909		if (entry_index > pstate_arrays->ucNumEntries)
 910			return -1;
 911
 912		pstate_entry_v2 = get_state_entry_v2(pstate_arrays, entry_index);
 913		pclock_arrays = (ClockInfoArray *)(((unsigned long)powerplay_table) +
 914					le16_to_cpu(powerplay_table->usClockInfoArrayOffset));
 915
 916		pnon_clock_arrays = (NonClockInfoArray *)(((unsigned long)powerplay_table) +
 917						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset));
 918
 919		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)(pnon_clock_arrays->nonClockInfo) +
 920					(pstate_entry_v2->nonClockInfoIndex * pnon_clock_arrays->ucEntrySize));
 921
 922		result = init_non_clock_fields(hwmgr, ps, pnon_clock_arrays->ucEntrySize, pnon_clock_info);
 923
 924		for (i = 0; i < pstate_entry_v2->ucNumDPMLevels; i++) {
 925			const void *pclock_info = (const void *)(
 926							(unsigned long)(pclock_arrays->clockInfo) +
 927							(pstate_entry_v2->clockInfoIndex[i] * pclock_arrays->ucEntrySize));
 928			res = func(hwmgr, &ps->hardware, i, pclock_info);
 929			if ((0 == result) && (0 != res))
 930				result = res;
 931		}
 932	} else {
 933		if (entry_index > powerplay_table->ucNumStates)
 934			return -1;
 935
 936		pstate_entry = (ATOM_PPLIB_STATE *)((unsigned long)powerplay_table +
 937						    le16_to_cpu(powerplay_table->usStateArrayOffset) +
 938						    entry_index * powerplay_table->ucStateEntrySize);
 939
 940		pnon_clock_info = (ATOM_PPLIB_NONCLOCK_INFO *)((unsigned long)powerplay_table +
 941						le16_to_cpu(powerplay_table->usNonClockInfoArrayOffset) +
 942						pstate_entry->ucNonClockStateIndex *
 943						powerplay_table->ucNonClockSize);
 944
 945		result = init_non_clock_fields(hwmgr, ps,
 946							powerplay_table->ucNonClockSize,
 947							pnon_clock_info);
 948
 949		for (i = 0; i < powerplay_table->ucStateEntrySize-1; i++) {
 950			const void *pclock_info = (const void *)((unsigned long)powerplay_table +
 951						le16_to_cpu(powerplay_table->usClockInfoArrayOffset) +
 952						pstate_entry->ucClockStateIndices[i] *
 953						powerplay_table->ucClockInfoSize);
 954
 955			int res = func(hwmgr, &ps->hardware, i, pclock_info);
 956
 957			if ((0 == result) && (0 != res))
 958					result = res;
 959		}
 960	}
 961
 962	if ((0 == result) && (0 != (ps->classification.flags & PP_StateClassificationFlag_Boot))) {
 963		if (hwmgr->chip_family < AMDGPU_FAMILY_RV)
 964			result = hwmgr->hwmgr_func->patch_boot_state(hwmgr, &(ps->hardware));
 965	}
 966
 967	return result;
 968}
 969
 970static int init_powerplay_tables(
 971			struct pp_hwmgr *hwmgr,
 972			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table
 973)
 974{
 975	return 0;
 976}
 977
 978
 979static int init_thermal_controller(
 980			struct pp_hwmgr *hwmgr,
 981			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
 982{
 983	struct amdgpu_device *adev = hwmgr->adev;
 984
 985	hwmgr->thermal_controller.ucType =
 986			powerplay_table->sThermalController.ucType;
 987	hwmgr->thermal_controller.ucI2cLine =
 988			powerplay_table->sThermalController.ucI2cLine;
 989	hwmgr->thermal_controller.ucI2cAddress =
 990			powerplay_table->sThermalController.ucI2cAddress;
 991
 992	hwmgr->thermal_controller.fanInfo.bNoFan =
 993		(0 != (powerplay_table->sThermalController.ucFanParameters &
 994			ATOM_PP_FANPARAMETERS_NOFAN));
 995
 996	hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution =
 997		powerplay_table->sThermalController.ucFanParameters &
 998		ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
 999
1000	hwmgr->thermal_controller.fanInfo.ulMinRPM
1001		= powerplay_table->sThermalController.ucFanMinRPM * 100UL;
1002	hwmgr->thermal_controller.fanInfo.ulMaxRPM
1003		= powerplay_table->sThermalController.ucFanMaxRPM * 100UL;
1004
1005	set_hw_cap(hwmgr,
1006		   ATOM_PP_THERMALCONTROLLER_NONE != hwmgr->thermal_controller.ucType,
1007		   PHM_PlatformCaps_ThermalController);
1008
1009        if (powerplay_table->usTableSize >= sizeof(ATOM_PPLIB_POWERPLAYTABLE3)) {
1010		const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3 =
1011			(const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1012
1013		if (0 == le16_to_cpu(powerplay_table3->usFanTableOffset)) {
1014			hwmgr->thermal_controller.use_hw_fan_control = 1;
1015			return 0;
1016		} else {
1017			const ATOM_PPLIB_FANTABLE *fan_table =
1018				(const ATOM_PPLIB_FANTABLE *)(((unsigned long)powerplay_table) +
1019							      le16_to_cpu(powerplay_table3->usFanTableOffset));
1020
1021			if (1 <= fan_table->ucFanTableFormat) {
1022				hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst =
1023					fan_table->ucTHyst;
1024				hwmgr->thermal_controller.advanceFanControlParameters.usTMin =
1025					le16_to_cpu(fan_table->usTMin);
1026				hwmgr->thermal_controller.advanceFanControlParameters.usTMed =
1027					le16_to_cpu(fan_table->usTMed);
1028				hwmgr->thermal_controller.advanceFanControlParameters.usTHigh =
1029					le16_to_cpu(fan_table->usTHigh);
1030				hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin =
1031					le16_to_cpu(fan_table->usPWMMin);
1032				hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed =
1033					le16_to_cpu(fan_table->usPWMMed);
1034				hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh =
1035					le16_to_cpu(fan_table->usPWMHigh);
1036				hwmgr->thermal_controller.advanceFanControlParameters.usTMax = 10900;
1037				hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay = 100000;
1038
1039				phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1040					    PHM_PlatformCaps_MicrocodeFanControl);
1041			}
1042
1043			if (2 <= fan_table->ucFanTableFormat) {
1044				const ATOM_PPLIB_FANTABLE2 *fan_table2 =
1045					(const ATOM_PPLIB_FANTABLE2 *)(((unsigned long)powerplay_table) +
1046								       le16_to_cpu(powerplay_table3->usFanTableOffset));
1047				hwmgr->thermal_controller.advanceFanControlParameters.usTMax =
1048					le16_to_cpu(fan_table2->usTMax);
1049			}
1050
1051			if (3 <= fan_table->ucFanTableFormat) {
1052				const ATOM_PPLIB_FANTABLE3 *fan_table3 =
1053					(const ATOM_PPLIB_FANTABLE3 *) (((unsigned long)powerplay_table) +
1054									le16_to_cpu(powerplay_table3->usFanTableOffset));
1055
1056				hwmgr->thermal_controller.advanceFanControlParameters.ucFanControlMode =
1057					fan_table3->ucFanControlMode;
1058
1059				if ((3 == fan_table->ucFanTableFormat) &&
1060				    (0x67B1 == adev->pdev->device))
1061					hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM =
1062						47;
1063				else
1064					hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanPWM =
1065						le16_to_cpu(fan_table3->usFanPWMMax);
1066
1067				hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity =
1068					4836;
1069				hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
1070					le16_to_cpu(fan_table3->usFanOutputSensitivity);
1071			}
1072
1073			if (6 <= fan_table->ucFanTableFormat) {
1074				const ATOM_PPLIB_FANTABLE4 *fan_table4 =
1075					(const ATOM_PPLIB_FANTABLE4 *)(((unsigned long)powerplay_table) +
1076								       le16_to_cpu(powerplay_table3->usFanTableOffset));
1077
1078				phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1079					    PHM_PlatformCaps_FanSpeedInTableIsRPM);
1080
1081				hwmgr->thermal_controller.advanceFanControlParameters.usDefaultMaxFanRPM =
1082					le16_to_cpu(fan_table4->usFanRPMMax);
1083			}
1084
1085			if (7 <= fan_table->ucFanTableFormat) {
1086				const ATOM_PPLIB_FANTABLE5 *fan_table5 =
1087					(const ATOM_PPLIB_FANTABLE5 *)(((unsigned long)powerplay_table) +
1088								       le16_to_cpu(powerplay_table3->usFanTableOffset));
1089
1090				if (0x67A2 == adev->pdev->device ||
1091				    0x67A9 == adev->pdev->device ||
1092				    0x67B9 == adev->pdev->device) {
1093					phm_cap_set(hwmgr->platform_descriptor.platformCaps,
1094						    PHM_PlatformCaps_GeminiRegulatorFanControlSupport);
1095					hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentLow =
1096						le16_to_cpu(fan_table5->usFanCurrentLow);
1097					hwmgr->thermal_controller.advanceFanControlParameters.usFanCurrentHigh =
1098						le16_to_cpu(fan_table5->usFanCurrentHigh);
1099					hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMLow =
1100						le16_to_cpu(fan_table5->usFanRPMLow);
1101					hwmgr->thermal_controller.advanceFanControlParameters.usFanRPMHigh =
1102						le16_to_cpu(fan_table5->usFanRPMHigh);
1103				}
1104			}
1105		}
1106	}
1107
1108	return 0;
1109}
1110
1111static int init_overdrive_limits_V1_4(struct pp_hwmgr *hwmgr,
1112			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1113			const ATOM_FIRMWARE_INFO_V1_4 *fw_info)
1114{
1115	hwmgr->platform_descriptor.overdriveLimit.engineClock =
1116				le32_to_cpu(fw_info->ulASICMaxEngineClock);
1117
1118	hwmgr->platform_descriptor.overdriveLimit.memoryClock =
1119				le32_to_cpu(fw_info->ulASICMaxMemoryClock);
1120
1121	hwmgr->platform_descriptor.maxOverdriveVDDC =
1122		le32_to_cpu(fw_info->ul3DAccelerationEngineClock) & 0x7FF;
1123
1124	hwmgr->platform_descriptor.minOverdriveVDDC =
1125			   le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1126
1127	hwmgr->platform_descriptor.maxOverdriveVDDC =
1128			   le16_to_cpu(fw_info->usBootUpVDDCVoltage);
1129
1130	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1131	return 0;
1132}
1133
1134static int init_overdrive_limits_V2_1(struct pp_hwmgr *hwmgr,
1135			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table,
1136			const ATOM_FIRMWARE_INFO_V2_1 *fw_info)
1137{
1138	const ATOM_PPLIB_POWERPLAYTABLE3 *powerplay_table3;
1139	const ATOM_PPLIB_EXTENDEDHEADER *header;
1140
1141	if (le16_to_cpu(powerplay_table->usTableSize) <
1142	    sizeof(ATOM_PPLIB_POWERPLAYTABLE3))
1143		return 0;
1144
1145	powerplay_table3 = (const ATOM_PPLIB_POWERPLAYTABLE3 *)powerplay_table;
1146
1147	if (0 == powerplay_table3->usExtendendedHeaderOffset)
1148		return 0;
1149
1150	header = (ATOM_PPLIB_EXTENDEDHEADER *)(((unsigned long) powerplay_table) +
1151			le16_to_cpu(powerplay_table3->usExtendendedHeaderOffset));
1152
1153	hwmgr->platform_descriptor.overdriveLimit.engineClock = le32_to_cpu(header->ulMaxEngineClock);
1154	hwmgr->platform_descriptor.overdriveLimit.memoryClock = le32_to_cpu(header->ulMaxMemoryClock);
1155
1156
1157	hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1158	hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1159	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1160
1161	return 0;
1162}
1163
1164static int init_overdrive_limits(struct pp_hwmgr *hwmgr,
1165			const ATOM_PPLIB_POWERPLAYTABLE *powerplay_table)
1166{
1167	int result = 0;
1168	uint8_t frev, crev;
1169	uint16_t size;
1170
1171	const ATOM_COMMON_TABLE_HEADER *fw_info = NULL;
1172
1173	hwmgr->platform_descriptor.overdriveLimit.engineClock = 0;
1174	hwmgr->platform_descriptor.overdriveLimit.memoryClock = 0;
1175	hwmgr->platform_descriptor.minOverdriveVDDC = 0;
1176	hwmgr->platform_descriptor.maxOverdriveVDDC = 0;
1177	hwmgr->platform_descriptor.overdriveVDDCStep = 0;
1178
1179	if (hwmgr->chip_id == CHIP_RAVEN)
1180		return 0;
1181
1182	/* We assume here that fw_info is unchanged if this call fails.*/
1183	fw_info = smu_atom_get_data_table(hwmgr->adev,
1184			 GetIndexIntoMasterTable(DATA, FirmwareInfo),
1185			 &size, &frev, &crev);
1186	PP_ASSERT_WITH_CODE(fw_info != NULL,
1187			    "Missing firmware info!", return -EINVAL);
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
~/ Read-only file preview.