File Index
Files and directories
Sign in
FILE

legacy_dpm.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/amd/pm/legacy-dpm/legacy_dpm.c C
   1/*
   2 * Copyright 2021 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 "amdgpu.h"
  24#include "amdgpu_i2c.h"
  25#include "amdgpu_atombios.h"
  26#include "atom.h"
  27#include "amd_pcie.h"
  28#include "legacy_dpm.h"
  29#include "amdgpu_dpm_internal.h"
  30#include "amdgpu_display.h"
  31
  32#define amdgpu_dpm_pre_set_power_state(adev) \
  33		((adev)->powerplay.pp_funcs->pre_set_power_state((adev)->powerplay.pp_handle))
  34
  35#define amdgpu_dpm_post_set_power_state(adev) \
  36		((adev)->powerplay.pp_funcs->post_set_power_state((adev)->powerplay.pp_handle))
  37
  38#define amdgpu_dpm_display_configuration_changed(adev) \
  39		((adev)->powerplay.pp_funcs->display_configuration_changed((adev)->powerplay.pp_handle))
  40
  41#define amdgpu_dpm_print_power_state(adev, ps) \
  42		((adev)->powerplay.pp_funcs->print_power_state((adev)->powerplay.pp_handle, (ps)))
  43
  44#define amdgpu_dpm_vblank_too_short(adev) \
  45		((adev)->powerplay.pp_funcs->vblank_too_short((adev)->powerplay.pp_handle))
  46
  47#define amdgpu_dpm_check_state_equal(adev, cps, rps, equal) \
  48		((adev)->powerplay.pp_funcs->check_state_equal((adev)->powerplay.pp_handle, (cps), (rps), (equal)))
  49
  50void amdgpu_dpm_dbg_print_class_info(struct amdgpu_device *adev, u32 class, u32 class2)
  51{
  52	const char *s;
  53
  54	switch (class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) {
  55	case ATOM_PPLIB_CLASSIFICATION_UI_NONE:
  56	default:
  57		s = "none";
  58		break;
  59	case ATOM_PPLIB_CLASSIFICATION_UI_BATTERY:
  60		s = "battery";
  61		break;
  62	case ATOM_PPLIB_CLASSIFICATION_UI_BALANCED:
  63		s = "balanced";
  64		break;
  65	case ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE:
  66		s = "performance";
  67		break;
  68	}
  69	drm_dbg(adev_to_drm(adev), "\tui class: %s\n", s);
  70	if (((class & ~ATOM_PPLIB_CLASSIFICATION_UI_MASK) == 0) &&
  71	    (class2 == 0))
  72		drm_dbg(adev_to_drm(adev), "\tinternal class: none\n");
  73	else
  74		drm_dbg(adev_to_drm(adev), "\tinternal class: %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
  75			(class & ATOM_PPLIB_CLASSIFICATION_BOOT) ? " boot" : "",
  76			(class & ATOM_PPLIB_CLASSIFICATION_THERMAL) ? " thermal" : "",
  77			(class & ATOM_PPLIB_CLASSIFICATION_LIMITEDPOWERSOURCE) ? " limited_pwr" : "",
  78			(class & ATOM_PPLIB_CLASSIFICATION_REST) ? " rest" : "",
  79			(class & ATOM_PPLIB_CLASSIFICATION_FORCED) ? " forced" : "",
  80			(class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE) ? " 3d_perf" : "",
  81			(class & ATOM_PPLIB_CLASSIFICATION_OVERDRIVETEMPLATE) ? " ovrdrv" : "",
  82			(class & ATOM_PPLIB_CLASSIFICATION_UVDSTATE) ? " uvd" : "",
  83			(class & ATOM_PPLIB_CLASSIFICATION_3DLOW) ? " 3d_low" : "",
  84			(class & ATOM_PPLIB_CLASSIFICATION_ACPI) ? " acpi" : "",
  85			(class & ATOM_PPLIB_CLASSIFICATION_HD2STATE) ? " uvd_hd2" : "",
  86			(class & ATOM_PPLIB_CLASSIFICATION_HDSTATE) ? " uvd_hd" : "",
  87			(class & ATOM_PPLIB_CLASSIFICATION_SDSTATE) ? " uvd_sd" : "",
  88			(class2 & ATOM_PPLIB_CLASSIFICATION2_LIMITEDPOWERSOURCE_2) ? " limited_pwr2" : "",
  89			(class2 & ATOM_PPLIB_CLASSIFICATION2_ULV) ? " ulv" : "",
  90			(class2 & ATOM_PPLIB_CLASSIFICATION2_MVC) ? " uvd_mvc" : "");
  91}
  92
  93void amdgpu_dpm_dbg_print_cap_info(struct amdgpu_device *adev, u32 caps)
  94{
  95	drm_dbg(adev_to_drm(adev), "\tcaps: %s%s%s\n",
  96		(caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) ? " single_disp" : "",
  97		(caps & ATOM_PPLIB_SUPPORTS_VIDEO_PLAYBACK) ? " video" : "",
  98		(caps & ATOM_PPLIB_DISALLOW_ON_DC) ? " no_dc" : "");
  99}
 100
 101void amdgpu_dpm_dbg_print_ps_status(struct amdgpu_device *adev,
 102				struct amdgpu_ps *rps)
 103{
 104	drm_dbg(adev_to_drm(adev), "\tstatus:%s%s%s\n",
 105		rps == adev->pm.dpm.current_ps ? " c" : "",
 106		rps == adev->pm.dpm.requested_ps ? " r" : "",
 107		rps == adev->pm.dpm.boot_ps ? " b" : "");
 108}
 109
 110void amdgpu_pm_print_power_states(struct amdgpu_device *adev)
 111{
 112	int i;
 113
 114	if (adev->powerplay.pp_funcs->print_power_state == NULL)
 115		return;
 116
 117	for (i = 0; i < adev->pm.dpm.num_ps; i++)
 118		amdgpu_dpm_print_power_state(adev, &adev->pm.dpm.ps[i]);
 119
 120}
 121
 122union power_info {
 123	struct _ATOM_POWERPLAY_INFO info;
 124	struct _ATOM_POWERPLAY_INFO_V2 info_2;
 125	struct _ATOM_POWERPLAY_INFO_V3 info_3;
 126	struct _ATOM_PPLIB_POWERPLAYTABLE pplib;
 127	struct _ATOM_PPLIB_POWERPLAYTABLE2 pplib2;
 128	struct _ATOM_PPLIB_POWERPLAYTABLE3 pplib3;
 129	struct _ATOM_PPLIB_POWERPLAYTABLE4 pplib4;
 130	struct _ATOM_PPLIB_POWERPLAYTABLE5 pplib5;
 131};
 132
 133int amdgpu_get_platform_caps(struct amdgpu_device *adev)
 134{
 135	struct amdgpu_mode_info *mode_info = &adev->mode_info;
 136	union power_info *power_info;
 137	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
 138	u16 data_offset;
 139	u8 frev, crev;
 140
 141	if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
 142				   &frev, &crev, &data_offset))
 143		return -EINVAL;
 144	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
 145
 146	adev->pm.dpm.platform_caps = le32_to_cpu(power_info->pplib.ulPlatformCaps);
 147	adev->pm.dpm.backbias_response_time = le16_to_cpu(power_info->pplib.usBackbiasTime);
 148	adev->pm.dpm.voltage_response_time = le16_to_cpu(power_info->pplib.usVoltageTime);
 149
 150	return 0;
 151}
 152
 153union fan_info {
 154	struct _ATOM_PPLIB_FANTABLE fan;
 155	struct _ATOM_PPLIB_FANTABLE2 fan2;
 156	struct _ATOM_PPLIB_FANTABLE3 fan3;
 157};
 158
 159static int amdgpu_parse_clk_voltage_dep_table(struct amdgpu_clock_voltage_dependency_table *amdgpu_table,
 160					      ATOM_PPLIB_Clock_Voltage_Dependency_Table *atom_table)
 161{
 162	u32 size = atom_table->ucNumEntries *
 163		sizeof(struct amdgpu_clock_voltage_dependency_entry);
 164	int i;
 165	ATOM_PPLIB_Clock_Voltage_Dependency_Record *entry;
 166
 167	amdgpu_table->entries = kzalloc(size, GFP_KERNEL);
 168	if (!amdgpu_table->entries)
 169		return -ENOMEM;
 170
 171	entry = &atom_table->entries[0];
 172	for (i = 0; i < atom_table->ucNumEntries; i++) {
 173		amdgpu_table->entries[i].clk = le16_to_cpu(entry->usClockLow) |
 174			(entry->ucClockHigh << 16);
 175		amdgpu_table->entries[i].v = le16_to_cpu(entry->usVoltage);
 176		entry = (ATOM_PPLIB_Clock_Voltage_Dependency_Record *)
 177			((u8 *)entry + sizeof(ATOM_PPLIB_Clock_Voltage_Dependency_Record));
 178	}
 179	amdgpu_table->count = atom_table->ucNumEntries;
 180
 181	return 0;
 182}
 183
 184/* sizeof(ATOM_PPLIB_EXTENDEDHEADER) */
 185#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2 12
 186#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3 14
 187#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4 16
 188#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5 18
 189#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6 20
 190#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7 22
 191#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8 24
 192#define SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V9 26
 193
 194int amdgpu_parse_extended_power_table(struct amdgpu_device *adev)
 195{
 196	struct amdgpu_mode_info *mode_info = &adev->mode_info;
 197	union power_info *power_info;
 198	union fan_info *fan_info;
 199	ATOM_PPLIB_Clock_Voltage_Dependency_Table *dep_table;
 200	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
 201	u16 data_offset;
 202	u8 frev, crev;
 203	int ret, i;
 204
 205	if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
 206				   &frev, &crev, &data_offset))
 207		return -EINVAL;
 208	power_info = (union power_info *)(mode_info->atom_context->bios + data_offset);
 209
 210	/* fan table */
 211	if (le16_to_cpu(power_info->pplib.usTableSize) >=
 212	    sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
 213		if (power_info->pplib3.usFanTableOffset) {
 214			fan_info = (union fan_info *)(mode_info->atom_context->bios + data_offset +
 215						      le16_to_cpu(power_info->pplib3.usFanTableOffset));
 216			adev->pm.dpm.fan.t_hyst = fan_info->fan.ucTHyst;
 217			adev->pm.dpm.fan.t_min = le16_to_cpu(fan_info->fan.usTMin);
 218			adev->pm.dpm.fan.t_med = le16_to_cpu(fan_info->fan.usTMed);
 219			adev->pm.dpm.fan.t_high = le16_to_cpu(fan_info->fan.usTHigh);
 220			adev->pm.dpm.fan.pwm_min = le16_to_cpu(fan_info->fan.usPWMMin);
 221			adev->pm.dpm.fan.pwm_med = le16_to_cpu(fan_info->fan.usPWMMed);
 222			adev->pm.dpm.fan.pwm_high = le16_to_cpu(fan_info->fan.usPWMHigh);
 223			if (fan_info->fan.ucFanTableFormat >= 2)
 224				adev->pm.dpm.fan.t_max = le16_to_cpu(fan_info->fan2.usTMax);
 225			else
 226				adev->pm.dpm.fan.t_max = 10900;
 227			adev->pm.dpm.fan.cycle_delay = 100000;
 228			if (fan_info->fan.ucFanTableFormat >= 3) {
 229				adev->pm.dpm.fan.control_mode = fan_info->fan3.ucFanControlMode;
 230				adev->pm.dpm.fan.default_max_fan_pwm =
 231					le16_to_cpu(fan_info->fan3.usFanPWMMax);
 232				adev->pm.dpm.fan.default_fan_output_sensitivity = 4836;
 233				adev->pm.dpm.fan.fan_output_sensitivity =
 234					le16_to_cpu(fan_info->fan3.usFanOutputSensitivity);
 235			}
 236			adev->pm.dpm.fan.ucode_fan_control = true;
 237		}
 238	}
 239
 240	/* clock dependancy tables, shedding tables */
 241	if (le16_to_cpu(power_info->pplib.usTableSize) >=
 242	    sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE4)) {
 243		if (power_info->pplib4.usVddcDependencyOnSCLKOffset) {
 244			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
 245				(mode_info->atom_context->bios + data_offset +
 246				 le16_to_cpu(power_info->pplib4.usVddcDependencyOnSCLKOffset));
 247			ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_sclk,
 248								 dep_table);
 249			if (ret)
 250				return ret;
 251		}
 252		if (power_info->pplib4.usVddciDependencyOnMCLKOffset) {
 253			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
 254				(mode_info->atom_context->bios + data_offset +
 255				 le16_to_cpu(power_info->pplib4.usVddciDependencyOnMCLKOffset));
 256			ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddci_dependency_on_mclk,
 257								 dep_table);
 258			if (ret)
 259				return ret;
 260		}
 261		if (power_info->pplib4.usVddcDependencyOnMCLKOffset) {
 262			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
 263				(mode_info->atom_context->bios + data_offset +
 264				 le16_to_cpu(power_info->pplib4.usVddcDependencyOnMCLKOffset));
 265			ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.vddc_dependency_on_mclk,
 266								 dep_table);
 267			if (ret)
 268				return ret;
 269		}
 270		if (power_info->pplib4.usMvddDependencyOnMCLKOffset) {
 271			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
 272				(mode_info->atom_context->bios + data_offset +
 273				 le16_to_cpu(power_info->pplib4.usMvddDependencyOnMCLKOffset));
 274			ret = amdgpu_parse_clk_voltage_dep_table(&adev->pm.dpm.dyn_state.mvdd_dependency_on_mclk,
 275								 dep_table);
 276			if (ret)
 277				return ret;
 278		}
 279		if (power_info->pplib4.usMaxClockVoltageOnDCOffset) {
 280			ATOM_PPLIB_Clock_Voltage_Limit_Table *clk_v =
 281				(ATOM_PPLIB_Clock_Voltage_Limit_Table *)
 282				(mode_info->atom_context->bios + data_offset +
 283				 le16_to_cpu(power_info->pplib4.usMaxClockVoltageOnDCOffset));
 284			if (clk_v->ucNumEntries) {
 285				adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.sclk =
 286					le16_to_cpu(clk_v->entries[0].usSclkLow) |
 287					(clk_v->entries[0].ucSclkHigh << 16);
 288				adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.mclk =
 289					le16_to_cpu(clk_v->entries[0].usMclkLow) |
 290					(clk_v->entries[0].ucMclkHigh << 16);
 291				adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddc =
 292					le16_to_cpu(clk_v->entries[0].usVddc);
 293				adev->pm.dpm.dyn_state.max_clock_voltage_on_dc.vddci =
 294					le16_to_cpu(clk_v->entries[0].usVddci);
 295			}
 296		}
 297		if (power_info->pplib4.usVddcPhaseShedLimitsTableOffset) {
 298			ATOM_PPLIB_PhaseSheddingLimits_Table *psl =
 299				(ATOM_PPLIB_PhaseSheddingLimits_Table *)
 300				(mode_info->atom_context->bios + data_offset +
 301				 le16_to_cpu(power_info->pplib4.usVddcPhaseShedLimitsTableOffset));
 302			ATOM_PPLIB_PhaseSheddingLimits_Record *entry;
 303
 304			adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries =
 305				kcalloc(psl->ucNumEntries,
 306					sizeof(struct amdgpu_phase_shedding_limits_entry),
 307					GFP_KERNEL);
 308			if (!adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries)
 309				return -ENOMEM;
 310
 311			entry = &psl->entries[0];
 312			for (i = 0; i < psl->ucNumEntries; i++) {
 313				adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].sclk =
 314					le16_to_cpu(entry->usSclkLow) | (entry->ucSclkHigh << 16);
 315				adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].mclk =
 316					le16_to_cpu(entry->usMclkLow) | (entry->ucMclkHigh << 16);
 317				adev->pm.dpm.dyn_state.phase_shedding_limits_table.entries[i].voltage =
 318					le16_to_cpu(entry->usVoltage);
 319				entry = (ATOM_PPLIB_PhaseSheddingLimits_Record *)
 320					((u8 *)entry + sizeof(ATOM_PPLIB_PhaseSheddingLimits_Record));
 321			}
 322			adev->pm.dpm.dyn_state.phase_shedding_limits_table.count =
 323				psl->ucNumEntries;
 324		}
 325	}
 326
 327	/* cac data */
 328	if (le16_to_cpu(power_info->pplib.usTableSize) >=
 329	    sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE5)) {
 330		adev->pm.dpm.tdp_limit = le32_to_cpu(power_info->pplib5.ulTDPLimit);
 331		adev->pm.dpm.near_tdp_limit = le32_to_cpu(power_info->pplib5.ulNearTDPLimit);
 332		adev->pm.dpm.near_tdp_limit_adjusted = adev->pm.dpm.near_tdp_limit;
 333		adev->pm.dpm.tdp_od_limit = le16_to_cpu(power_info->pplib5.usTDPODLimit);
 334		if (adev->pm.dpm.tdp_od_limit)
 335			adev->pm.dpm.power_control = true;
 336		else
 337			adev->pm.dpm.power_control = false;
 338		adev->pm.dpm.tdp_adjustment = 0;
 339		adev->pm.dpm.sq_ramping_threshold = le32_to_cpu(power_info->pplib5.ulSQRampingThreshold);
 340		adev->pm.dpm.cac_leakage = le32_to_cpu(power_info->pplib5.ulCACLeakage);
 341		adev->pm.dpm.load_line_slope = le16_to_cpu(power_info->pplib5.usLoadLineSlope);
 342		if (power_info->pplib5.usCACLeakageTableOffset) {
 343			ATOM_PPLIB_CAC_Leakage_Table *cac_table =
 344				(ATOM_PPLIB_CAC_Leakage_Table *)
 345				(mode_info->atom_context->bios + data_offset +
 346				 le16_to_cpu(power_info->pplib5.usCACLeakageTableOffset));
 347			ATOM_PPLIB_CAC_Leakage_Record *entry;
 348			u32 size = cac_table->ucNumEntries * sizeof(struct amdgpu_cac_leakage_table);
 349			adev->pm.dpm.dyn_state.cac_leakage_table.entries = kzalloc(size, GFP_KERNEL);
 350			if (!adev->pm.dpm.dyn_state.cac_leakage_table.entries)
 351				return -ENOMEM;
 352			entry = &cac_table->entries[0];
 353			for (i = 0; i < cac_table->ucNumEntries; i++) {
 354				if (adev->pm.dpm.platform_caps & ATOM_PP_PLATFORM_CAP_EVV) {
 355					adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc1 =
 356						le16_to_cpu(entry->usVddc1);
 357					adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc2 =
 358						le16_to_cpu(entry->usVddc2);
 359					adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc3 =
 360						le16_to_cpu(entry->usVddc3);
 361				} else {
 362					adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].vddc =
 363						le16_to_cpu(entry->usVddc);
 364					adev->pm.dpm.dyn_state.cac_leakage_table.entries[i].leakage =
 365						le32_to_cpu(entry->ulLeakageValue);
 366				}
 367				entry = (ATOM_PPLIB_CAC_Leakage_Record *)
 368					((u8 *)entry + sizeof(ATOM_PPLIB_CAC_Leakage_Record));
 369			}
 370			adev->pm.dpm.dyn_state.cac_leakage_table.count = cac_table->ucNumEntries;
 371		}
 372	}
 373
 374	/* ext tables */
 375	if (le16_to_cpu(power_info->pplib.usTableSize) >=
 376	    sizeof(struct _ATOM_PPLIB_POWERPLAYTABLE3)) {
 377		ATOM_PPLIB_EXTENDEDHEADER *ext_hdr = (ATOM_PPLIB_EXTENDEDHEADER *)
 378			(mode_info->atom_context->bios + data_offset +
 379			 le16_to_cpu(power_info->pplib3.usExtendendedHeaderOffset));
 380		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V2) &&
 381			ext_hdr->usVCETableOffset) {
 382			VCEClockInfoArray *array = (VCEClockInfoArray *)
 383				(mode_info->atom_context->bios + data_offset +
 384				 le16_to_cpu(ext_hdr->usVCETableOffset) + 1);
 385			ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *limits =
 386				(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Table *)
 387				(mode_info->atom_context->bios + data_offset +
 388				 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
 389				 1 + array->ucNumEntries * sizeof(VCEClockInfo));
 390			ATOM_PPLIB_VCE_State_Table *states =
 391				(ATOM_PPLIB_VCE_State_Table *)
 392				(mode_info->atom_context->bios + data_offset +
 393				 le16_to_cpu(ext_hdr->usVCETableOffset) + 1 +
 394				 1 + (array->ucNumEntries * sizeof (VCEClockInfo)) +
 395				 1 + (limits->numEntries * sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record)));
 396			ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *entry;
 397			ATOM_PPLIB_VCE_State_Record *state_entry;
 398			VCEClockInfo *vce_clk;
 399			u32 size = limits->numEntries *
 400				sizeof(struct amdgpu_vce_clock_voltage_dependency_entry);
 401			adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries =
 402				kzalloc(size, GFP_KERNEL);
 403			if (!adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries)
 404				return -ENOMEM;
 405			adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.count =
 406				limits->numEntries;
 407			entry = &limits->entries[0];
 408			state_entry = &states->entries[0];
 409			for (i = 0; i < limits->numEntries; i++) {
 410				vce_clk = (VCEClockInfo *)
 411					((u8 *)&array->entries[0] +
 412					 (entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
 413				adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].evclk =
 414					le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
 415				adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].ecclk =
 416					le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
 417				adev->pm.dpm.dyn_state.vce_clock_voltage_dependency_table.entries[i].v =
 418					le16_to_cpu(entry->usVoltage);
 419				entry = (ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record *)
 420					((u8 *)entry + sizeof(ATOM_PPLIB_VCE_Clock_Voltage_Limit_Record));
 421			}
 422			adev->pm.dpm.num_of_vce_states =
 423					states->numEntries > AMD_MAX_VCE_LEVELS ?
 424					AMD_MAX_VCE_LEVELS : states->numEntries;
 425			for (i = 0; i < adev->pm.dpm.num_of_vce_states; i++) {
 426				vce_clk = (VCEClockInfo *)
 427					((u8 *)&array->entries[0] +
 428					 (state_entry->ucVCEClockInfoIndex * sizeof(VCEClockInfo)));
 429				adev->pm.dpm.vce_states[i].evclk =
 430					le16_to_cpu(vce_clk->usEVClkLow) | (vce_clk->ucEVClkHigh << 16);
 431				adev->pm.dpm.vce_states[i].ecclk =
 432					le16_to_cpu(vce_clk->usECClkLow) | (vce_clk->ucECClkHigh << 16);
 433				adev->pm.dpm.vce_states[i].clk_idx =
 434					state_entry->ucClockInfoIndex & 0x3f;
 435				adev->pm.dpm.vce_states[i].pstate =
 436					(state_entry->ucClockInfoIndex & 0xc0) >> 6;
 437				state_entry = (ATOM_PPLIB_VCE_State_Record *)
 438					((u8 *)state_entry + sizeof(ATOM_PPLIB_VCE_State_Record));
 439			}
 440		}
 441		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V3) &&
 442			ext_hdr->usUVDTableOffset) {
 443			UVDClockInfoArray *array = (UVDClockInfoArray *)
 444				(mode_info->atom_context->bios + data_offset +
 445				 le16_to_cpu(ext_hdr->usUVDTableOffset) + 1);
 446			ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *limits =
 447				(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Table *)
 448				(mode_info->atom_context->bios + data_offset +
 449				 le16_to_cpu(ext_hdr->usUVDTableOffset) + 1 +
 450				 1 + (array->ucNumEntries * sizeof (UVDClockInfo)));
 451			ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *entry;
 452			u32 size = limits->numEntries *
 453				sizeof(struct amdgpu_uvd_clock_voltage_dependency_entry);
 454			adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries =
 455				kzalloc(size, GFP_KERNEL);
 456			if (!adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries)
 457				return -ENOMEM;
 458			adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.count =
 459				limits->numEntries;
 460			entry = &limits->entries[0];
 461			for (i = 0; i < limits->numEntries; i++) {
 462				UVDClockInfo *uvd_clk = (UVDClockInfo *)
 463					((u8 *)&array->entries[0] +
 464					 (entry->ucUVDClockInfoIndex * sizeof(UVDClockInfo)));
 465				adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].vclk =
 466					le16_to_cpu(uvd_clk->usVClkLow) | (uvd_clk->ucVClkHigh << 16);
 467				adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].dclk =
 468					le16_to_cpu(uvd_clk->usDClkLow) | (uvd_clk->ucDClkHigh << 16);
 469				adev->pm.dpm.dyn_state.uvd_clock_voltage_dependency_table.entries[i].v =
 470					le16_to_cpu(entry->usVoltage);
 471				entry = (ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record *)
 472					((u8 *)entry + sizeof(ATOM_PPLIB_UVD_Clock_Voltage_Limit_Record));
 473			}
 474		}
 475		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V4) &&
 476			ext_hdr->usSAMUTableOffset) {
 477			ATOM_PPLIB_SAMClk_Voltage_Limit_Table *limits =
 478				(ATOM_PPLIB_SAMClk_Voltage_Limit_Table *)
 479				(mode_info->atom_context->bios + data_offset +
 480				 le16_to_cpu(ext_hdr->usSAMUTableOffset) + 1);
 481			ATOM_PPLIB_SAMClk_Voltage_Limit_Record *entry;
 482			u32 size = limits->numEntries *
 483				sizeof(struct amdgpu_clock_voltage_dependency_entry);
 484			adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries =
 485				kzalloc(size, GFP_KERNEL);
 486			if (!adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries)
 487				return -ENOMEM;
 488			adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.count =
 489				limits->numEntries;
 490			entry = &limits->entries[0];
 491			for (i = 0; i < limits->numEntries; i++) {
 492				adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].clk =
 493					le16_to_cpu(entry->usSAMClockLow) | (entry->ucSAMClockHigh << 16);
 494				adev->pm.dpm.dyn_state.samu_clock_voltage_dependency_table.entries[i].v =
 495					le16_to_cpu(entry->usVoltage);
 496				entry = (ATOM_PPLIB_SAMClk_Voltage_Limit_Record *)
 497					((u8 *)entry + sizeof(ATOM_PPLIB_SAMClk_Voltage_Limit_Record));
 498			}
 499		}
 500		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V5) &&
 501		    ext_hdr->usPPMTableOffset) {
 502			ATOM_PPLIB_PPM_Table *ppm = (ATOM_PPLIB_PPM_Table *)
 503				(mode_info->atom_context->bios + data_offset +
 504				 le16_to_cpu(ext_hdr->usPPMTableOffset));
 505			adev->pm.dpm.dyn_state.ppm_table =
 506				kzalloc(sizeof(struct amdgpu_ppm_table), GFP_KERNEL);
 507			if (!adev->pm.dpm.dyn_state.ppm_table)
 508				return -ENOMEM;
 509			adev->pm.dpm.dyn_state.ppm_table->ppm_design = ppm->ucPpmDesign;
 510			adev->pm.dpm.dyn_state.ppm_table->cpu_core_number =
 511				le16_to_cpu(ppm->usCpuCoreNumber);
 512			adev->pm.dpm.dyn_state.ppm_table->platform_tdp =
 513				le32_to_cpu(ppm->ulPlatformTDP);
 514			adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdp =
 515				le32_to_cpu(ppm->ulSmallACPlatformTDP);
 516			adev->pm.dpm.dyn_state.ppm_table->platform_tdc =
 517				le32_to_cpu(ppm->ulPlatformTDC);
 518			adev->pm.dpm.dyn_state.ppm_table->small_ac_platform_tdc =
 519				le32_to_cpu(ppm->ulSmallACPlatformTDC);
 520			adev->pm.dpm.dyn_state.ppm_table->apu_tdp =
 521				le32_to_cpu(ppm->ulApuTDP);
 522			adev->pm.dpm.dyn_state.ppm_table->dgpu_tdp =
 523				le32_to_cpu(ppm->ulDGpuTDP);
 524			adev->pm.dpm.dyn_state.ppm_table->dgpu_ulv_power =
 525				le32_to_cpu(ppm->ulDGpuUlvPower);
 526			adev->pm.dpm.dyn_state.ppm_table->tj_max =
 527				le32_to_cpu(ppm->ulTjmax);
 528		}
 529		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V6) &&
 530			ext_hdr->usACPTableOffset) {
 531			ATOM_PPLIB_ACPClk_Voltage_Limit_Table *limits =
 532				(ATOM_PPLIB_ACPClk_Voltage_Limit_Table *)
 533				(mode_info->atom_context->bios + data_offset +
 534				 le16_to_cpu(ext_hdr->usACPTableOffset) + 1);
 535			ATOM_PPLIB_ACPClk_Voltage_Limit_Record *entry;
 536			u32 size = limits->numEntries *
 537				sizeof(struct amdgpu_clock_voltage_dependency_entry);
 538			adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries =
 539				kzalloc(size, GFP_KERNEL);
 540			if (!adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries)
 541				return -ENOMEM;
 542			adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.count =
 543				limits->numEntries;
 544			entry = &limits->entries[0];
 545			for (i = 0; i < limits->numEntries; i++) {
 546				adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].clk =
 547					le16_to_cpu(entry->usACPClockLow) | (entry->ucACPClockHigh << 16);
 548				adev->pm.dpm.dyn_state.acp_clock_voltage_dependency_table.entries[i].v =
 549					le16_to_cpu(entry->usVoltage);
 550				entry = (ATOM_PPLIB_ACPClk_Voltage_Limit_Record *)
 551					((u8 *)entry + sizeof(ATOM_PPLIB_ACPClk_Voltage_Limit_Record));
 552			}
 553		}
 554		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V7) &&
 555			ext_hdr->usPowerTuneTableOffset) {
 556			u8 rev = *(u8 *)(mode_info->atom_context->bios + data_offset +
 557					 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
 558			ATOM_PowerTune_Table *pt;
 559			adev->pm.dpm.dyn_state.cac_tdp_table =
 560				kzalloc(sizeof(struct amdgpu_cac_tdp_table), GFP_KERNEL);
 561			if (!adev->pm.dpm.dyn_state.cac_tdp_table)
 562				return -ENOMEM;
 563			if (rev > 0) {
 564				ATOM_PPLIB_POWERTUNE_Table_V1 *ppt = (ATOM_PPLIB_POWERTUNE_Table_V1 *)
 565					(mode_info->atom_context->bios + data_offset +
 566					 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
 567				adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit =
 568					ppt->usMaximumPowerDeliveryLimit;
 569				pt = &ppt->power_tune_table;
 570			} else {
 571				ATOM_PPLIB_POWERTUNE_Table *ppt = (ATOM_PPLIB_POWERTUNE_Table *)
 572					(mode_info->atom_context->bios + data_offset +
 573					 le16_to_cpu(ext_hdr->usPowerTuneTableOffset));
 574				adev->pm.dpm.dyn_state.cac_tdp_table->maximum_power_delivery_limit = 255;
 575				pt = &ppt->power_tune_table;
 576			}
 577			adev->pm.dpm.dyn_state.cac_tdp_table->tdp = le16_to_cpu(pt->usTDP);
 578			adev->pm.dpm.dyn_state.cac_tdp_table->configurable_tdp =
 579				le16_to_cpu(pt->usConfigurableTDP);
 580			adev->pm.dpm.dyn_state.cac_tdp_table->tdc = le16_to_cpu(pt->usTDC);
 581			adev->pm.dpm.dyn_state.cac_tdp_table->battery_power_limit =
 582				le16_to_cpu(pt->usBatteryPowerLimit);
 583			adev->pm.dpm.dyn_state.cac_tdp_table->small_power_limit =
 584				le16_to_cpu(pt->usSmallPowerLimit);
 585			adev->pm.dpm.dyn_state.cac_tdp_table->low_cac_leakage =
 586				le16_to_cpu(pt->usLowCACLeakage);
 587			adev->pm.dpm.dyn_state.cac_tdp_table->high_cac_leakage =
 588				le16_to_cpu(pt->usHighCACLeakage);
 589		}
 590		if ((le16_to_cpu(ext_hdr->usSize) >= SIZE_OF_ATOM_PPLIB_EXTENDEDHEADER_V8) &&
 591				ext_hdr->usSclkVddgfxTableOffset) {
 592			dep_table = (ATOM_PPLIB_Clock_Voltage_Dependency_Table *)
 593				(mode_info->atom_context->bios + data_offset +
 594				 le16_to_cpu(ext_hdr->usSclkVddgfxTableOffset));
 595			ret = amdgpu_parse_clk_voltage_dep_table(
 596					&adev->pm.dpm.dyn_state.vddgfx_dependency_on_sclk,
 597					dep_table);
 598			if (ret)
 599				return ret;
 600		}
 601	}
 602
 603	return 0;
 604}
 605
 606void amdgpu_free_extended_power_table(struct amdgpu_device *adev)
 607{
 608	struct amdgpu_dpm_dynamic_state *dyn_state = &adev->pm.dpm.dyn_state;
 609
 610	kfree(dyn_state->vddc_dependency_on_sclk.entries);
 611	kfree(dyn_state->vddci_dependency_on_mclk.entries);
 612	kfree(dyn_state->vddc_dependency_on_mclk.entries);
 613	kfree(dyn_state->mvdd_dependency_on_mclk.entries);
 614	kfree(dyn_state->cac_leakage_table.entries);
 615	kfree(dyn_state->phase_shedding_limits_table.entries);
 616	kfree(dyn_state->ppm_table);
 617	kfree(dyn_state->cac_tdp_table);
 618	kfree(dyn_state->vce_clock_voltage_dependency_table.entries);
 619	kfree(dyn_state->uvd_clock_voltage_dependency_table.entries);
 620	kfree(dyn_state->samu_clock_voltage_dependency_table.entries);
 621	kfree(dyn_state->acp_clock_voltage_dependency_table.entries);
 622	kfree(dyn_state->vddgfx_dependency_on_sclk.entries);
 623}
 624
 625static const char *pp_lib_thermal_controller_names[] = {
 626	"NONE",
 627	"lm63",
 628	"adm1032",
 629	"adm1030",
 630	"max6649",
 631	"lm64",
 632	"f75375",
 633	"RV6xx",
 634	"RV770",
 635	"adt7473",
 636	"NONE",
 637	"External GPIO",
 638	"Evergreen",
 639	"emc2103",
 640	"Sumo",
 641	"Northern Islands",
 642	"Southern Islands",
 643	"lm96163",
 644	"Sea Islands",
 645	"Kaveri/Kabini",
 646};
 647
 648void amdgpu_add_thermal_controller(struct amdgpu_device *adev)
 649{
 650	struct amdgpu_mode_info *mode_info = &adev->mode_info;
 651	ATOM_PPLIB_POWERPLAYTABLE *power_table;
 652	int index = GetIndexIntoMasterTable(DATA, PowerPlayInfo);
 653	ATOM_PPLIB_THERMALCONTROLLER *controller;
 654	struct amdgpu_i2c_bus_rec i2c_bus;
 655	u16 data_offset;
 656	u8 frev, crev;
 657
 658	if (!amdgpu_atom_parse_data_header(mode_info->atom_context, index, NULL,
 659				   &frev, &crev, &data_offset))
 660		return;
 661	power_table = (ATOM_PPLIB_POWERPLAYTABLE *)
 662		(mode_info->atom_context->bios + data_offset);
 663	controller = &power_table->sThermalController;
 664
 665	/* add the i2c bus for thermal/fan chip */
 666	if (controller->ucType > 0) {
 667		if (controller->ucFanParameters & ATOM_PP_FANPARAMETERS_NOFAN)
 668			adev->pm.no_fan = true;
 669		adev->pm.fan_pulses_per_revolution =
 670			controller->ucFanParameters & ATOM_PP_FANPARAMETERS_TACHOMETER_PULSES_PER_REVOLUTION_MASK;
 671		if (adev->pm.fan_pulses_per_revolution) {
 672			adev->pm.fan_min_rpm = controller->ucFanMinRPM;
 673			adev->pm.fan_max_rpm = controller->ucFanMaxRPM;
 674		}
 675		if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV6xx) {
 676			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 677				 (controller->ucFanParameters &
 678				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 679			adev->pm.int_thermal_type = THERMAL_TYPE_RV6XX;
 680		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_RV770) {
 681			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 682				 (controller->ucFanParameters &
 683				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 684			adev->pm.int_thermal_type = THERMAL_TYPE_RV770;
 685		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EVERGREEN) {
 686			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 687				 (controller->ucFanParameters &
 688				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 689			adev->pm.int_thermal_type = THERMAL_TYPE_EVERGREEN;
 690		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SUMO) {
 691			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 692				 (controller->ucFanParameters &
 693				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 694			adev->pm.int_thermal_type = THERMAL_TYPE_SUMO;
 695		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_NISLANDS) {
 696			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 697				 (controller->ucFanParameters &
 698				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 699			adev->pm.int_thermal_type = THERMAL_TYPE_NI;
 700		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_SISLANDS) {
 701			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 702				 (controller->ucFanParameters &
 703				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 704			adev->pm.int_thermal_type = THERMAL_TYPE_SI;
 705		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_CISLANDS) {
 706			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 707				 (controller->ucFanParameters &
 708				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 709			adev->pm.int_thermal_type = THERMAL_TYPE_CI;
 710		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_KAVERI) {
 711			drm_info(adev_to_drm(adev), "Internal thermal controller %s fan control\n",
 712				 (controller->ucFanParameters &
 713				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 714			adev->pm.int_thermal_type = THERMAL_TYPE_KV;
 715		} else if (controller->ucType == ATOM_PP_THERMALCONTROLLER_EXTERNAL_GPIO) {
 716			drm_info(adev_to_drm(adev), "External GPIO thermal controller %s fan control\n",
 717				 (controller->ucFanParameters &
 718				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 719			adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL_GPIO;
 720		} else if (controller->ucType ==
 721			   ATOM_PP_THERMALCONTROLLER_ADT7473_WITH_INTERNAL) {
 722			drm_info(adev_to_drm(adev), "ADT7473 with internal thermal controller %s fan control\n",
 723				 (controller->ucFanParameters &
 724				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 725			adev->pm.int_thermal_type = THERMAL_TYPE_ADT7473_WITH_INTERNAL;
 726		} else if (controller->ucType ==
 727			   ATOM_PP_THERMALCONTROLLER_EMC2103_WITH_INTERNAL) {
 728			drm_info(adev_to_drm(adev), "EMC2103 with internal thermal controller %s fan control\n",
 729				 (controller->ucFanParameters &
 730				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 731			adev->pm.int_thermal_type = THERMAL_TYPE_EMC2103_WITH_INTERNAL;
 732		} else if (controller->ucType < ARRAY_SIZE(pp_lib_thermal_controller_names)) {
 733			drm_info(adev_to_drm(adev), "Possible %s thermal controller at 0x%02x %s fan control\n",
 734				 pp_lib_thermal_controller_names[controller->ucType],
 735				 controller->ucI2cAddress >> 1,
 736				 (controller->ucFanParameters &
 737				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 738			adev->pm.int_thermal_type = THERMAL_TYPE_EXTERNAL;
 739			i2c_bus = amdgpu_atombios_lookup_i2c_gpio(adev, controller->ucI2cLine);
 740			adev->pm.i2c_bus = amdgpu_i2c_lookup(adev, &i2c_bus);
 741			if (adev->pm.i2c_bus) {
 742				struct i2c_board_info info = { };
 743				const char *name = pp_lib_thermal_controller_names[controller->ucType];
 744				info.addr = controller->ucI2cAddress >> 1;
 745				strscpy(info.type, name, sizeof(info.type));
 746				i2c_new_client_device(&adev->pm.i2c_bus->adapter, &info);
 747			}
 748		} else {
 749			drm_info(adev_to_drm(adev), "Unknown thermal controller type %d at 0x%02x %s fan control\n",
 750				 controller->ucType,
 751				 controller->ucI2cAddress >> 1,
 752				 (controller->ucFanParameters &
 753				  ATOM_PP_FANPARAMETERS_NOFAN) ? "without" : "with");
 754		}
 755	}
 756}
 757
 758struct amd_vce_state* amdgpu_get_vce_clock_state(void *handle, u32 idx)
 759{
 760	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 761
 762	if (idx < adev->pm.dpm.num_of_vce_states)
 763		return &adev->pm.dpm.vce_states[idx];
 764
 765	return NULL;
 766}
 767
 768static struct amdgpu_ps *amdgpu_dpm_pick_power_state(struct amdgpu_device *adev,
 769						     enum amd_pm_state_type dpm_state)
 770{
 771	int i;
 772	struct amdgpu_ps *ps;
 773	u32 ui_class;
 774	bool single_display = adev->pm.pm_display_cfg.num_display < 2;
 775
 776	/* check if the vblank period is too short to adjust the mclk */
 777	if (single_display && adev->powerplay.pp_funcs->vblank_too_short) {
 778		if (amdgpu_dpm_vblank_too_short(adev))
 779			single_display = false;
 780	}
 781
 782	/* certain older asics have a separare 3D performance state,
 783	 * so try that first if the user selected performance
 784	 */
 785	if (dpm_state == POWER_STATE_TYPE_PERFORMANCE)
 786		dpm_state = POWER_STATE_TYPE_INTERNAL_3DPERF;
 787	/* balanced states don't exist at the moment */
 788	if (dpm_state == POWER_STATE_TYPE_BALANCED)
 789		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 790
 791restart_search:
 792	/* Pick the best power state based on current conditions */
 793	for (i = 0; i < adev->pm.dpm.num_ps; i++) {
 794		ps = &adev->pm.dpm.ps[i];
 795		ui_class = ps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK;
 796		switch (dpm_state) {
 797		/* user states */
 798		case POWER_STATE_TYPE_BATTERY:
 799			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_BATTERY) {
 800				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
 801					if (single_display)
 802						return ps;
 803				} else
 804					return ps;
 805			}
 806			break;
 807		case POWER_STATE_TYPE_PERFORMANCE:
 808			if (ui_class == ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
 809				if (ps->caps & ATOM_PPLIB_SINGLE_DISPLAY_ONLY) {
 810					if (single_display)
 811						return ps;
 812				} else
 813					return ps;
 814			}
 815			break;
 816		/* internal states */
 817		case POWER_STATE_TYPE_INTERNAL_UVD:
 818			if (adev->pm.dpm.uvd_ps)
 819				return adev->pm.dpm.uvd_ps;
 820			else
 821				break;
 822		case POWER_STATE_TYPE_INTERNAL_UVD_SD:
 823			if (ps->class & ATOM_PPLIB_CLASSIFICATION_SDSTATE)
 824				return ps;
 825			break;
 826		case POWER_STATE_TYPE_INTERNAL_UVD_HD:
 827			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HDSTATE)
 828				return ps;
 829			break;
 830		case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
 831			if (ps->class & ATOM_PPLIB_CLASSIFICATION_HD2STATE)
 832				return ps;
 833			break;
 834		case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
 835			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_MVC)
 836				return ps;
 837			break;
 838		case POWER_STATE_TYPE_INTERNAL_BOOT:
 839			return adev->pm.dpm.boot_ps;
 840		case POWER_STATE_TYPE_INTERNAL_THERMAL:
 841			if (ps->class & ATOM_PPLIB_CLASSIFICATION_THERMAL)
 842				return ps;
 843			break;
 844		case POWER_STATE_TYPE_INTERNAL_ACPI:
 845			if (ps->class & ATOM_PPLIB_CLASSIFICATION_ACPI)
 846				return ps;
 847			break;
 848		case POWER_STATE_TYPE_INTERNAL_ULV:
 849			if (ps->class2 & ATOM_PPLIB_CLASSIFICATION2_ULV)
 850				return ps;
 851			break;
 852		case POWER_STATE_TYPE_INTERNAL_3DPERF:
 853			if (ps->class & ATOM_PPLIB_CLASSIFICATION_3DPERFORMANCE)
 854				return ps;
 855			break;
 856		default:
 857			break;
 858		}
 859	}
 860	/* use a fallback state if we didn't match */
 861	switch (dpm_state) {
 862	case POWER_STATE_TYPE_INTERNAL_UVD_SD:
 863		dpm_state = POWER_STATE_TYPE_INTERNAL_UVD_HD;
 864		goto restart_search;
 865	case POWER_STATE_TYPE_INTERNAL_UVD_HD:
 866	case POWER_STATE_TYPE_INTERNAL_UVD_HD2:
 867	case POWER_STATE_TYPE_INTERNAL_UVD_MVC:
 868		if (adev->pm.dpm.uvd_ps) {
 869			return adev->pm.dpm.uvd_ps;
 870		} else {
 871			dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 872			goto restart_search;
 873		}
 874	case POWER_STATE_TYPE_INTERNAL_THERMAL:
 875		dpm_state = POWER_STATE_TYPE_INTERNAL_ACPI;
 876		goto restart_search;
 877	case POWER_STATE_TYPE_INTERNAL_ACPI:
 878		dpm_state = POWER_STATE_TYPE_BATTERY;
 879		goto restart_search;
 880	case POWER_STATE_TYPE_BATTERY:
 881	case POWER_STATE_TYPE_BALANCED:
 882	case POWER_STATE_TYPE_INTERNAL_3DPERF:
 883		dpm_state = POWER_STATE_TYPE_PERFORMANCE;
 884		goto restart_search;
 885	default:
 886		break;
 887	}
 888
 889	return NULL;
 890}
 891
 892static int amdgpu_dpm_change_power_state_locked(struct amdgpu_device *adev)
 893{
 894	const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
 895	struct amdgpu_ps *ps;
 896	enum amd_pm_state_type dpm_state;
 897	int ret;
 898	bool equal = false;
 899
 900	/* if dpm init failed */
 901	if (!adev->pm.dpm_enabled)
 902		return 0;
 903
 904	if (adev->pm.dpm.user_state != adev->pm.dpm.state) {
 905		/* add other state override checks here */
 906		if ((!adev->pm.dpm.thermal_active) &&
 907		    (!adev->pm.dpm.uvd_active))
 908			adev->pm.dpm.state = adev->pm.dpm.user_state;
 909	}
 910	dpm_state = adev->pm.dpm.state;
 911
 912	ps = amdgpu_dpm_pick_power_state(adev, dpm_state);
 913	if (ps)
 914		adev->pm.dpm.requested_ps = ps;
 915	else
 916		return -EINVAL;
 917
 918	if (amdgpu_dpm == 1 && pp_funcs->print_power_state) {
 919		drm_dbg(adev_to_drm(adev), "switching from power state\n");
 920		amdgpu_dpm_print_power_state(adev, adev->pm.dpm.current_ps);
 921		drm_dbg(adev_to_drm(adev), "switching to power state\n");
 922		amdgpu_dpm_print_power_state(adev, adev->pm.dpm.requested_ps);
 923	}
 924
 925	/* update whether vce is active */
 926	ps->vce_active = adev->pm.dpm.vce_active;
 927	if (pp_funcs->display_configuration_changed)
 928		amdgpu_dpm_display_configuration_changed(adev);
 929
 930	ret = amdgpu_dpm_pre_set_power_state(adev);
 931	if (ret)
 932		return ret;
 933
 934	if (pp_funcs->check_state_equal) {
 935		if (0 != amdgpu_dpm_check_state_equal(adev, adev->pm.dpm.current_ps, adev->pm.dpm.requested_ps, &equal))
 936			equal = false;
 937	}
 938
 939	if (equal)
 940		return 0;
 941
 942	if (pp_funcs->set_power_state)
 943		pp_funcs->set_power_state(adev->powerplay.pp_handle);
 944
 945	amdgpu_dpm_post_set_power_state(adev);
 946
 947	if (pp_funcs->force_performance_level) {
 948		if (adev->pm.dpm.thermal_active) {
 949			enum amd_dpm_forced_level level = adev->pm.dpm.forced_level;
 950			/* force low perf level for thermal */
 951			pp_funcs->force_performance_level(adev, AMD_DPM_FORCED_LEVEL_LOW);
 952			/* save the user's level */
 953			adev->pm.dpm.forced_level = level;
 954		} else {
 955			/* otherwise, user selected level */
 956			pp_funcs->force_performance_level(adev, adev->pm.dpm.forced_level);
 957		}
 958	}
 959
 960	return 0;
 961}
 962
 963void amdgpu_legacy_dpm_compute_clocks(void *handle)
 964{
 965	struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 966
 967	if (!adev->dc_enabled)
 968		amdgpu_dpm_get_display_cfg(adev);
 969
 970	amdgpu_dpm_change_power_state_locked(adev);
 971}
 972
 973void amdgpu_dpm_thermal_work_handler(struct work_struct *work)
 974{
 975	struct amdgpu_device *adev =
 976		container_of(work, struct amdgpu_device,
 977			     pm.dpm.thermal.work);
 978	const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
 979	/* switch to the thermal state */
 980	enum amd_pm_state_type dpm_state = POWER_STATE_TYPE_INTERNAL_THERMAL;
 981	int temp, size = sizeof(temp);
 982
 983	mutex_lock(&adev->pm.mutex);
 984
 985	if (!adev->pm.dpm_enabled) {
 986		mutex_unlock(&adev->pm.mutex);
 987		return;
 988	}
 989	if (!pp_funcs->read_sensor(adev->powerplay.pp_handle,
 990				   AMDGPU_PP_SENSOR_GPU_TEMP,
 991				   (void *)&temp,
 992				   &size)) {
 993		if (temp < adev->pm.dpm.thermal.min_temp)
 994			/* switch back the user state */
 995			dpm_state = adev->pm.dpm.user_state;
 996	} else {
 997		if (adev->pm.dpm.thermal.high_to_low)
 998			/* switch back the user state */
 999			dpm_state = adev->pm.dpm.user_state;
1000	}
1001
1002	if (dpm_state == POWER_STATE_TYPE_INTERNAL_THERMAL)
1003		adev->pm.dpm.thermal_active = true;
1004	else
1005		adev->pm.dpm.thermal_active = false;
1006
1007	adev->pm.dpm.state = dpm_state;
1008
1009	amdgpu_legacy_dpm_compute_clocks(adev->powerplay.pp_handle);
1010	mutex_unlock(&adev->pm.mutex);
1011}
~/ Read-only file preview.