Commit e805ed83 authored by Rex Zhu's avatar Rex Zhu Committed by Alex Deucher

drm/amd/powerplay: delete useless files.

Signed-off-by: default avatarRex Zhu <Rex.Zhu@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ab4f06d3
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "hwmgr.h"
#include "fiji_clockpowergating.h"
#include "fiji_ppsmc.h"
#include "fiji_hwmgr.h"
int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
data->uvd_power_gated = false;
data->vce_power_gated = false;
data->samu_power_gated = false;
data->acp_power_gated = false;
return 0;
}
int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
if (data->uvd_power_gated == bgate)
return 0;
data->uvd_power_gated = bgate;
if (bgate) {
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_CG_STATE_GATE);
fiji_update_uvd_dpm(hwmgr, true);
} else {
fiji_update_uvd_dpm(hwmgr, false);
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_CG_STATE_UNGATE);
}
return 0;
}
int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
struct phm_set_power_state_input states;
const struct pp_power_state *pcurrent;
struct pp_power_state *requested;
if (data->vce_power_gated == bgate)
return 0;
data->vce_power_gated = bgate;
pcurrent = hwmgr->current_ps;
requested = hwmgr->request_ps;
states.pcurrent_state = &(pcurrent->hardware);
states.pnew_state = &(requested->hardware);
fiji_update_vce_dpm(hwmgr, &states);
fiji_enable_disable_vce_dpm(hwmgr, !bgate);
return 0;
}
int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
if (data->samu_power_gated == bgate)
return 0;
data->samu_power_gated = bgate;
if (bgate)
fiji_update_samu_dpm(hwmgr, true);
else
fiji_update_samu_dpm(hwmgr, false);
return 0;
}
int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
if (data->acp_power_gated == bgate)
return 0;
data->acp_power_gated = bgate;
if (bgate)
fiji_update_acp_dpm(hwmgr, true);
else
fiji_update_acp_dpm(hwmgr, false);
return 0;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _FIJI_CLOCK_POWER_GATING_H_
#define _FIJI_CLOCK_POWER_GATING_H_
#include "fiji_hwmgr.h"
#include "pp_asicblocks.h"
extern int fiji_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
extern int fiji_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
extern int fiji_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
extern int fiji_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
extern int fiji_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef FIJI_DYN_DEFAULTS_H
#define FIJI_DYN_DEFAULTS_H
/** \file
* Volcanic Islands Dynamic default parameters.
*/
enum FIJIdpm_TrendDetection
{
FIJIAdpm_TrendDetection_AUTO,
FIJIAdpm_TrendDetection_UP,
FIJIAdpm_TrendDetection_DOWN
};
typedef enum FIJIdpm_TrendDetection FIJIdpm_TrendDetection;
/* We need to fill in the default values!!!!!!!!!!!!!!!!!!!!!!! */
/* Bit vector representing same fields as hardware register. */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy ????
* HDP_busy
* IH_busy
* UVD_busy
* VCE_busy
* ACP_busy
* SAMU_busy
* SDMA enabled */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. ????
* SH_Gfx_busy
* RB_Gfx_busy
* VCE_busy */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility.
* FE_Gfx_busy
* RB_Gfx_busy
* ACP_busy */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility.
* FE_Gfx_busy
* SH_Gfx_busy
* UVD_busy */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy
* VCE_busy
* ACP_busy
* SAMU_busy */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP */
#define PPFIJI_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP */
/* thermal protection counter (units). */
#define PPFIJI_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
/* static screen threshold unit */
#define PPFIJI_STATICSCREENTHRESHOLDUNIT_DFLT 0
/* static screen threshold */
#define PPFIJI_STATICSCREENTHRESHOLD_DFLT 0x00C8
/* gfx idle clock stop threshold */
#define PPFIJI_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
/* Fixed reference divider to use when building baby stepping tables. */
#define PPFIJI_REFERENCEDIVIDER_DFLT 4
/* ULV voltage change delay time
* Used to be delay_vreg in N.I. split for S.I.
* Using N.I. delay_vreg value as default
* ReferenceClock = 2700
* VoltageResponseTime = 1000
* VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
*/
#define PPFIJI_ULVVOLTAGECHANGEDELAY_DFLT 1687
#define PPFIJI_CGULVPARAMETER_DFLT 0x00040035
#define PPFIJI_CGULVCONTROL_DFLT 0x00007450
#define PPFIJI_TARGETACTIVITY_DFLT 30 /* 30%*/
#define PPFIJI_MCLK_TARGETACTIVITY_DFLT 10 /* 10% */
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _FIJI_HWMGR_H_
#define _FIJI_HWMGR_H_
#include "hwmgr.h"
#include "smu73.h"
#include "smu73_discrete.h"
#include "ppatomctrl.h"
#include "fiji_ppsmc.h"
#include "pp_endian.h"
#define FIJI_MAX_HARDWARE_POWERLEVELS 2
#define FIJI_AT_DFLT 30
#define FIJI_VOLTAGE_CONTROL_NONE 0x0
#define FIJI_VOLTAGE_CONTROL_BY_GPIO 0x1
#define FIJI_VOLTAGE_CONTROL_BY_SVID2 0x2
#define FIJI_VOLTAGE_CONTROL_MERGED 0x3
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
struct fiji_performance_level {
uint32_t memory_clock;
uint32_t engine_clock;
uint16_t pcie_gen;
uint16_t pcie_lane;
};
struct fiji_uvd_clocks {
uint32_t vclk;
uint32_t dclk;
};
struct fiji_vce_clocks {
uint32_t evclk;
uint32_t ecclk;
};
struct fiji_power_state {
uint32_t magic;
struct fiji_uvd_clocks uvd_clks;
struct fiji_vce_clocks vce_clks;
uint32_t sam_clk;
uint32_t acp_clk;
uint16_t performance_level_count;
bool dc_compatible;
uint32_t sclk_threshold;
struct fiji_performance_level performance_levels[FIJI_MAX_HARDWARE_POWERLEVELS];
};
struct fiji_dpm_level {
bool enabled;
uint32_t value;
uint32_t param1;
};
#define FIJI_MAX_DEEPSLEEP_DIVIDER_ID 5
#define MAX_REGULAR_DPM_NUMBER 8
#define FIJI_MINIMUM_ENGINE_CLOCK 2500
struct fiji_single_dpm_table {
uint32_t count;
struct fiji_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
};
struct fiji_dpm_table {
struct fiji_single_dpm_table sclk_table;
struct fiji_single_dpm_table mclk_table;
struct fiji_single_dpm_table pcie_speed_table;
struct fiji_single_dpm_table vddc_table;
struct fiji_single_dpm_table vddci_table;
struct fiji_single_dpm_table mvdd_table;
};
struct fiji_clock_registers {
uint32_t vCG_SPLL_FUNC_CNTL;
uint32_t vCG_SPLL_FUNC_CNTL_2;
uint32_t vCG_SPLL_FUNC_CNTL_3;
uint32_t vCG_SPLL_FUNC_CNTL_4;
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
uint32_t vDLL_CNTL;
uint32_t vMCLK_PWRMGT_CNTL;
uint32_t vMPLL_AD_FUNC_CNTL;
uint32_t vMPLL_DQ_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL_1;
uint32_t vMPLL_FUNC_CNTL_2;
uint32_t vMPLL_SS1;
uint32_t vMPLL_SS2;
};
struct fiji_voltage_smio_registers {
uint32_t vS0_VID_LOWER_SMIO_CNTL;
};
#define FIJI_MAX_LEAKAGE_COUNT 8
struct fiji_leakage_voltage {
uint16_t count;
uint16_t leakage_id[FIJI_MAX_LEAKAGE_COUNT];
uint16_t actual_voltage[FIJI_MAX_LEAKAGE_COUNT];
};
struct fiji_vbios_boot_state {
uint16_t mvdd_bootup_value;
uint16_t vddc_bootup_value;
uint16_t vddci_bootup_value;
uint32_t sclk_bootup_value;
uint32_t mclk_bootup_value;
uint16_t pcie_gen_bootup_value;
uint16_t pcie_lane_bootup_value;
};
struct fiji_bacos {
uint32_t best_match;
uint32_t baco_flags;
struct fiji_performance_level performance_level;
};
/* Ultra Low Voltage parameter structure */
struct fiji_ulv_parm {
bool ulv_supported;
uint32_t cg_ulv_parameter;
uint32_t ulv_volt_change_delay;
struct fiji_performance_level ulv_power_level;
};
struct fiji_display_timing {
uint32_t min_clock_in_sr;
uint32_t num_existing_displays;
};
struct fiji_dpmlevel_enable_mask {
uint32_t uvd_dpm_enable_mask;
uint32_t vce_dpm_enable_mask;
uint32_t acp_dpm_enable_mask;
uint32_t samu_dpm_enable_mask;
uint32_t sclk_dpm_enable_mask;
uint32_t mclk_dpm_enable_mask;
uint32_t pcie_dpm_enable_mask;
};
struct fiji_pcie_perf_range {
uint16_t max;
uint16_t min;
};
struct fiji_hwmgr {
struct fiji_dpm_table dpm_table;
struct fiji_dpm_table golden_dpm_table;
uint32_t voting_rights_clients0;
uint32_t voting_rights_clients1;
uint32_t voting_rights_clients2;
uint32_t voting_rights_clients3;
uint32_t voting_rights_clients4;
uint32_t voting_rights_clients5;
uint32_t voting_rights_clients6;
uint32_t voting_rights_clients7;
uint32_t static_screen_threshold_unit;
uint32_t static_screen_threshold;
uint32_t voltage_control;
uint32_t vddc_vddci_delta;
uint32_t active_auto_throttle_sources;
struct fiji_clock_registers clock_registers;
struct fiji_voltage_smio_registers voltage_smio_registers;
bool is_memory_gddr5;
uint16_t acpi_vddc;
bool pspp_notify_required;
uint16_t force_pcie_gen;
uint16_t acpi_pcie_gen;
uint32_t pcie_gen_cap;
uint32_t pcie_lane_cap;
uint32_t pcie_spc_cap;
struct fiji_leakage_voltage vddc_leakage;
struct fiji_leakage_voltage Vddci_leakage;
uint32_t mvdd_control;
uint32_t vddc_mask_low;
uint32_t mvdd_mask_low;
uint16_t max_vddc_in_pptable;
uint16_t min_vddc_in_pptable;
uint16_t max_vddci_in_pptable;
uint16_t min_vddci_in_pptable;
uint32_t mclk_strobe_mode_threshold;
uint32_t mclk_stutter_mode_threshold;
uint32_t mclk_edc_enable_threshold;
uint32_t mclk_edcwr_enable_threshold;
bool is_uvd_enabled;
struct fiji_vbios_boot_state vbios_boot_state;
bool battery_state;
bool is_tlu_enabled;
/* ---- SMC SRAM Address of firmware header tables ---- */
uint32_t sram_end;
uint32_t dpm_table_start;
uint32_t soft_regs_start;
uint32_t mc_reg_table_start;
uint32_t fan_table_start;
uint32_t arb_table_start;
struct SMU73_Discrete_DpmTable smc_state_table;
struct SMU73_Discrete_Ulv ulv_setting;
/* ---- Stuff originally coming from Evergreen ---- */
uint32_t vddci_control;
struct pp_atomctrl_voltage_table vddc_voltage_table;
struct pp_atomctrl_voltage_table vddci_voltage_table;
struct pp_atomctrl_voltage_table mvdd_voltage_table;
uint32_t mgcg_cgtt_local2;
uint32_t mgcg_cgtt_local3;
uint32_t gpio_debug;
uint32_t mc_micro_code_feature;
uint32_t highest_mclk;
uint16_t acpi_vddci;
uint8_t mvdd_high_index;
uint8_t mvdd_low_index;
bool dll_default_on;
bool performance_request_registered;
/* ---- Low Power Features ---- */
struct fiji_bacos bacos;
struct fiji_ulv_parm ulv;
/* ---- CAC Stuff ---- */
uint32_t cac_table_start;
bool cac_configuration_required;
bool driver_calculate_cac_leakage;
bool cac_enabled;
/* ---- DPM2 Parameters ---- */
uint32_t power_containment_features;
bool enable_dte_feature;
bool enable_tdc_limit_feature;
bool enable_pkg_pwr_tracking_feature;
bool disable_uvd_power_tune_feature;
const struct fiji_pt_defaults *power_tune_defaults;
struct SMU73_Discrete_PmFuses power_tune_table;
uint32_t dte_tj_offset;
uint32_t fast_watermark_threshold;
/* ---- Phase Shedding ---- */
bool vddc_phase_shed_control;
/* ---- DI/DT ---- */
struct fiji_display_timing display_timing;
/* ---- Thermal Temperature Setting ---- */
struct fiji_dpmlevel_enable_mask dpm_level_enable_mask;
uint32_t need_update_smu7_dpm_table;
uint32_t sclk_dpm_key_disabled;
uint32_t mclk_dpm_key_disabled;
uint32_t pcie_dpm_key_disabled;
uint32_t min_engine_clocks;
struct fiji_pcie_perf_range pcie_gen_performance;
struct fiji_pcie_perf_range pcie_lane_performance;
struct fiji_pcie_perf_range pcie_gen_power_saving;
struct fiji_pcie_perf_range pcie_lane_power_saving;
bool use_pcie_performance_levels;
bool use_pcie_power_saving_levels;
uint32_t activity_target[SMU73_MAX_LEVELS_GRAPHICS];
uint32_t mclk_activity_target;
uint32_t mclk_dpm0_activity_target;
uint32_t low_sclk_interrupt_threshold;
uint32_t last_mclk_dpm_enable_mask;
bool uvd_enabled;
/* ---- Power Gating States ---- */
bool uvd_power_gated;
bool vce_power_gated;
bool samu_power_gated;
bool acp_power_gated;
bool pg_acp_init;
bool frtc_enabled;
bool frtc_status_changed;
};
/* To convert to Q8.8 format for firmware */
#define FIJI_Q88_FORMAT_CONVERSION_UNIT 256
enum Fiji_I2CLineID {
Fiji_I2CLineID_DDC1 = 0x90,
Fiji_I2CLineID_DDC2 = 0x91,
Fiji_I2CLineID_DDC3 = 0x92,
Fiji_I2CLineID_DDC4 = 0x93,
Fiji_I2CLineID_DDC5 = 0x94,
Fiji_I2CLineID_DDC6 = 0x95,
Fiji_I2CLineID_SCLSDA = 0x96,
Fiji_I2CLineID_DDCVGA = 0x97
};
#define Fiji_I2C_DDC1DATA 0
#define Fiji_I2C_DDC1CLK 1
#define Fiji_I2C_DDC2DATA 2
#define Fiji_I2C_DDC2CLK 3
#define Fiji_I2C_DDC3DATA 4
#define Fiji_I2C_DDC3CLK 5
#define Fiji_I2C_SDA 40
#define Fiji_I2C_SCL 41
#define Fiji_I2C_DDC4DATA 65
#define Fiji_I2C_DDC4CLK 66
#define Fiji_I2C_DDC5DATA 0x48
#define Fiji_I2C_DDC5CLK 0x49
#define Fiji_I2C_DDC6DATA 0x4a
#define Fiji_I2C_DDC6CLK 0x4b
#define Fiji_I2C_DDCVGADATA 0x4c
#define Fiji_I2C_DDCVGACLK 0x4d
#define FIJI_UNUSED_GPIO_PIN 0x7F
extern int tonga_initializa_dynamic_state_adjustment_rule_settings(struct pp_hwmgr *hwmgr);
extern int tonga_get_mc_microcode_version (struct pp_hwmgr *hwmgr);
extern int tonga_notify_smc_display_config_after_ps_adjustment(struct pp_hwmgr *hwmgr);
extern int tonga_notify_smc_display_change(struct pp_hwmgr *hwmgr, bool has_display);
int fiji_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
int fiji_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int fiji_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int fiji_update_acp_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int fiji_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
#endif /* _FIJI_HWMGR_H_ */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "hwmgr.h"
#include "smumgr.h"
#include "fiji_hwmgr.h"
#include "fiji_powertune.h"
#include "fiji_smumgr.h"
#include "smu73_discrete.h"
#include "pp_debug.h"
#define VOLTAGE_SCALE 4
#define POWERTUNE_DEFAULT_SET_MAX 1
const struct fiji_pt_defaults fiji_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
/*sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc */
{1, 0xF, 0xFD,
/* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase */
0x19, 5, 45}
};
void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *fiji_hwmgr = (struct fiji_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
uint32_t tmp = 0;
if(table_info &&
table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
table_info->cac_dtp_table->usPowerTuneDataSetID)
fiji_hwmgr->power_tune_defaults =
&fiji_power_tune_data_set_array
[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
else
fiji_hwmgr->power_tune_defaults = &fiji_power_tune_data_set_array[0];
/* Assume disabled */
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SQRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_DBRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TDRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TCPRamping);
fiji_hwmgr->dte_tj_offset = tmp;
if (!tmp) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
fiji_hwmgr->fast_watermark_threshold = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
tmp = 1;
fiji_hwmgr->enable_dte_feature = tmp ? false : true;
fiji_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
fiji_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
}
}
}
/* PPGen has the gain setting generated in x * 100 unit
* This function is to convert the unit to x * 4096(0x1000) unit.
* This is the unit expected by SMC firmware
*/
static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
{
uint32_t tmp;
tmp = raw_setting * 4096 / 100;
return (uint16_t)tmp;
}
static void get_scl_sda_value(uint8_t line, uint8_t *scl, uint8_t* sda)
{
switch (line) {
case Fiji_I2CLineID_DDC1 :
*scl = Fiji_I2C_DDC1CLK;
*sda = Fiji_I2C_DDC1DATA;
break;
case Fiji_I2CLineID_DDC2 :
*scl = Fiji_I2C_DDC2CLK;
*sda = Fiji_I2C_DDC2DATA;
break;
case Fiji_I2CLineID_DDC3 :
*scl = Fiji_I2C_DDC3CLK;
*sda = Fiji_I2C_DDC3DATA;
break;
case Fiji_I2CLineID_DDC4 :
*scl = Fiji_I2C_DDC4CLK;
*sda = Fiji_I2C_DDC4DATA;
break;
case Fiji_I2CLineID_DDC5 :
*scl = Fiji_I2C_DDC5CLK;
*sda = Fiji_I2C_DDC5DATA;
break;
case Fiji_I2CLineID_DDC6 :
*scl = Fiji_I2C_DDC6CLK;
*sda = Fiji_I2C_DDC6DATA;
break;
case Fiji_I2CLineID_SCLSDA :
*scl = Fiji_I2C_SCL;
*sda = Fiji_I2C_SDA;
break;
case Fiji_I2CLineID_DDCVGA :
*scl = Fiji_I2C_DDCVGACLK;
*sda = Fiji_I2C_DDCVGADATA;
break;
default:
*scl = 0;
*sda = 0;
break;
}
}
int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
SMU73_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
struct pp_advance_fan_control_parameters *fan_table=
&hwmgr->thermal_controller.advanceFanControlParameters;
uint8_t uc_scl, uc_sda;
/* TDP number of fraction bits are changed from 8 to 7 for Fiji
* as requested by SMC team
*/
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
(uint16_t)(cac_dtp_table->usTDP * 128));
dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
(uint16_t)(cac_dtp_table->usTDP * 128));
PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
"Target Operating Temp is out of Range!",);
dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
dpm_table->GpuTjHyst = 8;
dpm_table->DTEAmbientTempBase = defaults->DTEAmbientTempBase;
/* The following are for new Fiji Multi-input fan/thermal control */
dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
cac_dtp_table->usTargetOperatingTemp * 256);
dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitHotspot * 256);
dpm_table->TemperatureLimitLiquid1 = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitLiquid1 * 256);
dpm_table->TemperatureLimitLiquid2 = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitLiquid2 * 256);
dpm_table->TemperatureLimitVrVddc = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitVrVddc * 256);
dpm_table->TemperatureLimitVrMvdd = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitVrMvdd * 256);
dpm_table->TemperatureLimitPlx = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitPlx * 256);
dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainEdge));
dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainHotspot));
dpm_table->FanGainLiquid = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainLiquid));
dpm_table->FanGainVrVddc = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainVrVddc));
dpm_table->FanGainVrMvdd = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainVrMvdd));
dpm_table->FanGainPlx = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainPlx));
dpm_table->FanGainHbm = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainHbm));
dpm_table->Liquid1_I2C_address = cac_dtp_table->ucLiquid1_I2C_address;
dpm_table->Liquid2_I2C_address = cac_dtp_table->ucLiquid2_I2C_address;
dpm_table->Vr_I2C_address = cac_dtp_table->ucVr_I2C_address;
dpm_table->Plx_I2C_address = cac_dtp_table->ucPlx_I2C_address;
get_scl_sda_value(cac_dtp_table->ucLiquid_I2C_Line, &uc_scl, &uc_sda);
dpm_table->Liquid_I2C_LineSCL = uc_scl;
dpm_table->Liquid_I2C_LineSDA = uc_sda;
get_scl_sda_value(cac_dtp_table->ucVr_I2C_Line, &uc_scl, &uc_sda);
dpm_table->Vr_I2C_LineSCL = uc_scl;
dpm_table->Vr_I2C_LineSDA = uc_sda;
get_scl_sda_value(cac_dtp_table->ucPlx_I2C_Line, &uc_scl, &uc_sda);
dpm_table->Plx_I2C_LineSCL = uc_scl;
dpm_table->Plx_I2C_LineSDA = uc_sda;
return 0;
}
static int fiji_populate_svi_load_line(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
data->power_tune_table.SviLoadLineTrimVddC = 3;
data->power_tune_table.SviLoadLineOffsetVddC = 0;
return 0;
}
static int fiji_populate_tdc_limit(struct pp_hwmgr *hwmgr)
{
uint16_t tdc_limit;
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
/* TDC number of fraction bits are changed from 8 to 7
* for Fiji as requested by SMC team
*/
tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
data->power_tune_table.TDC_VDDC_PkgLimit =
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
return 0;
}
static int fiji_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
const struct fiji_pt_defaults *defaults = data->power_tune_defaults;
uint32_t temp;
if (fiji_read_smc_sram_dword(hwmgr->smumgr,
fuse_table_offset +
offsetof(SMU73_Discrete_PmFuses, TdcWaterfallCtl),
(uint32_t *)&temp, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
else {
data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
data->power_tune_table.LPMLTemperatureMin =
(uint8_t)((temp >> 16) & 0xff);
data->power_tune_table.LPMLTemperatureMax =
(uint8_t)((temp >> 8) & 0xff);
data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
}
return 0;
}
static int fiji_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
{
int i;
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.LPMLTemperatureScaler[i] = 0;
return 0;
}
static int fiji_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
if( (hwmgr->thermal_controller.advanceFanControlParameters.
usFanOutputSensitivity & (1 << 15)) ||
0 == hwmgr->thermal_controller.advanceFanControlParameters.
usFanOutputSensitivity )
hwmgr->thermal_controller.advanceFanControlParameters.
usFanOutputSensitivity = hwmgr->thermal_controller.
advanceFanControlParameters.usDefaultFanOutputSensitivity;
data->power_tune_table.FuzzyFan_PwmSetDelta =
PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
advanceFanControlParameters.usFanOutputSensitivity);
return 0;
}
static int fiji_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
{
int i;
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.GnbLPML[i] = 0;
return 0;
}
static int fiji_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
{
/* int i, min, max;
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
uint8_t * pHiVID = data->power_tune_table.BapmVddCVidHiSidd;
uint8_t * pLoVID = data->power_tune_table.BapmVddCVidLoSidd;
min = max = pHiVID[0];
for (i = 0; i < 8; i++) {
if (0 != pHiVID[i]) {
if (min > pHiVID[i])
min = pHiVID[i];
if (max < pHiVID[i])
max = pHiVID[i];
}
if (0 != pLoVID[i]) {
if (min > pLoVID[i])
min = pLoVID[i];
if (max < pLoVID[i])
max = pLoVID[i];
}
}
PP_ASSERT_WITH_CODE((0 != min) && (0 != max), "BapmVddcVidSidd table does not exist!", return int_Failed);
data->power_tune_table.GnbLPMLMaxVid = (uint8_t)max;
data->power_tune_table.GnbLPMLMinVid = (uint8_t)min;
*/
return 0;
}
static int fiji_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
return 0;
}
int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
uint32_t pm_fuse_table_offset;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (fiji_read_smc_sram_dword(hwmgr->smumgr,
SMU7_FIRMWARE_HEADER_LOCATION +
offsetof(SMU73_Firmware_Header, PmFuseTable),
&pm_fuse_table_offset, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to get pm_fuse_table_offset Failed!",
return -EINVAL);
/* DW6 */
if (fiji_populate_svi_load_line(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate SviLoadLine Failed!",
return -EINVAL);
/* DW7 */
if (fiji_populate_tdc_limit(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TDCLimit Failed!", return -EINVAL);
/* DW8 */
if (fiji_populate_dw8(hwmgr, pm_fuse_table_offset))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TdcWaterfallCtl, "
"LPMLTemperature Min and Max Failed!",
return -EINVAL);
/* DW9-DW12 */
if (0 != fiji_populate_temperature_scaler(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate LPMLTemperatureScaler Failed!",
return -EINVAL);
/* DW13-DW14 */
if(fiji_populate_fuzzy_fan(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate Fuzzy Fan Control parameters Failed!",
return -EINVAL);
/* DW15-DW18 */
if (fiji_populate_gnb_lpml(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Failed!",
return -EINVAL);
/* DW19 */
if (fiji_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Min and Max Vid Failed!",
return -EINVAL);
/* DW20 */
if (fiji_populate_bapm_vddc_base_leakage_sidd(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate BapmVddCBaseLeakage Hi and Lo "
"Sidd Failed!", return -EINVAL);
if (fiji_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
(uint8_t *)&data->power_tune_table,
sizeof(struct SMU73_Discrete_PmFuses), data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to download PmFuseTable Failed!",
return -EINVAL);
}
return 0;
}
int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC)) {
int smc_result;
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableCac));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable CAC in SMC.", result = -1);
data->cac_enabled = (0 == smc_result) ? true : false;
}
return result;
}
int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC) && data->cac_enabled) {
int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableCac));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable CAC in SMC.", result = -1);
data->cac_enabled = false;
}
return result;
}
int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
if(data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_PkgPwrSetLimit, n);
return 0;
}
static int fiji_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
{
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
}
int fiji_enable_power_containment(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
int smc_result;
int result = 0;
data->power_containment_features = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (data->enable_dte_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableDTE));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable DTE in SMC.", result = -1;);
if (0 == smc_result)
data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
}
if (data->enable_tdc_limit_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable TDCLimit in SMC.", result = -1;);
if (0 == smc_result)
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_TDCLimit;
}
if (data->enable_pkg_pwr_tracking_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
if (0 == smc_result) {
struct phm_cac_tdp_table *cac_table =
table_info->cac_dtp_table;
uint32_t default_limit =
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
if (fiji_set_power_limit(hwmgr, default_limit))
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
}
}
}
return result;
}
int fiji_disable_power_containment(struct pp_hwmgr *hwmgr)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment) &&
data->power_containment_features) {
int smc_result;
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_TDCLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable TDCLimit in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_DTE) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableDTE));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable DTE in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable PkgPwrTracking in SMC.",
result = smc_result);
}
data->power_containment_features = 0;
}
return result;
}
int fiji_power_control_set_level(struct pp_hwmgr *hwmgr)
{
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
int adjust_percent, target_tdp;
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
/* adjustment percentage has already been validated */
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
hwmgr->platform_descriptor.TDPAdjustment :
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
/* SMC requested that target_tdp to be 7 bit fraction in DPM table
* but message to be 8 bit fraction for messages
*/
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
result = fiji_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
}
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef FIJI_POWERTUNE_H
#define FIJI_POWERTUNE_H
enum fiji_pt_config_reg_type {
FIJI_CONFIGREG_MMR = 0,
FIJI_CONFIGREG_SMC_IND,
FIJI_CONFIGREG_DIDT_IND,
FIJI_CONFIGREG_CACHE,
FIJI_CONFIGREG_MAX
};
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
#define DIDT_SQ_CTRL0__UNUSED_0_MASK 0xffffffc0
#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT 0x6
#define DIDT_TD_CTRL0__UNUSED_0_MASK 0xffffffc0
#define DIDT_TD_CTRL0__UNUSED_0__SHIFT 0x6
#define DIDT_TCP_CTRL0__UNUSED_0_MASK 0xffffffc0
#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT 0x6
#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK 0xe0000000
#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001d
struct fiji_pt_config_reg {
uint32_t offset;
uint32_t mask;
uint32_t shift;
uint32_t value;
enum fiji_pt_config_reg_type type;
};
struct fiji_pt_defaults
{
uint8_t SviLoadLineEn;
uint8_t SviLoadLineVddC;
uint8_t TDC_VDDC_ThrottleReleaseLimitPerc;
uint8_t TDC_MAWt;
uint8_t TdcWaterfallCtl;
uint8_t DTEAmbientTempBase;
};
void fiji_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
int fiji_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
int fiji_populate_pm_fuses(struct pp_hwmgr *hwmgr);
int fiji_enable_smc_cac(struct pp_hwmgr *hwmgr);
int fiji_disable_smc_cac(struct pp_hwmgr *hwmgr);
int fiji_enable_power_containment(struct pp_hwmgr *hwmgr);
int fiji_disable_power_containment(struct pp_hwmgr *hwmgr);
int fiji_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
int fiji_power_control_set_level(struct pp_hwmgr *hwmgr);
#endif /* FIJI_POWERTUNE_H */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <asm/div64.h>
#include "fiji_thermal.h"
#include "fiji_hwmgr.h"
#include "fiji_smumgr.h"
#include "fiji_ppsmc.h"
#include "smu/smu_7_1_3_d.h"
#include "smu/smu_7_1_3_sh_mask.h"
int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
struct phm_fan_speed_info *fan_speed_info)
{
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
fan_speed_info->supports_percent_read = true;
fan_speed_info->supports_percent_write = true;
fan_speed_info->min_percent = 0;
fan_speed_info->max_percent = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
fan_speed_info->supports_rpm_read = true;
fan_speed_info->supports_rpm_write = true;
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
} else {
fan_speed_info->min_rpm = 0;
fan_speed_info->max_rpm = 0;
}
return 0;
}
int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
uint32_t *speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_STATUS, FDO_PWM_DUTY);
if (duty100 == 0)
return -EINVAL;
tmp64 = (uint64_t)duty * 100;
do_div(tmp64, duty100);
*speed = (uint32_t)tmp64;
if (*speed > 100)
*speed = 100;
return 0;
}
int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
uint32_t tach_period;
uint32_t crystal_clock_freq;
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
(hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution == 0))
return 0;
tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_STATUS, TACH_PERIOD);
if (tach_period == 0)
return -EINVAL;
crystal_clock_freq = tonga_get_xclk(hwmgr);
*speed = 60 * crystal_clock_freq * 10000/ tach_period;
return 0;
}
/**
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
* @param hwmgr the address of the powerplay hardware manager.
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
* @exception Should always succeed.
*/
int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
{
if (hwmgr->fan_ctrl_is_in_default_mode) {
hwmgr->fan_ctrl_default_mode =
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE);
hwmgr->tmin =
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN);
hwmgr->fan_ctrl_is_in_default_mode = false;
}
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN, 0);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE, mode);
return 0;
}
/**
* Reset Fan Speed Control to default mode.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Should always succeed.
*/
int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->fan_ctrl_is_in_default_mode) {
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN, hwmgr->tmin);
hwmgr->fan_ctrl_is_in_default_mode = true;
}
return 0;
}
static int fiji_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
{
int result;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_FanSpeedInTableIsRPM))
hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
hwmgr->thermal_controller.
advanceFanControlParameters.usMaxFanRPM);
else
hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
hwmgr->thermal_controller.
advanceFanControlParameters.usMaxFanPWM);
} else {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
}
if (!result && hwmgr->thermal_controller.
advanceFanControlParameters.ucTargetTemperature)
result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanTemperatureTarget,
hwmgr->thermal_controller.
advanceFanControlParameters.ucTargetTemperature);
return result;
}
int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
{
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
}
/**
* Set Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (0% - 100%) to be set.
* @exception Fails is the 100% setting appears to be 0.
*/
int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
uint32_t speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (speed > 100)
speed = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl))
fiji_fan_ctrl_stop_smc_fan_control(hwmgr);
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
if (duty100 == 0)
return -EINVAL;
tmp64 = (uint64_t)speed * duty100;
do_div(tmp64, 100);
duty = (uint32_t)tmp64;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reset Fan Speed to default.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Always succeeds.
*/
int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
{
int result;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl)) {
result = fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
if (!result)
result = fiji_fan_ctrl_start_smc_fan_control(hwmgr);
} else
result = fiji_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (min - max) to be set.
* @exception Fails is the speed not lie between min and max.
*/
int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
{
uint32_t tach_period;
uint32_t crystal_clock_freq;
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
(hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution == 0) ||
(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
return 0;
crystal_clock_freq = tonga_get_xclk(hwmgr);
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_STATUS, TACH_PERIOD, tach_period);
return fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reads the remote temperature from the SIslands thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr)
{
int temp;
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_MULT_THERMAL_STATUS, CTF_TEMP);
/* Bit 9 means the reading is lower than the lowest usable value. */
if (temp & 0x200)
temp = FIJI_THERMAL_MAXIMUM_TEMP_READING;
else
temp = temp & 0x1ff;
temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
return temp;
}
/**
* Set the requested temperature range for high and low alert signals
*
* @param hwmgr The address of the hardware manager.
* @param range Temperature range to be programmed for high and low alert signals
* @exception PP_Result_BadInput if the input data is not valid.
*/
static int fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
uint32_t low_temp, uint32_t high_temp)
{
uint32_t low = FIJI_THERMAL_MINIMUM_ALERT_TEMP *
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
uint32_t high = FIJI_THERMAL_MAXIMUM_ALERT_TEMP *
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
if (low < low_temp)
low = low_temp;
if (high > high_temp)
high = high_temp;
if (low > high)
return -EINVAL;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, DIG_THERM_INTH,
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, DIG_THERM_INTL,
(low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_CTRL, DIG_THERM_DPM,
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
return 0;
}
/**
* Programs thermal controller one-time setting registers
*
* @param hwmgr The address of the hardware manager.
*/
static int fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
{
if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_CTRL, EDGE_PER_REV,
hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution - 1);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
return 0;
}
/**
* Enable thermal alerts on the RV770 thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
static int fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK);
alert &= ~(FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to enable internal thermal interrupts */
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
}
/**
* Disable thermal alerts on the RV770 thermal controller.
* @param hwmgr The address of the hardware manager.
*/
static int fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK);
alert |= (FIJI_THERMAL_HIGH_ALERT_MASK | FIJI_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to disable internal thermal interrupts */
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
}
/**
* Uninitialize the thermal controller.
* Currently just disables alerts.
* @param hwmgr The address of the hardware manager.
*/
int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
{
int result = fiji_thermal_disable_alert(hwmgr);
if (hwmgr->thermal_controller.fanInfo.bNoFan)
fiji_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set up the fan table to control the fan using the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
static int tf_fiji_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
struct fiji_hwmgr *data = (struct fiji_hwmgr *)(hwmgr->backend);
SMU73_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
uint32_t duty100;
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
uint16_t fdo_min, slope1, slope2;
uint32_t reference_clock;
int res;
uint64_t tmp64;
if (data->fan_table_start == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
if (duty100 == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
usPWMMin * duty100;
do_div(tmp64, 10000);
fdo_min = (uint16_t)tmp64;
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
fan_table.TempMin = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMin) / 100);
fan_table.TempMed = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMed) / 100);
fan_table.TempMax = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMax) / 100);
fan_table.Slope1 = cpu_to_be16(slope1);
fan_table.Slope2 = cpu_to_be16(slope2);
fan_table.FdoMin = cpu_to_be16(fdo_min);
fan_table.HystDown = cpu_to_be16(hwmgr->
thermal_controller.advanceFanControlParameters.ucTHyst);
fan_table.HystUp = cpu_to_be16(1);
fan_table.HystSlope = cpu_to_be16(1);
fan_table.TempRespLim = cpu_to_be16(5);
reference_clock = tonga_get_xclk(hwmgr);
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
thermal_controller.advanceFanControlParameters.ulCycleDelay *
reference_clock) / 1600);
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
hwmgr->device, CGS_IND_REG__SMC,
CG_MULT_THERMAL_CTRL, TEMP_SEL);
res = fiji_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
(uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
data->sram_end);
if (!res && hwmgr->thermal_controller.
advanceFanControlParameters.ucMinimumPWMLimit)
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanMinPwm,
hwmgr->thermal_controller.
advanceFanControlParameters.ucMinimumPWMLimit);
if (!res && hwmgr->thermal_controller.
advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanSclkTarget,
hwmgr->thermal_controller.
advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
if (res)
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
/**
* Start the fan control on the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
static int tf_fiji_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
/* If the fantable setup has failed we could have disabled
* PHM_PlatformCaps_MicrocodeFanControl even after
* this function was included in the table.
* Make sure that we still think controlling the fan is OK.
*/
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl)) {
fiji_fan_ctrl_start_smc_fan_control(hwmgr);
fiji_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
return 0;
}
/**
* Set temperature range for high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
if (range == NULL)
return -EINVAL;
return fiji_thermal_set_temperature_range(hwmgr, range->min, range->max);
}
/**
* Programs one-time setting registers
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from initialize thermal controller routine
*/
int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return fiji_thermal_initialize(hwmgr);
}
/**
* Enable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from enable alert routine
*/
int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return fiji_thermal_enable_alert(hwmgr);
}
/**
* Disable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from disable alert routine
*/
static int tf_fiji_thermal_disable_alert(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return fiji_thermal_disable_alert(hwmgr);
}
static const struct phm_master_table_item
fiji_thermal_start_thermal_controller_master_list[] = {
{NULL, tf_fiji_thermal_initialize},
{NULL, tf_fiji_thermal_set_temperature_range},
{NULL, tf_fiji_thermal_enable_alert},
/* We should restrict performance levels to low before we halt the SMC.
* On the other hand we are still in boot state when we do this
* so it would be pointless.
* If this assumption changes we have to revisit this table.
*/
{NULL, tf_fiji_thermal_setup_fan_table},
{NULL, tf_fiji_thermal_start_smc_fan_control},
{NULL, NULL}
};
static const struct phm_master_table_header
fiji_thermal_start_thermal_controller_master = {
0,
PHM_MasterTableFlag_None,
fiji_thermal_start_thermal_controller_master_list
};
static const struct phm_master_table_item
fiji_thermal_set_temperature_range_master_list[] = {
{NULL, tf_fiji_thermal_disable_alert},
{NULL, tf_fiji_thermal_set_temperature_range},
{NULL, tf_fiji_thermal_enable_alert},
{NULL, NULL}
};
static const struct phm_master_table_header
fiji_thermal_set_temperature_range_master = {
0,
PHM_MasterTableFlag_None,
fiji_thermal_set_temperature_range_master_list
};
int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
fiji_fan_ctrl_set_default_mode(hwmgr);
return 0;
}
/**
* Initializes the thermal controller related functions in the Hardware Manager structure.
* @param hwmgr The address of the hardware manager.
* @exception Any error code from the low-level communication.
*/
int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr)
{
int result;
result = phm_construct_table(hwmgr,
&fiji_thermal_set_temperature_range_master,
&(hwmgr->set_temperature_range));
if (!result) {
result = phm_construct_table(hwmgr,
&fiji_thermal_start_thermal_controller_master,
&(hwmgr->start_thermal_controller));
if (result)
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
}
if (!result)
hwmgr->fan_ctrl_is_in_default_mode = true;
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef FIJI_THERMAL_H
#define FIJI_THERMAL_H
#include "hwmgr.h"
#define FIJI_THERMAL_HIGH_ALERT_MASK 0x1
#define FIJI_THERMAL_LOW_ALERT_MASK 0x2
#define FIJI_THERMAL_MINIMUM_TEMP_READING -256
#define FIJI_THERMAL_MAXIMUM_TEMP_READING 255
#define FIJI_THERMAL_MINIMUM_ALERT_TEMP 0
#define FIJI_THERMAL_MAXIMUM_ALERT_TEMP 255
#define FDO_PWM_MODE_STATIC 1
#define FDO_PWM_MODE_STATIC_RPM 5
extern int tf_fiji_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_fiji_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_fiji_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int fiji_thermal_get_temperature(struct pp_hwmgr *hwmgr);
extern int fiji_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
extern int fiji_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
extern int fiji_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int fiji_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
extern int fiji_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
extern int fiji_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int fiji_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
extern int pp_fiji_thermal_initialize(struct pp_hwmgr *hwmgr);
extern int fiji_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
extern int fiji_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int fiji_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int fiji_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#include "hwmgr.h"
#include "iceland_clockpowergating.h"
#include "ppsmc.h"
#include "iceland_hwmgr.h"
int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
{
/* iceland does not have MM hardware block */
return 0;
}
static int iceland_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
{
/* iceland does not have MM hardware block */
return 0;
}
static int iceland_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
{
/* iceland does not have MM hardware block */
return 0;
}
static int iceland_phm_powerup_vce(struct pp_hwmgr *hwmgr)
{
/* iceland does not have MM hardware block */
return 0;
}
int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum
PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
{
int ret = 0;
switch (block) {
case PHM_AsicBlock_UVD_MVC:
case PHM_AsicBlock_UVD:
case PHM_AsicBlock_UVD_HD:
case PHM_AsicBlock_UVD_SD:
if (gating == PHM_ClockGateSetting_StaticOff)
ret = iceland_phm_powerdown_uvd(hwmgr);
else
ret = iceland_phm_powerup_uvd(hwmgr);
break;
case PHM_AsicBlock_GFX:
default:
break;
}
return ret;
}
int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
data->uvd_power_gated = false;
data->vce_power_gated = false;
iceland_phm_powerup_uvd(hwmgr);
iceland_phm_powerup_vce(hwmgr);
return 0;
}
int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
{
if (bgate) {
iceland_update_uvd_dpm(hwmgr, true);
iceland_phm_powerdown_uvd(hwmgr);
} else {
iceland_phm_powerup_uvd(hwmgr);
iceland_update_uvd_dpm(hwmgr, false);
}
return 0;
}
int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
{
if (bgate)
return iceland_phm_powerdown_vce(hwmgr);
else
return iceland_phm_powerup_vce(hwmgr);
return 0;
}
int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
const uint32_t *msg_id)
{
/* iceland does not have MM hardware block */
return 0;
}
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#ifndef _ICELAND_CLOCK_POWER_GATING_H_
#define _ICELAND_CLOCK_POWER_GATING_H_
#include "iceland_hwmgr.h"
#include "pp_asicblocks.h"
extern int iceland_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
extern int iceland_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
extern int iceland_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
extern int iceland_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
extern int iceland_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
extern int iceland_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
#endif /* _ICELAND_CLOCK_POWER_GATING_H_ */
#ifndef ICELAND_DYN_DEFAULTS_H
#define ICELAND_DYN_DEFAULTS_H
enum ICELANDdpm_TrendDetection
{
ICELANDdpm_TrendDetection_AUTO,
ICELANDdpm_TrendDetection_UP,
ICELANDdpm_TrendDetection_DOWN
};
typedef enum ICELANDdpm_TrendDetection ICELANDdpm_TrendDetection;
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT1 0x000400
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033
#define PPICELAND_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000
#define PPICELAND_THERMALPROTECTCOUNTER_DFLT 0x200
#define PPICELAND_STATICSCREENTHRESHOLDUNIT_DFLT 0
#define PPICELAND_STATICSCREENTHRESHOLD_DFLT 0x00C8
#define PPICELAND_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200
#define PPICELAND_REFERENCEDIVIDER_DFLT 4
#define PPICELAND_ULVVOLTAGECHANGEDELAY_DFLT 1687
#define PPICELAND_CGULVPARAMETER_DFLT 0x00040035
#define PPICELAND_CGULVCONTROL_DFLT 0x00007450
#define PPICELAND_TARGETACTIVITY_DFLT 30
#define PPICELAND_MCLK_TARGETACTIVITY_DFLT 10
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#ifndef ICELAND_HWMGR_H
#define ICELAND_HWMGR_H
#include "hwmgr.h"
#include "ppatomctrl.h"
#include "ppinterrupt.h"
#include "ppsmc.h"
#include "iceland_powertune.h"
#include "pp_endian.h"
#include "smu71_discrete.h"
#define ICELAND_MAX_HARDWARE_POWERLEVELS 2
#define ICELAND_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
struct iceland_performance_level {
uint32_t memory_clock;
uint32_t engine_clock;
uint16_t pcie_gen;
uint16_t pcie_lane;
};
struct _phw_iceland_bacos {
uint32_t best_match;
uint32_t baco_flags;
struct iceland_performance_level performance_level;
};
typedef struct _phw_iceland_bacos phw_iceland_bacos;
struct _phw_iceland_uvd_clocks {
uint32_t VCLK;
uint32_t DCLK;
};
typedef struct _phw_iceland_uvd_clocks phw_iceland_uvd_clocks;
struct _phw_iceland_vce_clocks {
uint32_t EVCLK;
uint32_t ECCLK;
};
typedef struct _phw_iceland_vce_clocks phw_iceland_vce_clocks;
struct iceland_power_state {
uint32_t magic;
phw_iceland_uvd_clocks uvd_clocks;
phw_iceland_vce_clocks vce_clocks;
uint32_t sam_clk;
uint32_t acp_clk;
uint16_t performance_level_count;
bool dc_compatible;
uint32_t sclk_threshold;
struct iceland_performance_level performance_levels[ICELAND_MAX_HARDWARE_POWERLEVELS];
};
struct _phw_iceland_dpm_level {
bool enabled;
uint32_t value;
uint32_t param1;
};
typedef struct _phw_iceland_dpm_level phw_iceland_dpm_level;
#define ICELAND_MAX_DEEPSLEEP_DIVIDER_ID 5
#define MAX_REGULAR_DPM_NUMBER 8
#define ICELAND_MINIMUM_ENGINE_CLOCK 5000
struct iceland_single_dpm_table {
uint32_t count;
phw_iceland_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
};
struct iceland_dpm_table {
struct iceland_single_dpm_table sclk_table;
struct iceland_single_dpm_table mclk_table;
struct iceland_single_dpm_table pcie_speed_table;
struct iceland_single_dpm_table vddc_table;
struct iceland_single_dpm_table vdd_gfx_table;
struct iceland_single_dpm_table vdd_ci_table;
struct iceland_single_dpm_table mvdd_table;
};
typedef struct _phw_iceland_dpm_table phw_iceland_dpm_table;
struct _phw_iceland_clock_regisiters {
uint32_t vCG_SPLL_FUNC_CNTL;
uint32_t vCG_SPLL_FUNC_CNTL_2;
uint32_t vCG_SPLL_FUNC_CNTL_3;
uint32_t vCG_SPLL_FUNC_CNTL_4;
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
uint32_t vDLL_CNTL;
uint32_t vMCLK_PWRMGT_CNTL;
uint32_t vMPLL_AD_FUNC_CNTL;
uint32_t vMPLL_DQ_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL_1;
uint32_t vMPLL_FUNC_CNTL_2;
uint32_t vMPLL_SS1;
uint32_t vMPLL_SS2;
};
typedef struct _phw_iceland_clock_regisiters phw_iceland_clock_registers;
struct _phw_iceland_voltage_smio_registers {
uint32_t vs0_vid_lower_smio_cntl;
};
typedef struct _phw_iceland_voltage_smio_registers phw_iceland_voltage_smio_registers;
struct _phw_iceland_mc_reg_entry {
uint32_t mclk_max;
uint32_t mc_data[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_iceland_mc_reg_entry phw_iceland_mc_reg_entry;
struct _phw_iceland_mc_reg_table {
uint8_t last; /* number of registers*/
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
phw_iceland_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
SMU71_Discrete_MCRegisterAddress mc_reg_address[SMU71_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_iceland_mc_reg_table phw_iceland_mc_reg_table;
#define DISABLE_MC_LOADMICROCODE 1
#define DISABLE_MC_CFGPROGRAMMING 2
/*Ultra Low Voltage parameter structure */
struct phw_iceland_ulv_parm{
bool ulv_supported;
uint32_t ch_ulv_parameter;
uint32_t ulv_volt_change_delay;
struct iceland_performance_level ulv_power_level;
};
#define ICELAND_MAX_LEAKAGE_COUNT 8
struct phw_iceland_leakage_voltage {
uint16_t count;
uint16_t leakage_id[ICELAND_MAX_LEAKAGE_COUNT];
uint16_t actual_voltage[ICELAND_MAX_LEAKAGE_COUNT];
};
struct _phw_iceland_display_timing {
uint32_t min_clock_insr;
uint32_t num_existing_displays;
};
typedef struct _phw_iceland_display_timing phw_iceland_display_timing;
struct phw_iceland_thermal_temperature_setting
{
long temperature_low;
long temperature_high;
long temperature_shutdown;
};
struct _phw_iceland_dpmlevel_enable_mask {
uint32_t uvd_dpm_enable_mask;
uint32_t vce_dpm_enable_mask;
uint32_t acp_dpm_enable_mask;
uint32_t samu_dpm_enable_mask;
uint32_t sclk_dpm_enable_mask;
uint32_t mclk_dpm_enable_mask;
uint32_t pcie_dpm_enable_mask;
};
typedef struct _phw_iceland_dpmlevel_enable_mask phw_iceland_dpmlevel_enable_mask;
struct _phw_iceland_pcie_perf_range {
uint16_t max;
uint16_t min;
};
typedef struct _phw_iceland_pcie_perf_range phw_iceland_pcie_perf_range;
struct _phw_iceland_vbios_boot_state {
uint16_t mvdd_bootup_value;
uint16_t vddc_bootup_value;
uint16_t vddci_bootup_value;
uint16_t vddgfx_bootup_value;
uint32_t sclk_bootup_value;
uint32_t mclk_bootup_value;
uint16_t pcie_gen_bootup_value;
uint16_t pcie_lane_bootup_value;
};
typedef struct _phw_iceland_vbios_boot_state phw_iceland_vbios_boot_state;
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
/* We need to review which fields are needed. */
/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
struct iceland_hwmgr {
struct iceland_dpm_table dpm_table;
struct iceland_dpm_table golden_dpm_table;
uint32_t voting_rights_clients0;
uint32_t voting_rights_clients1;
uint32_t voting_rights_clients2;
uint32_t voting_rights_clients3;
uint32_t voting_rights_clients4;
uint32_t voting_rights_clients5;
uint32_t voting_rights_clients6;
uint32_t voting_rights_clients7;
uint32_t static_screen_threshold_unit;
uint32_t static_screen_threshold;
uint32_t voltage_control;
uint32_t vdd_gfx_control;
uint32_t vddc_vddci_delta;
uint32_t vddc_vddgfx_delta;
struct pp_interrupt_registration_info internal_high_thermal_interrupt_info;
struct pp_interrupt_registration_info internal_low_thermal_interrupt_info;
struct pp_interrupt_registration_info smc_to_host_interrupt_info;
uint32_t active_auto_throttle_sources;
struct pp_interrupt_registration_info external_throttle_interrupt;
irq_handler_func_t external_throttle_callback;
void *external_throttle_context;
struct pp_interrupt_registration_info ctf_interrupt_info;
irq_handler_func_t ctf_callback;
void *ctf_context;
phw_iceland_clock_registers clock_registers;
phw_iceland_voltage_smio_registers voltage_smio_registers;
bool is_memory_GDDR5;
uint16_t acpi_vddc;
bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
struct phw_iceland_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
struct phw_iceland_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
struct phw_iceland_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
uint32_t mvdd_control;
uint32_t vddc_mask_low;
uint32_t mvdd_mask_low;
uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
uint16_t min_vddc_in_pp_table;
uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
uint16_t min_vddci_in_pp_table;
uint32_t mclk_strobe_mode_threshold;
uint32_t mclk_stutter_mode_threshold;
uint32_t mclk_edc_enable_threshold;
uint32_t mclk_edc_wr_enable_threshold;
bool is_uvd_enabled;
bool is_xdma_enabled;
phw_iceland_vbios_boot_state vbios_boot_state;
bool battery_state;
bool is_tlu_enabled;
bool pcie_performance_request;
/* -------------- SMC SRAM Address of firmware header tables ----------------*/
uint32_t sram_end; /* The first address after the SMC SRAM. */
uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
uint32_t ulv_settings_start;
SMU71_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
SMU71_Discrete_MCRegisters mc_reg_table;
SMU71_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
/* -------------- Stuff originally coming from Evergreen --------------------*/
phw_iceland_mc_reg_table iceland_mc_reg_table;
uint32_t vdd_ci_control;
pp_atomctrl_voltage_table vddc_voltage_table;
pp_atomctrl_voltage_table vddci_voltage_table;
pp_atomctrl_voltage_table vddgfx_voltage_table;
pp_atomctrl_voltage_table mvdd_voltage_table;
uint32_t mgcg_cgtt_local2;
uint32_t mgcg_cgtt_local3;
uint32_t gpio_debug;
uint32_t mc_micro_code_feature;
uint32_t highest_mclk;
uint16_t acpi_vdd_ci;
uint8_t mvdd_high_index;
uint8_t mvdd_low_index;
bool dll_defaule_on;
bool performance_request_registered;
/* ----------------- Low Power Features ---------------------*/
phw_iceland_bacos bacos;
struct phw_iceland_ulv_parm ulv;
/* ----------------- CAC Stuff ---------------------*/
uint32_t cac_table_start;
bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
bool cac_enabled;
/* ----------------- DPM2 Parameters ---------------------*/
uint32_t power_containment_features;
bool enable_bapm_feature;
bool enable_dte_feature;
bool enable_tdc_limit_feature;
bool enable_pkg_pwr_tracking_feature;
bool disable_uvd_power_tune_feature;
struct iceland_pt_defaults *power_tune_defaults;
SMU71_Discrete_PmFuses power_tune_table;
uint32_t ul_dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
/* ----------------- Phase Shedding ---------------------*/
bool vddc_phase_shed_control;
/* --------------------- DI/DT --------------------------*/
phw_iceland_display_timing display_timing;
/* --------- ReadRegistry data for memory and engine clock margins ---- */
uint32_t engine_clock_data;
uint32_t memory_clock_data;
/* -------- Thermal Temperature Setting --------------*/
struct phw_iceland_thermal_temperature_setting thermal_temp_setting;
phw_iceland_dpmlevel_enable_mask dpm_level_enable_mask;
uint32_t need_update_smu7_dpm_table;
uint32_t sclk_dpm_key_disabled;
uint32_t mclk_dpm_key_disabled;
uint32_t pcie_dpm_key_disabled;
/* used to store the previous dal min sclock */
uint32_t min_engine_clocks;
phw_iceland_pcie_perf_range pcie_gen_performance;
phw_iceland_pcie_perf_range pcie_lane_performance;
phw_iceland_pcie_perf_range pcie_gen_power_saving;
phw_iceland_pcie_perf_range pcie_lane_power_saving;
bool use_pcie_performance_levels;
bool use_pcie_power_saving_levels;
/* percentage value from 0-100, default 50 */
uint32_t activity_target[SMU71_MAX_LEVELS_GRAPHICS];
uint32_t mclk_activity_target;
uint32_t low_sclk_interrupt_threshold;
uint32_t last_mclk_dpm_enable_mask;
bool uvd_enabled;
uint32_t pcc_monitor_enabled;
/* --------- Power Gating States ------------*/
bool uvd_power_gated; /* 1: gated, 0:not gated */
bool vce_power_gated; /* 1: gated, 0:not gated */
bool samu_power_gated; /* 1: gated, 0:not gated */
bool acp_power_gated; /* 1: gated, 0:not gated */
bool pg_acp_init;
/* soft pptable for re-uploading into smu */
void *soft_pp_table;
};
typedef struct iceland_hwmgr iceland_hwmgr;
int iceland_hwmgr_init(struct pp_hwmgr *hwmgr);
int iceland_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
uint32_t iceland_get_xclk(struct pp_hwmgr *hwmgr);
int iceland_populate_bapm_vddc_vid_sidd(struct pp_hwmgr *hwmgr);
int iceland_populate_vddc_vid(struct pp_hwmgr *hwmgr);
#define ICELAND_DPM2_NEAR_TDP_DEC 10
#define ICELAND_DPM2_ABOVE_SAFE_INC 5
#define ICELAND_DPM2_BELOW_SAFE_INC 20
/*
* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size
* is 128, then this value should be Log2(128) = 7.
*/
#define ICELAND_DPM2_LTA_WINDOW_SIZE 7
#define ICELAND_DPM2_LTS_TRUNCATE 0
#define ICELAND_DPM2_TDP_SAFE_LIMIT_PERCENT 80 // Maximum 100
#define ICELAND_DPM2_MAXPS_PERCENT_H 90 // Maximum 0xFF
#define ICELAND_DPM2_MAXPS_PERCENT_M 90 // Maximum 0xFF
#define ICELAND_DPM2_PWREFFICIENCYRATIO_MARGIN 50
#define ICELAND_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
#define ICELAND_DPM2_SQ_RAMP_MIN_POWER 0x12
#define ICELAND_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
#define ICELAND_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
#define ICELAND_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
#define ICELAND_VOLTAGE_CONTROL_NONE 0x0
#define ICELAND_VOLTAGE_CONTROL_BY_GPIO 0x1
#define ICELAND_VOLTAGE_CONTROL_BY_SVID2 0x2
/* convert to Q8.8 format for firmware */
#define ICELAND_Q88_FORMAT_CONVERSION_UNIT 256
#define ICELAND_UNUSED_GPIO_PIN 0x7F
#endif
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#include "amdgpu.h"
#include "hwmgr.h"
#include "smumgr.h"
#include "iceland_hwmgr.h"
#include "iceland_powertune.h"
#include "iceland_smumgr.h"
#include "smu71_discrete.h"
#include "smu71.h"
#include "pp_debug.h"
#include "cgs_common.h"
#include "pp_endian.h"
#include "bif/bif_5_0_d.h"
#include "bif/bif_5_0_sh_mask.h"
#define VOLTAGE_SCALE 4
#define POWERTUNE_DEFAULT_SET_MAX 1
#define DEVICE_ID_VI_ICELAND_M_6900 0x6900
#define DEVICE_ID_VI_ICELAND_M_6901 0x6901
#define DEVICE_ID_VI_ICELAND_M_6902 0x6902
#define DEVICE_ID_VI_ICELAND_M_6903 0x6903
struct iceland_pt_defaults defaults_iceland =
{
/*
* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc,
* TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT
*/
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
{ 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61 },
{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 }
};
/* 35W - XT, XTL */
struct iceland_pt_defaults defaults_icelandxt =
{
/*
* sviLoadLIneEn, SviLoadLineVddC,
* TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
* TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
* BAPM_TEMP_GRADIENT
*/
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
{ 0xA7, 0x0, 0x0, 0xB5, 0x0, 0x0, 0x9F, 0x0, 0x0, 0xD6, 0x0, 0x0, 0xD7, 0x0, 0x0},
{ 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
};
/* 25W - PRO, LE */
struct iceland_pt_defaults defaults_icelandpro =
{
/*
* sviLoadLIneEn, SviLoadLineVddC,
* TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
* TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac,
* BAPM_TEMP_GRADIENT
*/
1, 0xF, 0xFD, 0x19, 5, 45, 0, 0x0,
{ 0xB7, 0x0, 0x0, 0xC3, 0x0, 0x0, 0xB5, 0x0, 0x0, 0xEA, 0x0, 0x0, 0xE6, 0x0, 0x0},
{ 0x1EA, 0x0, 0x0, 0x224, 0x0, 0x0, 0x25E, 0x0, 0x0, 0x28E, 0x0, 0x0, 0x2AB, 0x0, 0x0}
};
void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
uint32_t tmp = 0;
struct cgs_system_info sys_info = {0};
uint32_t pdev_id;
sys_info.size = sizeof(struct cgs_system_info);
sys_info.info_id = CGS_SYSTEM_INFO_PCIE_DEV;
cgs_query_system_info(hwmgr->device, &sys_info);
pdev_id = (uint32_t)sys_info.value;
switch (pdev_id) {
case DEVICE_ID_VI_ICELAND_M_6900:
case DEVICE_ID_VI_ICELAND_M_6903:
data->power_tune_defaults = &defaults_icelandxt;
break;
case DEVICE_ID_VI_ICELAND_M_6901:
case DEVICE_ID_VI_ICELAND_M_6902:
data->power_tune_defaults = &defaults_icelandpro;
break;
default:
/* TODO: need to assign valid defaults */
data->power_tune_defaults = &defaults_iceland;
pr_warning("Unknown V.I. Device ID.\n");
break;
}
/* Assume disabled */
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SQRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_DBRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TDRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TCPRamping);
data->ul_dte_tj_offset = tmp;
if (!tmp) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
data->fast_watermark_threshold = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
tmp = 1;
data->enable_dte_feature = tmp ? false : true;
data->enable_tdc_limit_feature = tmp ? true : false;
data->enable_pkg_pwr_tracking_feature = tmp ? true : false;
}
}
}
int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
struct iceland_pt_defaults *defaults = data->power_tune_defaults;
SMU71_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
struct phm_cac_tdp_table *cac_dtp_table = hwmgr->dyn_state.cac_dtp_table;
struct phm_ppm_table *ppm = hwmgr->dyn_state.ppm_parameter_table;
uint16_t *def1, *def2;
int i, j, k;
/*
* TDP number of fraction bits are changed from 8 to 7 for Iceland
* as requested by SMC team
*/
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 256));
dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
dpm_table->DTETjOffset = (uint8_t)data->ul_dte_tj_offset;
dpm_table->GpuTjMax = (uint8_t)(data->thermal_temp_setting.temperature_high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES);
dpm_table->GpuTjHyst = 8;
dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
/* The following are for new Iceland Multi-input fan/thermal control */
if(NULL != ppm) {
dpm_table->PPM_PkgPwrLimit = (uint16_t)ppm->dgpu_tdp * 256 / 1000;
dpm_table->PPM_TemperatureLimit = (uint16_t)ppm->tj_max * 256;
} else {
dpm_table->PPM_PkgPwrLimit = 0;
dpm_table->PPM_TemperatureLimit = 0;
}
CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_PkgPwrLimit);
CONVERT_FROM_HOST_TO_SMC_US(dpm_table->PPM_TemperatureLimit);
dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
def1 = defaults->bapmti_r;
def2 = defaults->bapmti_rc;
for (i = 0; i < SMU71_DTE_ITERATIONS; i++) {
for (j = 0; j < SMU71_DTE_SOURCES; j++) {
for (k = 0; k < SMU71_DTE_SINKS; k++) {
dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*def1);
dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*def2);
def1++;
def2++;
}
}
}
return 0;
}
static int iceland_populate_svi_load_line(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddc;
data->power_tune_table.SviLoadLineTrimVddC = 3;
data->power_tune_table.SviLoadLineOffsetVddC = 0;
return 0;
}
static int iceland_populate_tdc_limit(struct pp_hwmgr *hwmgr)
{
uint16_t tdc_limit;
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
/* TDC number of fraction bits are changed from 8 to 7
* for Iceland as requested by SMC team
*/
tdc_limit = (uint16_t)(hwmgr->dyn_state.cac_dtp_table->usTDC * 256);
data->power_tune_table.TDC_VDDC_PkgLimit =
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
defaults->tdc_vddc_throttle_release_limit_perc;
data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
return 0;
}
static int iceland_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
const struct iceland_pt_defaults *defaults = data->power_tune_defaults;
uint32_t temp;
if (smu7_read_smc_sram_dword(hwmgr->smumgr,
fuse_table_offset +
offsetof(SMU71_Discrete_PmFuses, TdcWaterfallCtl),
(uint32_t *)&temp, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
else
data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
return 0;
}
static int iceland_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
{
return 0;
}
static int iceland_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
{
int i;
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 8; i++)
data->power_tune_table.GnbLPML[i] = 0;
return 0;
}
static int iceland_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
{
return 0;
}
static int iceland_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
uint16_t HiSidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
uint16_t LoSidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
LoSidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
CONVERT_FROM_HOST_TO_SMC_US(HiSidd);
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
CONVERT_FROM_HOST_TO_SMC_US(LoSidd);
return 0;
}
int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
uint32_t pm_fuse_table_offset;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (smu7_read_smc_sram_dword(hwmgr->smumgr,
SMU71_FIRMWARE_HEADER_LOCATION +
offsetof(SMU71_Firmware_Header, PmFuseTable),
&pm_fuse_table_offset, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to get pm_fuse_table_offset Failed!",
return -EINVAL);
/* DW0 - DW3 */
if (iceland_populate_bapm_vddc_vid_sidd(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate bapm vddc vid Failed!",
return -EINVAL);
/* DW4 - DW5 */
if (iceland_populate_vddc_vid(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate vddc vid Failed!",
return -EINVAL);
/* DW6 */
if (iceland_populate_svi_load_line(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate SviLoadLine Failed!",
return -EINVAL);
/* DW7 */
if (iceland_populate_tdc_limit(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TDCLimit Failed!", return -EINVAL);
/* DW8 */
if (iceland_populate_dw8(hwmgr, pm_fuse_table_offset))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TdcWaterfallCtl, "
"LPMLTemperature Min and Max Failed!",
return -EINVAL);
/* DW9-DW12 */
if (0 != iceland_populate_temperature_scaler(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate LPMLTemperatureScaler Failed!",
return -EINVAL);
/* DW13-DW16 */
if (iceland_populate_gnb_lpml(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Failed!",
return -EINVAL);
/* DW17 */
if (iceland_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Min and Max Vid Failed!",
return -EINVAL);
/* DW18 */
if (iceland_populate_bapm_vddc_base_leakage_sidd(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
return -EINVAL);
if (smu7_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
(uint8_t *)&data->power_tune_table,
sizeof(struct SMU71_Discrete_PmFuses), data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to download PmFuseTable Failed!",
return -EINVAL);
}
return 0;
}
int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC)) {
int smc_result;
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableCac));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable CAC in SMC.", result = -1);
data->cac_enabled = (0 == smc_result) ? true : false;
}
return result;
}
static int iceland_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
if(data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_PkgPwrSetLimit, n);
return 0;
}
static int iceland_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
{
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
}
int iceland_enable_power_containment(struct pp_hwmgr *hwmgr)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
SMU71_Discrete_DpmTable *dpm_table = &data->smc_state_table;
int smc_result;
int result = 0;
uint32_t is_asic_kicker;
data->power_containment_features = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
is_asic_kicker = cgs_read_register(hwmgr->device, mmCC_BIF_BX_STRAP2);
is_asic_kicker = (is_asic_kicker >> 12) & 0x01;
if (data->enable_bapm_feature &&
(!is_asic_kicker ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc))) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableDTE));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable BAPM in SMC.", result = -1;);
if (0 == smc_result)
data->power_containment_features |= POWERCONTAINMENT_FEATURE_BAPM;
}
if (is_asic_kicker && !phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_DisableUsingActualTemperatureForPowerCalc))
dpm_table->DTEMode = 2;
if (data->enable_tdc_limit_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable TDCLimit in SMC.", result = -1;);
if (0 == smc_result)
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_TDCLimit;
}
if (data->enable_pkg_pwr_tracking_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
if (0 == smc_result) {
struct phm_cac_tdp_table *cac_table =
hwmgr->dyn_state.cac_dtp_table;
uint32_t default_limit =
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
if (iceland_set_power_limit(hwmgr, default_limit))
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
}
}
}
return result;
}
int iceland_power_control_set_level(struct pp_hwmgr *hwmgr)
{
struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table;
int adjust_percent, target_tdp;
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
/* adjustment percentage has already been validated */
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
hwmgr->platform_descriptor.TDPAdjustment :
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
/*
* SMC requested that target_tdp to be 7 bit fraction in DPM table
* but message to be 8 bit fraction for messages
*/
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
result = iceland_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
}
return result;
}
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#ifndef ICELAND_POWERTUNE_H
#define ICELAND_POWERTUNE_H
#include "smu71.h"
enum iceland_pt_config_reg_type {
ICELAND_CONFIGREG_MMR = 0,
ICELAND_CONFIGREG_SMC_IND,
ICELAND_CONFIGREG_DIDT_IND,
ICELAND_CONFIGREG_CACHE,
ICELAND_CONFIGREG_MAX
};
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
struct iceland_pt_config_reg {
uint32_t offset;
uint32_t mask;
uint32_t shift;
uint32_t value;
enum iceland_pt_config_reg_type type;
};
void iceland_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
int iceland_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
int iceland_populate_pm_fuses(struct pp_hwmgr *hwmgr);
int iceland_enable_smc_cac(struct pp_hwmgr *hwmgr);
int iceland_enable_power_containment(struct pp_hwmgr *hwmgr);
int iceland_power_control_set_level(struct pp_hwmgr *hwmgr);
#endif /* ICELAND_POWERTUNE_H */
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#include <asm/div64.h>
#include "iceland_thermal.h"
#include "iceland_hwmgr.h"
#include "iceland_smumgr.h"
#include "atombios.h"
#include "ppsmc.h"
#include "gmc/gmc_8_1_d.h"
#include "gmc/gmc_8_1_sh_mask.h"
#include "bif/bif_5_0_d.h"
#include "bif/bif_5_0_sh_mask.h"
#include "smu/smu_7_1_1_d.h"
#include "smu/smu_7_1_1_sh_mask.h"
/**
* Get Fan Speed Control Parameters.
* @param hwmgr the address of the powerplay hardware manager.
* @param pSpeed is the address of the structure where the result is to be placed.
* @exception Always succeeds except if we cannot zero out the output structure.
*/
int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
struct phm_fan_speed_info *fan_speed_info)
{
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
fan_speed_info->supports_percent_read = true;
fan_speed_info->supports_percent_write = true;
fan_speed_info->min_percent = 0;
fan_speed_info->max_percent = 100;
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
fan_speed_info->supports_rpm_read = true;
fan_speed_info->supports_rpm_write = true;
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
} else {
fan_speed_info->min_rpm = 0;
fan_speed_info->max_rpm = 0;
}
return 0;
}
/**
* Get Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param pSpeed is the address of the structure where the result is to be placed.
* @exception Fails is the 100% setting appears to be 0.
*/
int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
if (0 == duty100)
return -EINVAL;
tmp64 = (uint64_t)duty * 100;
do_div(tmp64, duty100);
*speed = (uint32_t)tmp64;
if (*speed > 100)
*speed = 100;
return 0;
}
/**
* Get Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the address of the structure where the result is to be placed.
* @exception Returns not supported if no fan is found or if pulses per revolution are not set
*/
int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
return 0;
}
/**
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
* @param hwmgr the address of the powerplay hardware manager.
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
* @exception Should always succeed.
*/
int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
{
if (hwmgr->fan_ctrl_is_in_default_mode) {
hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
hwmgr->fan_ctrl_is_in_default_mode = false;
}
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
return 0;
}
/**
* Reset Fan Speed Control to default mode.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Should always succeed.
*/
static int iceland_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->fan_ctrl_is_in_default_mode) {
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
hwmgr->fan_ctrl_is_in_default_mode = true;
}
return 0;
}
int iceland_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
{
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
}
int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
{
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL;
}
/**
* Set Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (0% - 100%) to be set.
* @exception Fails is the 100% setting appears to be 0.
*/
int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return -EINVAL;
if (speed > 100) {
pr_warning("Cannot set more than 100%% duty cycle. Set it to 100.\n");
speed = 100;
}
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
iceland_fan_ctrl_stop_smc_fan_control(hwmgr);
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
if (0 == duty100)
return -EINVAL;
tmp64 = (uint64_t)speed * duty100;
do_div(tmp64, 100);
duty = (uint32_t)tmp64;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
return iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reset Fan Speed to default.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Always succeeds.
*/
int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
{
int result;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
result = iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
if (0 == result)
result = iceland_fan_ctrl_start_smc_fan_control(hwmgr);
} else
result = iceland_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (min - max) to be set.
* @exception Fails is the speed not lie between min and max.
*/
int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
{
return 0;
}
/**
* Reads the remote temperature from the SIslands thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr)
{
int temp;
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
/*
* Bit 9 means the reading is lower than the lowest usable
* value.
*/
if (0 != (0x200 & temp))
temp = ICELAND_THERMAL_MAXIMUM_TEMP_READING;
else
temp = (temp & 0x1ff);
temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
return temp;
}
/**
* Set the requested temperature range for high and low alert signals
*
* @param hwmgr The address of the hardware manager.
* @param range Temperature range to be programmed for high and low alert signals
* @exception PP_Result_BadInput if the input data is not valid.
*/
static int iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
{
uint32_t low = ICELAND_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
uint32_t high = ICELAND_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
if (low < low_temp)
low = low_temp;
if (high > high_temp)
high = high_temp;
if (low > high)
return -EINVAL;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
return 0;
}
/**
* Programs thermal controller one-time setting registers
*
* @param hwmgr The address of the hardware manager.
*/
static int iceland_thermal_initialize(struct pp_hwmgr *hwmgr)
{
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_CTRL, EDGE_PER_REV,
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
return 0;
}
/**
* Enable thermal alerts on the RV770 thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
static int iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
alert &= ~(ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to enable internal thermal interrupts */
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
}
/**
* Disable thermal alerts on the RV770 thermal controller.
* @param hwmgr The address of the hardware manager.
*/
static int iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
alert |= (ICELAND_THERMAL_HIGH_ALERT_MASK | ICELAND_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to disable internal thermal interrupts */
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
}
/**
* Uninitialize the thermal controller.
* Currently just disables alerts.
* @param hwmgr The address of the hardware manager.
*/
int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
{
int result = iceland_thermal_disable_alert(hwmgr);
if (result)
pr_warning("Failed to disable thermal alerts!\n");
if (hwmgr->thermal_controller.fanInfo.bNoFan)
iceland_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set up the fan table to control the fan using the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_iceland_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
struct iceland_hwmgr *data = (struct iceland_hwmgr *)(hwmgr->backend);
SMU71_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
uint32_t duty100;
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
uint16_t fdo_min, slope1, slope2;
uint32_t reference_clock;
int res;
uint64_t tmp64;
if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
return 0;
if (0 == data->fan_table_start) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
if (0 == duty100) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
do_div(tmp64, 10000);
fdo_min = (uint16_t)tmp64;
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
fan_table.Slope1 = cpu_to_be16(slope1);
fan_table.Slope2 = cpu_to_be16(slope2);
fan_table.FdoMin = cpu_to_be16(fdo_min);
fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
fan_table.HystUp = cpu_to_be16(1);
fan_table.HystSlope = cpu_to_be16(1);
fan_table.TempRespLim = cpu_to_be16(5);
reference_clock = iceland_get_xclk(hwmgr);
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
//fan_table.FanControl_GL_Flag = 1;
res = smu7_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
if (0 != res)
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
*/
return 0;
}
/**
* Start the fan control on the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_iceland_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
* Make sure that we still think controlling the fan is OK.
*/
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
iceland_fan_ctrl_start_smc_fan_control(hwmgr);
iceland_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
return 0;
}
/**
* Set temperature range for high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
static int tf_iceland_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
if (range == NULL)
return -EINVAL;
return iceland_thermal_set_temperature_range(hwmgr, range->min, range->max);
}
/**
* Programs one-time setting registers
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from initialize thermal controller routine
*/
static int tf_iceland_thermal_initialize(struct pp_hwmgr *hwmgr, void *input,
void *output, void *storage, int result)
{
return iceland_thermal_initialize(hwmgr);
}
/**
* Enable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from enable alert routine
*/
static int tf_iceland_thermal_enable_alert(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return iceland_thermal_enable_alert(hwmgr);
}
/**
* Disable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from disable alert routine
*/
static int tf_iceland_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
return iceland_thermal_disable_alert(hwmgr);
}
static const struct phm_master_table_item iceland_thermal_start_thermal_controller_master_list[] = {
{ NULL, tf_iceland_thermal_initialize },
{ NULL, tf_iceland_thermal_set_temperature_range },
{ NULL, tf_iceland_thermal_enable_alert },
/*
* We should restrict performance levels to low before we halt
* the SMC. On the other hand we are still in boot state when
* we do this so it would be pointless. If this assumption
* changes we have to revisit this table.
*/
{ NULL, tf_iceland_thermal_setup_fan_table},
{ NULL, tf_iceland_thermal_start_smc_fan_control},
{ NULL, NULL }
};
static const struct phm_master_table_header iceland_thermal_start_thermal_controller_master = {
0,
PHM_MasterTableFlag_None,
iceland_thermal_start_thermal_controller_master_list
};
static const struct phm_master_table_item iceland_thermal_set_temperature_range_master_list[] = {
{ NULL, tf_iceland_thermal_disable_alert},
{ NULL, tf_iceland_thermal_set_temperature_range},
{ NULL, tf_iceland_thermal_enable_alert},
{ NULL, NULL }
};
static const struct phm_master_table_header iceland_thermal_set_temperature_range_master = {
0,
PHM_MasterTableFlag_None,
iceland_thermal_set_temperature_range_master_list
};
int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
iceland_fan_ctrl_set_default_mode(hwmgr);
return 0;
}
/**
* Initializes the thermal controller related functions in the Hardware Manager structure.
* @param hwmgr The address of the hardware manager.
* @exception Any error code from the low-level communication.
*/
int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr)
{
int result;
result = phm_construct_table(hwmgr, &iceland_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
if (0 == result) {
result = phm_construct_table(hwmgr,
&iceland_thermal_start_thermal_controller_master,
&(hwmgr->start_thermal_controller));
if (0 != result)
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
}
if (0 == result)
hwmgr->fan_ctrl_is_in_default_mode = true;
return result;
}
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Author: Huang Rui <ray.huang@amd.com>
*
*/
#ifndef ICELAND_THERMAL_H
#define ICELAND_THERMAL_H
#include "hwmgr.h"
#define ICELAND_THERMAL_HIGH_ALERT_MASK 0x1
#define ICELAND_THERMAL_LOW_ALERT_MASK 0x2
#define ICELAND_THERMAL_MINIMUM_TEMP_READING -256
#define ICELAND_THERMAL_MAXIMUM_TEMP_READING 255
#define ICELAND_THERMAL_MINIMUM_ALERT_TEMP 0
#define ICELAND_THERMAL_MAXIMUM_ALERT_TEMP 255
#define FDO_PWM_MODE_STATIC 1
#define FDO_PWM_MODE_STATIC_RPM 5
extern int iceland_thermal_get_temperature(struct pp_hwmgr *hwmgr);
extern int iceland_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
extern int iceland_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
extern int iceland_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int iceland_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
extern int iceland_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int iceland_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
extern int pp_iceland_thermal_initialize(struct pp_hwmgr *hwmgr);
extern int iceland_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
extern int iceland_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int iceland_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int iceland_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "polaris10_clockpowergating.h"
int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_uvd_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_UVDPowerOFF);
return 0;
}
static int polaris10_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_uvd_power_gating(hwmgr)) {
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_UVDDynamicPowerGating)) {
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_UVDPowerON, 1);
} else {
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_UVDPowerON, 0);
}
}
return 0;
}
static int polaris10_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_vce_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_VCEPowerOFF);
return 0;
}
static int polaris10_phm_powerup_vce(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_vce_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_VCEPowerON);
return 0;
}
static int polaris10_phm_powerdown_samu(struct pp_hwmgr *hwmgr)
{
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SamuPowerGating))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_SAMPowerOFF);
return 0;
}
static int polaris10_phm_powerup_samu(struct pp_hwmgr *hwmgr)
{
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SamuPowerGating))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_SAMPowerON);
return 0;
}
int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
data->uvd_power_gated = false;
data->vce_power_gated = false;
data->samu_power_gated = false;
polaris10_phm_powerup_uvd(hwmgr);
polaris10_phm_powerup_vce(hwmgr);
polaris10_phm_powerup_samu(hwmgr);
return 0;
}
int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if (data->uvd_power_gated == bgate)
return 0;
data->uvd_power_gated = bgate;
if (bgate) {
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_CG_STATE_GATE);
polaris10_update_uvd_dpm(hwmgr, true);
polaris10_phm_powerdown_uvd(hwmgr);
} else {
polaris10_phm_powerup_uvd(hwmgr);
polaris10_update_uvd_dpm(hwmgr, false);
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_CG_STATE_UNGATE);
}
return 0;
}
int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if (data->vce_power_gated == bgate)
return 0;
data->vce_power_gated = bgate;
if (bgate) {
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_CG_STATE_GATE);
polaris10_update_vce_dpm(hwmgr, true);
polaris10_phm_powerdown_vce(hwmgr);
} else {
polaris10_phm_powerup_vce(hwmgr);
polaris10_update_vce_dpm(hwmgr, false);
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_CG_STATE_UNGATE);
}
return 0;
}
int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if (data->samu_power_gated == bgate)
return 0;
data->samu_power_gated = bgate;
if (bgate) {
polaris10_update_samu_dpm(hwmgr, true);
polaris10_phm_powerdown_samu(hwmgr);
} else {
polaris10_phm_powerup_samu(hwmgr);
polaris10_update_samu_dpm(hwmgr, false);
}
return 0;
}
int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
const uint32_t *msg_id)
{
PPSMC_Msg msg;
uint32_t value;
switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
case PP_GROUP_GFX:
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
case PP_BLOCK_GFX_CG:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_CGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_CGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_GFX_3D:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_3DCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_3DLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_GFX_RLC:
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_RLC_LS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_GFX_CP:
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_CP_LS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_GFX_MG:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = (CG_CPF_MGCG_MASK | CG_RLC_MGCG_MASK |
CG_GFX_OTHERS_MGCG_MASK);
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
default:
return -1;
}
break;
case PP_GROUP_SYS:
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
case PP_BLOCK_SYS_BIF:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_BIF_MGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_BIF_MGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_MC:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_MC_MGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_MC_MGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_DRM:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_CG ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_DRM_MGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_DRM_MGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_HDP:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_HDP_MGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_HDP_MGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_SDMA:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_SDMA_MGCG_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_SDMA_MGLS_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_ROM:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG) ?
PPSMC_MSG_EnableClockGatingFeature :
PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_ROM_MASK;
if (smum_send_msg_to_smc_with_parameter(
hwmgr->smumgr, msg, value))
return -1;
}
break;
default:
return -1;
}
break;
default:
return -1;
}
return 0;
}
/* This function is for Polaris11 only for now,
* Powerplay will only control the static per CU Power Gating.
* Dynamic per CU Power Gating will be done in gfx.
*/
int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable)
{
struct cgs_system_info sys_info = {0};
uint32_t active_cus;
int result;
sys_info.size = sizeof(struct cgs_system_info);
sys_info.info_id = CGS_SYSTEM_INFO_GFX_CU_INFO;
result = cgs_query_system_info(hwmgr->device, &sys_info);
if (result)
return -EINVAL;
else
active_cus = sys_info.value;
if (enable)
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_GFX_CU_PG_ENABLE, active_cus);
else
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_GFX_CU_PG_DISABLE);
}
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _POLARIS10_CLOCK_POWER_GATING_H_
#define _POLARIS10_CLOCK_POWER_GATING_H_
#include "polaris10_hwmgr.h"
#include "pp_asicblocks.h"
int polaris10_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
int polaris10_phm_powergate_samu(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_phm_powergate_acp(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
int polaris10_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
const uint32_t *msg_id);
int polaris10_phm_enable_per_cu_power_gating(struct pp_hwmgr *hwmgr, bool enable);
#endif /* _POLARIS10_CLOCK_POWER_GATING_H_ */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef POLARIS10_DYN_DEFAULTS_H
#define POLARIS10_DYN_DEFAULTS_H
enum Polaris10dpm_TrendDetection {
Polaris10Adpm_TrendDetection_AUTO,
Polaris10Adpm_TrendDetection_UP,
Polaris10Adpm_TrendDetection_DOWN
};
typedef enum Polaris10dpm_TrendDetection Polaris10dpm_TrendDetection;
/* We need to fill in the default values */
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT1 0x000400
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033
#define PPPOLARIS10_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000
#define PPPOLARIS10_THERMALPROTECTCOUNTER_DFLT 0x200
#define PPPOLARIS10_STATICSCREENTHRESHOLDUNIT_DFLT 0
#define PPPOLARIS10_STATICSCREENTHRESHOLD_DFLT 0x00C8
#define PPPOLARIS10_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200
#define PPPOLARIS10_REFERENCEDIVIDER_DFLT 4
#define PPPOLARIS10_ULVVOLTAGECHANGEDELAY_DFLT 1687
#define PPPOLARIS10_CGULVPARAMETER_DFLT 0x00040035
#define PPPOLARIS10_CGULVCONTROL_DFLT 0x00007450
#define PPPOLARIS10_TARGETACTIVITY_DFLT 50
#define PPPOLARIS10_MCLK_TARGETACTIVITY_DFLT 10
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef POLARIS10_HWMGR_H
#define POLARIS10_HWMGR_H
#include "hwmgr.h"
#include "smu74.h"
#include "smu74_discrete.h"
#include "ppatomctrl.h"
#include "polaris10_ppsmc.h"
#include "polaris10_powertune.h"
#include "polaris10_smumgr.h"
#define POLARIS10_MAX_HARDWARE_POWERLEVELS 2
#define POLARIS10_VOLTAGE_CONTROL_NONE 0x0
#define POLARIS10_VOLTAGE_CONTROL_BY_GPIO 0x1
#define POLARIS10_VOLTAGE_CONTROL_BY_SVID2 0x2
#define POLARIS10_VOLTAGE_CONTROL_MERGED 0x3
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
struct polaris10_performance_level {
uint32_t memory_clock;
uint32_t engine_clock;
uint16_t pcie_gen;
uint16_t pcie_lane;
};
struct polaris10_uvd_clocks {
uint32_t vclk;
uint32_t dclk;
};
struct polaris10_vce_clocks {
uint32_t evclk;
uint32_t ecclk;
};
struct polaris10_power_state {
uint32_t magic;
struct polaris10_uvd_clocks uvd_clks;
struct polaris10_vce_clocks vce_clks;
uint32_t sam_clk;
uint16_t performance_level_count;
bool dc_compatible;
uint32_t sclk_threshold;
struct polaris10_performance_level performance_levels[POLARIS10_MAX_HARDWARE_POWERLEVELS];
};
struct polaris10_dpm_level {
bool enabled;
uint32_t value;
uint32_t param1;
};
#define POLARIS10_MAX_DEEPSLEEP_DIVIDER_ID 5
#define MAX_REGULAR_DPM_NUMBER 8
#define POLARIS10_MINIMUM_ENGINE_CLOCK 2500
struct polaris10_single_dpm_table {
uint32_t count;
struct polaris10_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
};
struct polaris10_dpm_table {
struct polaris10_single_dpm_table sclk_table;
struct polaris10_single_dpm_table mclk_table;
struct polaris10_single_dpm_table pcie_speed_table;
struct polaris10_single_dpm_table vddc_table;
struct polaris10_single_dpm_table vddci_table;
struct polaris10_single_dpm_table mvdd_table;
};
struct polaris10_clock_registers {
uint32_t vCG_SPLL_FUNC_CNTL;
uint32_t vCG_SPLL_FUNC_CNTL_2;
uint32_t vCG_SPLL_FUNC_CNTL_3;
uint32_t vCG_SPLL_FUNC_CNTL_4;
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
uint32_t vDLL_CNTL;
uint32_t vMCLK_PWRMGT_CNTL;
uint32_t vMPLL_AD_FUNC_CNTL;
uint32_t vMPLL_DQ_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL_1;
uint32_t vMPLL_FUNC_CNTL_2;
uint32_t vMPLL_SS1;
uint32_t vMPLL_SS2;
};
#define DISABLE_MC_LOADMICROCODE 1
#define DISABLE_MC_CFGPROGRAMMING 2
struct polaris10_voltage_smio_registers {
uint32_t vS0_VID_LOWER_SMIO_CNTL;
};
#define POLARIS10_MAX_LEAKAGE_COUNT 8
struct polaris10_leakage_voltage {
uint16_t count;
uint16_t leakage_id[POLARIS10_MAX_LEAKAGE_COUNT];
uint16_t actual_voltage[POLARIS10_MAX_LEAKAGE_COUNT];
};
struct polaris10_vbios_boot_state {
uint16_t mvdd_bootup_value;
uint16_t vddc_bootup_value;
uint16_t vddci_bootup_value;
uint32_t sclk_bootup_value;
uint32_t mclk_bootup_value;
uint16_t pcie_gen_bootup_value;
uint16_t pcie_lane_bootup_value;
};
/* Ultra Low Voltage parameter structure */
struct polaris10_ulv_parm {
bool ulv_supported;
uint32_t cg_ulv_parameter;
uint32_t ulv_volt_change_delay;
struct polaris10_performance_level ulv_power_level;
};
struct polaris10_display_timing {
uint32_t min_clock_in_sr;
uint32_t num_existing_displays;
};
struct polaris10_dpmlevel_enable_mask {
uint32_t uvd_dpm_enable_mask;
uint32_t vce_dpm_enable_mask;
uint32_t acp_dpm_enable_mask;
uint32_t samu_dpm_enable_mask;
uint32_t sclk_dpm_enable_mask;
uint32_t mclk_dpm_enable_mask;
uint32_t pcie_dpm_enable_mask;
};
struct polaris10_pcie_perf_range {
uint16_t max;
uint16_t min;
};
struct polaris10_hwmgr {
struct polaris10_dpm_table dpm_table;
struct polaris10_dpm_table golden_dpm_table;
SMU74_Discrete_DpmTable smc_state_table;
struct SMU74_Discrete_Ulv ulv_setting;
struct polaris10_range_table range_table[NUM_SCLK_RANGE];
uint32_t voting_rights_clients0;
uint32_t voting_rights_clients1;
uint32_t voting_rights_clients2;
uint32_t voting_rights_clients3;
uint32_t voting_rights_clients4;
uint32_t voting_rights_clients5;
uint32_t voting_rights_clients6;
uint32_t voting_rights_clients7;
uint32_t static_screen_threshold_unit;
uint32_t static_screen_threshold;
uint32_t voltage_control;
uint32_t vddc_vddci_delta;
uint32_t active_auto_throttle_sources;
struct polaris10_clock_registers clock_registers;
struct polaris10_voltage_smio_registers voltage_smio_registers;
bool is_memory_gddr5;
uint16_t acpi_vddc;
bool pspp_notify_required;
uint16_t force_pcie_gen;
uint16_t acpi_pcie_gen;
uint32_t pcie_gen_cap;
uint32_t pcie_lane_cap;
uint32_t pcie_spc_cap;
struct polaris10_leakage_voltage vddc_leakage;
struct polaris10_leakage_voltage Vddci_leakage;
uint32_t mvdd_control;
uint32_t vddc_mask_low;
uint32_t mvdd_mask_low;
uint16_t max_vddc_in_pptable;
uint16_t min_vddc_in_pptable;
uint16_t max_vddci_in_pptable;
uint16_t min_vddci_in_pptable;
uint32_t mclk_strobe_mode_threshold;
uint32_t mclk_stutter_mode_threshold;
uint32_t mclk_edc_enable_threshold;
uint32_t mclk_edcwr_enable_threshold;
bool is_uvd_enabled;
struct polaris10_vbios_boot_state vbios_boot_state;
bool pcie_performance_request;
bool battery_state;
bool is_tlu_enabled;
/* ---- SMC SRAM Address of firmware header tables ---- */
uint32_t sram_end;
uint32_t dpm_table_start;
uint32_t soft_regs_start;
uint32_t mc_reg_table_start;
uint32_t fan_table_start;
uint32_t arb_table_start;
/* ---- Stuff originally coming from Evergreen ---- */
uint32_t vddci_control;
struct pp_atomctrl_voltage_table vddc_voltage_table;
struct pp_atomctrl_voltage_table vddci_voltage_table;
struct pp_atomctrl_voltage_table mvdd_voltage_table;
uint32_t mgcg_cgtt_local2;
uint32_t mgcg_cgtt_local3;
uint32_t gpio_debug;
uint32_t mc_micro_code_feature;
uint32_t highest_mclk;
uint16_t acpi_vddci;
uint8_t mvdd_high_index;
uint8_t mvdd_low_index;
bool dll_default_on;
bool performance_request_registered;
/* ---- Low Power Features ---- */
struct polaris10_ulv_parm ulv;
/* ---- CAC Stuff ---- */
uint32_t cac_table_start;
bool cac_configuration_required;
bool driver_calculate_cac_leakage;
bool cac_enabled;
/* ---- DPM2 Parameters ---- */
uint32_t power_containment_features;
bool enable_dte_feature;
bool enable_tdc_limit_feature;
bool enable_pkg_pwr_tracking_feature;
bool disable_uvd_power_tune_feature;
const struct polaris10_pt_defaults *power_tune_defaults;
struct SMU74_Discrete_PmFuses power_tune_table;
uint32_t dte_tj_offset;
uint32_t fast_watermark_threshold;
/* ---- Phase Shedding ---- */
bool vddc_phase_shed_control;
/* ---- DI/DT ---- */
struct polaris10_display_timing display_timing;
uint32_t bif_sclk_table[SMU74_MAX_LEVELS_LINK];
/* ---- Thermal Temperature Setting ---- */
struct polaris10_dpmlevel_enable_mask dpm_level_enable_mask;
uint32_t need_update_smu7_dpm_table;
uint32_t sclk_dpm_key_disabled;
uint32_t mclk_dpm_key_disabled;
uint32_t pcie_dpm_key_disabled;
uint32_t min_engine_clocks;
struct polaris10_pcie_perf_range pcie_gen_performance;
struct polaris10_pcie_perf_range pcie_lane_performance;
struct polaris10_pcie_perf_range pcie_gen_power_saving;
struct polaris10_pcie_perf_range pcie_lane_power_saving;
bool use_pcie_performance_levels;
bool use_pcie_power_saving_levels;
uint32_t activity_target[SMU74_MAX_LEVELS_GRAPHICS];
uint32_t mclk_activity_target;
uint32_t mclk_dpm0_activity_target;
uint32_t low_sclk_interrupt_threshold;
uint32_t last_mclk_dpm_enable_mask;
bool uvd_enabled;
/* ---- Power Gating States ---- */
bool uvd_power_gated;
bool vce_power_gated;
bool samu_power_gated;
bool need_long_memory_training;
/* Application power optimization parameters */
bool update_up_hyst;
bool update_down_hyst;
uint32_t down_hyst;
uint32_t up_hyst;
uint32_t disable_dpm_mask;
bool apply_optimized_settings;
uint32_t avfs_vdroop_override_setting;
bool apply_avfs_cks_off_voltage;
uint32_t frame_time_x2;
};
/* To convert to Q8.8 format for firmware */
#define POLARIS10_Q88_FORMAT_CONVERSION_UNIT 256
enum Polaris10_I2CLineID {
Polaris10_I2CLineID_DDC1 = 0x90,
Polaris10_I2CLineID_DDC2 = 0x91,
Polaris10_I2CLineID_DDC3 = 0x92,
Polaris10_I2CLineID_DDC4 = 0x93,
Polaris10_I2CLineID_DDC5 = 0x94,
Polaris10_I2CLineID_DDC6 = 0x95,
Polaris10_I2CLineID_SCLSDA = 0x96,
Polaris10_I2CLineID_DDCVGA = 0x97
};
#define POLARIS10_I2C_DDC1DATA 0
#define POLARIS10_I2C_DDC1CLK 1
#define POLARIS10_I2C_DDC2DATA 2
#define POLARIS10_I2C_DDC2CLK 3
#define POLARIS10_I2C_DDC3DATA 4
#define POLARIS10_I2C_DDC3CLK 5
#define POLARIS10_I2C_SDA 40
#define POLARIS10_I2C_SCL 41
#define POLARIS10_I2C_DDC4DATA 65
#define POLARIS10_I2C_DDC4CLK 66
#define POLARIS10_I2C_DDC5DATA 0x48
#define POLARIS10_I2C_DDC5CLK 0x49
#define POLARIS10_I2C_DDC6DATA 0x4a
#define POLARIS10_I2C_DDC6CLK 0x4b
#define POLARIS10_I2C_DDCVGADATA 0x4c
#define POLARIS10_I2C_DDCVGACLK 0x4d
#define POLARIS10_UNUSED_GPIO_PIN 0x7F
int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr);
int polaris10_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_update_samu_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int polaris10_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
int polaris10_update_vce_dpm(struct pp_hwmgr *hwmgr, bool bgate);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "hwmgr.h"
#include "smumgr.h"
#include "polaris10_hwmgr.h"
#include "polaris10_powertune.h"
#include "polaris10_smumgr.h"
#include "smu74_discrete.h"
#include "pp_debug.h"
#include "gca/gfx_8_0_d.h"
#include "gca/gfx_8_0_sh_mask.h"
#include "oss/oss_3_0_sh_mask.h"
#define VOLTAGE_SCALE 4
#define POWERTUNE_DEFAULT_SET_MAX 1
uint32_t DIDTBlock_Info = SQ_IR_MASK | TCP_IR_MASK | TD_PCC_MASK;
struct polaris10_pt_config_reg GCCACConfig_Polaris10[] = {
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Offset Mask Shift Value Type
* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00060013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00860013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01060013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01860013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02060013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02860013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x03060013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x03860013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x04060013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x000E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x008E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x010E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x018E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x020E0013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00100013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00900013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01100013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01900013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02100013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02900013, POLARIS10_CONFIGREG_GC_CAC_IND },
{ 0xFFFFFFFF }
};
struct polaris10_pt_config_reg GCCACConfig_Polaris11[] = {
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Offset Mask Shift Value Type
* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00060011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00860011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01060011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01860011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02060011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02860011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x03060011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x03860011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x04060011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x000E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x008E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x010E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x018E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x020E0011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00100011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x00900011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01100011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x01900011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02100011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ ixGC_CAC_CNTL, 0xFFFFFFFF, 0, 0x02900011, POLARIS10_CONFIGREG_GC_CAC_IND },
{ 0xFFFFFFFF }
};
struct polaris10_pt_config_reg DIDTConfig_Polaris10[] = {
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Offset Mask Shift Value Type
* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT0_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT0__SHIFT, 0x0073, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT1_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT1__SHIFT, 0x00ab, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT2_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT2__SHIFT, 0x0084, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT3_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT3__SHIFT, 0x005a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT4_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT4__SHIFT, 0x0067, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT5_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT5__SHIFT, 0x0084, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT6_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT6__SHIFT, 0x0027, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT7_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT7__SHIFT, 0x0046, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT8_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT8__SHIFT, 0x00aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT9_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT9__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT10_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT10__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT11_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT11__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MIN_POWER_MASK, DIDT_SQ_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MAX_POWER_MASK, DIDT_SQ_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3853, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_0_MASK, DIDT_SQ_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x005a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_1_MASK, DIDT_SQ_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_2_MASK, DIDT_SQ_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x0ebb, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__UNUSED_0_MASK, DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3853, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3153, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK, DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK, DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__PHASE_OFFSET_MASK, DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__UNUSED_0_MASK, DIDT_SQ_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT0_MASK, DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT, 0x000a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT1_MASK, DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT2_MASK, DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT, 0x0017, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT3_MASK, DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT, 0x002f, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT4_MASK, DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT, 0x0046, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT5_MASK, DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT, 0x005d, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT6_MASK, DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT7_MASK, DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MIN_POWER_MASK, DIDT_TD_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MAX_POWER_MASK, DIDT_TD_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__UNUSED_0_MASK, DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0x00ff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_0_MASK, DIDT_TD_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x000f, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_1_MASK, DIDT_TD_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_2_MASK, DIDT_TD_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__UNUSED_0_MASK, DIDT_TD_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x0dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x0dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__UNUSED_0_MASK, DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__USE_REF_CLOCK_MASK, DIDT_TD_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__PHASE_OFFSET_MASK, DIDT_TD_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TD_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0009, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0009, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__UNUSED_0_MASK, DIDT_TD_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT0_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT0__SHIFT, 0x0004, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT1_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT1__SHIFT, 0x0037, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT2_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT2__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT3_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT3__SHIFT, 0x00ff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT4_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT4__SHIFT, 0x0054, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT5_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT5__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT6_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT7_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MIN_POWER_MASK, DIDT_TCP_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MAX_POWER_MASK, DIDT_TCP_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__UNUSED_0_MASK, DIDT_TCP_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TCP_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_0_MASK, DIDT_TCP_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x0032, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_1_MASK, DIDT_TCP_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_2_MASK, DIDT_TCP_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__UNUSED_0_MASK, DIDT_TCP_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK, DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__USE_REF_CLOCK_MASK, DIDT_TCP_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__PHASE_OFFSET_MASK, DIDT_TCP_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__UNUSED_0_MASK, DIDT_TCP_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ 0xFFFFFFFF }
};
struct polaris10_pt_config_reg DIDTConfig_Polaris11[] = {
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
* Offset Mask Shift Value Type
* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
*/
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT0_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT0__SHIFT, 0x0073, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT1_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT1__SHIFT, 0x00ab, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT2_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT2__SHIFT, 0x0084, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT0_3, DIDT_SQ_WEIGHT0_3__WEIGHT3_MASK, DIDT_SQ_WEIGHT0_3__WEIGHT3__SHIFT, 0x005a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT4_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT4__SHIFT, 0x0067, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT5_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT5__SHIFT, 0x0084, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT6_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT6__SHIFT, 0x0027, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT4_7, DIDT_SQ_WEIGHT4_7__WEIGHT7_MASK, DIDT_SQ_WEIGHT4_7__WEIGHT7__SHIFT, 0x0046, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT8_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT8__SHIFT, 0x00aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT9_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT9__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT10_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT10__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_WEIGHT8_11, DIDT_SQ_WEIGHT8_11__WEIGHT11_MASK, DIDT_SQ_WEIGHT8_11__WEIGHT11__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MIN_POWER_MASK, DIDT_SQ_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL1, DIDT_SQ_CTRL1__MAX_POWER_MASK, DIDT_SQ_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__UNUSED_0_MASK, DIDT_SQ_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL_OCP, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_SQ_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__MAX_POWER_DELTA_MASK, DIDT_SQ_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3853, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_0_MASK, DIDT_SQ_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_SQ_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x005a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_1_MASK, DIDT_SQ_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_SQ_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL2, DIDT_SQ_CTRL2__UNUSED_2_MASK, DIDT_SQ_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_SQ_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_SQ_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x0ebb, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_STALL_CTRL, DIDT_SQ_STALL_CTRL__UNUSED_0_MASK, DIDT_SQ_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_SQ_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3853, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_SQ_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3153, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_TUNING_CTRL, DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK, DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__USE_REF_CLOCK_MASK, DIDT_SQ_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__PHASE_OFFSET_MASK, DIDT_SQ_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CTRL_RST_MASK, DIDT_SQ_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_SQ_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_SQ_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_SQ_CTRL0, DIDT_SQ_CTRL0__UNUSED_0_MASK, DIDT_SQ_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT0_MASK, DIDT_TD_WEIGHT0_3__WEIGHT0__SHIFT, 0x000a, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT1_MASK, DIDT_TD_WEIGHT0_3__WEIGHT1__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT2_MASK, DIDT_TD_WEIGHT0_3__WEIGHT2__SHIFT, 0x0017, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT0_3, DIDT_TD_WEIGHT0_3__WEIGHT3_MASK, DIDT_TD_WEIGHT0_3__WEIGHT3__SHIFT, 0x002f, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT4_MASK, DIDT_TD_WEIGHT4_7__WEIGHT4__SHIFT, 0x0046, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT5_MASK, DIDT_TD_WEIGHT4_7__WEIGHT5__SHIFT, 0x005d, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT6_MASK, DIDT_TD_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_WEIGHT4_7, DIDT_TD_WEIGHT4_7__WEIGHT7_MASK, DIDT_TD_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MIN_POWER_MASK, DIDT_TD_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL1, DIDT_TD_CTRL1__MAX_POWER_MASK, DIDT_TD_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__UNUSED_0_MASK, DIDT_TD_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL_OCP, DIDT_TD_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TD_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0x00ff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TD_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3fff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_0_MASK, DIDT_TD_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TD_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x000f, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_1_MASK, DIDT_TD_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TD_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL2, DIDT_TD_CTRL2__UNUSED_2_MASK, DIDT_TD_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TD_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TD_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_STALL_CTRL, DIDT_TD_STALL_CTRL__UNUSED_0_MASK, DIDT_TD_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TD_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x0dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TD_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x0dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_TUNING_CTRL, DIDT_TD_TUNING_CTRL__UNUSED_0_MASK, DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__USE_REF_CLOCK_MASK, DIDT_TD_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__PHASE_OFFSET_MASK, DIDT_TD_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TD_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TD_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0008, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TD_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0008, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TD_CTRL0, DIDT_TD_CTRL0__UNUSED_0_MASK, DIDT_TD_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT0_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT0__SHIFT, 0x0004, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT1_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT1__SHIFT, 0x0037, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT2_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT2__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT0_3, DIDT_TCP_WEIGHT0_3__WEIGHT3_MASK, DIDT_TCP_WEIGHT0_3__WEIGHT3__SHIFT, 0x00ff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT4_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT4__SHIFT, 0x0054, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT5_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT5__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT6_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT6__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_WEIGHT4_7, DIDT_TCP_WEIGHT4_7__WEIGHT7_MASK, DIDT_TCP_WEIGHT4_7__WEIGHT7__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MIN_POWER_MASK, DIDT_TCP_CTRL1__MIN_POWER__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL1, DIDT_TCP_CTRL1__MAX_POWER_MASK, DIDT_TCP_CTRL1__MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__UNUSED_0_MASK, DIDT_TCP_CTRL_OCP__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL_OCP, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER_MASK, DIDT_TCP_CTRL_OCP__OCP_MAX_POWER__SHIFT, 0xffff, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__MAX_POWER_DELTA_MASK, DIDT_TCP_CTRL2__MAX_POWER_DELTA__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_0_MASK, DIDT_TCP_CTRL2__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE_MASK, DIDT_TCP_CTRL2__SHORT_TERM_INTERVAL_SIZE__SHIFT, 0x0032, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_1_MASK, DIDT_TCP_CTRL2__UNUSED_1__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO_MASK, DIDT_TCP_CTRL2__LONG_TERM_INTERVAL_RATIO__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL2, DIDT_TCP_CTRL2__UNUSED_2_MASK, DIDT_TCP_CTRL2__UNUSED_2__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_CTRL_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_HI__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO_MASK, DIDT_TCP_STALL_CTRL__DIDT_STALL_DELAY_LO__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD_MASK, DIDT_TCP_STALL_CTRL__DIDT_HI_POWER_THRESHOLD__SHIFT, 0x01aa, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_STALL_CTRL, DIDT_TCP_STALL_CTRL__UNUSED_0_MASK, DIDT_TCP_STALL_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE_MASK, DIDT_TCP_TUNING_CTRL__DIDT_TUNING_ENABLE__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_HI__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO_MASK, DIDT_TCP_TUNING_CTRL__MAX_POWER_DELTA_LO__SHIFT, 0x3dde, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_TUNING_CTRL, DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK, DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT, 0x0001, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__USE_REF_CLOCK_MASK, DIDT_TCP_CTRL0__USE_REF_CLOCK__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__PHASE_OFFSET_MASK, DIDT_TCP_CTRL0__PHASE_OFFSET__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CTRL_RST_MASK, DIDT_TCP_CTRL0__DIDT_CTRL_RST__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE_MASK, DIDT_TCP_CTRL0__DIDT_CLK_EN_OVERRIDE__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_HI__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO_MASK, DIDT_TCP_CTRL0__DIDT_MAX_STALLS_ALLOWED_LO__SHIFT, 0x0010, POLARIS10_CONFIGREG_DIDT_IND },
{ ixDIDT_TCP_CTRL0, DIDT_TCP_CTRL0__UNUSED_0_MASK, DIDT_TCP_CTRL0__UNUSED_0__SHIFT, 0x0000, POLARIS10_CONFIGREG_DIDT_IND },
{ 0xFFFFFFFF }
};
static const struct polaris10_pt_defaults polaris10_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
/* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt,
* TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */
{ 1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
{ 0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
{ 0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } },
};
void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *polaris10_hwmgr = (struct polaris10_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
if (table_info &&
table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
table_info->cac_dtp_table->usPowerTuneDataSetID)
polaris10_hwmgr->power_tune_defaults =
&polaris10_power_tune_data_set_array
[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
else
polaris10_hwmgr->power_tune_defaults = &polaris10_power_tune_data_set_array[0];
}
static uint16_t scale_fan_gain_settings(uint16_t raw_setting)
{
uint32_t tmp;
tmp = raw_setting * 4096 / 100;
return (uint16_t)tmp;
}
int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
SMU74_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
struct pp_advance_fan_control_parameters *fan_table=
&hwmgr->thermal_controller.advanceFanControlParameters;
int i, j, k;
const uint16_t *pdef1;
const uint16_t *pdef2;
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
dpm_table->TargetTdp = PP_HOST_TO_SMC_US((uint16_t)(cac_dtp_table->usTDP * 128));
PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
"Target Operating Temp is out of Range!",
);
dpm_table->TemperatureLimitEdge = PP_HOST_TO_SMC_US(
cac_dtp_table->usTargetOperatingTemp * 256);
dpm_table->TemperatureLimitHotspot = PP_HOST_TO_SMC_US(
cac_dtp_table->usTemperatureLimitHotspot * 256);
dpm_table->FanGainEdge = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainEdge));
dpm_table->FanGainHotspot = PP_HOST_TO_SMC_US(
scale_fan_gain_settings(fan_table->usFanGainHotspot));
pdef1 = defaults->BAPMTI_R;
pdef2 = defaults->BAPMTI_RC;
for (i = 0; i < SMU74_DTE_ITERATIONS; i++) {
for (j = 0; j < SMU74_DTE_SOURCES; j++) {
for (k = 0; k < SMU74_DTE_SINKS; k++) {
dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1);
dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2);
pdef1++;
pdef2++;
}
}
}
return 0;
}
static int polaris10_populate_svi_load_line(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
data->power_tune_table.SviLoadLineEn = defaults->SviLoadLineEn;
data->power_tune_table.SviLoadLineVddC = defaults->SviLoadLineVddC;
data->power_tune_table.SviLoadLineTrimVddC = 3;
data->power_tune_table.SviLoadLineOffsetVddC = 0;
return 0;
}
static int polaris10_populate_tdc_limit(struct pp_hwmgr *hwmgr)
{
uint16_t tdc_limit;
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 128);
data->power_tune_table.TDC_VDDC_PkgLimit =
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
defaults->TDC_VDDC_ThrottleReleaseLimitPerc;
data->power_tune_table.TDC_MAWt = defaults->TDC_MAWt;
return 0;
}
static int polaris10_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
const struct polaris10_pt_defaults *defaults = data->power_tune_defaults;
uint32_t temp;
if (polaris10_read_smc_sram_dword(hwmgr->smumgr,
fuse_table_offset +
offsetof(SMU74_Discrete_PmFuses, TdcWaterfallCtl),
(uint32_t *)&temp, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
else {
data->power_tune_table.TdcWaterfallCtl = defaults->TdcWaterfallCtl;
data->power_tune_table.LPMLTemperatureMin =
(uint8_t)((temp >> 16) & 0xff);
data->power_tune_table.LPMLTemperatureMax =
(uint8_t)((temp >> 8) & 0xff);
data->power_tune_table.Reserved = (uint8_t)(temp & 0xff);
}
return 0;
}
static int polaris10_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
{
int i;
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.LPMLTemperatureScaler[i] = 0;
return 0;
}
static int polaris10_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if ((hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity & (1 << 15))
|| 0 == hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity)
hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity =
hwmgr->thermal_controller.advanceFanControlParameters.usDefaultFanOutputSensitivity;
data->power_tune_table.FuzzyFan_PwmSetDelta = PP_HOST_TO_SMC_US(
hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity);
return 0;
}
static int polaris10_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
{
int i;
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.GnbLPML[i] = 0;
return 0;
}
static int polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
{
return 0;
}
static int polaris10_enable_didt(struct pp_hwmgr *hwmgr, const bool enable)
{
uint32_t en = enable ? 1 : 0;
int32_t result = 0;
uint32_t data;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping)) {
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0);
data &= ~DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK;
data |= ((en << DIDT_SQ_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_SQ_CTRL0__DIDT_CTRL_EN_MASK);
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_SQ_CTRL0, data);
DIDTBlock_Info &= ~SQ_Enable_MASK;
DIDTBlock_Info |= en << SQ_Enable_SHIFT;
}
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping)) {
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0);
data &= ~DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK;
data |= ((en << DIDT_DB_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_DB_CTRL0__DIDT_CTRL_EN_MASK);
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_DB_CTRL0, data);
DIDTBlock_Info &= ~DB_Enable_MASK;
DIDTBlock_Info |= en << DB_Enable_SHIFT;
}
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping)) {
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0);
data &= ~DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK;
data |= ((en << DIDT_TD_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TD_CTRL0__DIDT_CTRL_EN_MASK);
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TD_CTRL0, data);
DIDTBlock_Info &= ~TD_Enable_MASK;
DIDTBlock_Info |= en << TD_Enable_SHIFT;
}
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0);
data &= ~DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK;
data |= ((en << DIDT_TCP_CTRL0__DIDT_CTRL_EN__SHIFT) & DIDT_TCP_CTRL0__DIDT_CTRL_EN_MASK);
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, ixDIDT_TCP_CTRL0, data);
DIDTBlock_Info &= ~TCP_Enable_MASK;
DIDTBlock_Info |= en << TCP_Enable_SHIFT;
}
if (enable)
result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_Didt_Block_Function, DIDTBlock_Info);
return result;
}
static int polaris10_program_pt_config_registers(struct pp_hwmgr *hwmgr,
struct polaris10_pt_config_reg *cac_config_regs)
{
struct polaris10_pt_config_reg *config_regs = cac_config_regs;
uint32_t cache = 0;
uint32_t data = 0;
PP_ASSERT_WITH_CODE((config_regs != NULL), "Invalid config register table.", return -EINVAL);
while (config_regs->offset != 0xFFFFFFFF) {
if (config_regs->type == POLARIS10_CONFIGREG_CACHE)
cache |= ((config_regs->value << config_regs->shift) & config_regs->mask);
else {
switch (config_regs->type) {
case POLARIS10_CONFIGREG_SMC_IND:
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset);
break;
case POLARIS10_CONFIGREG_DIDT_IND:
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset);
break;
case POLARIS10_CONFIGREG_GC_CAC_IND:
data = cgs_read_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset);
break;
default:
data = cgs_read_register(hwmgr->device, config_regs->offset);
break;
}
data &= ~config_regs->mask;
data |= ((config_regs->value << config_regs->shift) & config_regs->mask);
data |= cache;
switch (config_regs->type) {
case POLARIS10_CONFIGREG_SMC_IND:
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, config_regs->offset, data);
break;
case POLARIS10_CONFIGREG_DIDT_IND:
cgs_write_ind_register(hwmgr->device, CGS_IND_REG__DIDT, config_regs->offset, data);
break;
case POLARIS10_CONFIGREG_GC_CAC_IND:
cgs_write_ind_register(hwmgr->device, CGS_IND_REG_GC_CAC, config_regs->offset, data);
break;
default:
cgs_write_register(hwmgr->device, config_regs->offset, data);
break;
}
cache = 0;
}
config_regs++;
}
return 0;
}
int polaris10_enable_didt_config(struct pp_hwmgr *hwmgr)
{
int result;
uint32_t num_se = 0;
uint32_t count, value, value2;
struct cgs_system_info sys_info = {0};
sys_info.size = sizeof(struct cgs_system_info);
sys_info.info_id = CGS_SYSTEM_INFO_GFX_SE_INFO;
result = cgs_query_system_info(hwmgr->device, &sys_info);
if (result == 0)
num_se = sys_info.value;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
/* TO DO Pre DIDT disable clock gating */
value = 0;
value2 = cgs_read_register(hwmgr->device, mmGRBM_GFX_INDEX);
for (count = 0; count < num_se; count++) {
value = SYS_GRBM_GFX_INDEX_DATA__INSTANCE_BROADCAST_WRITES_MASK
| SYS_GRBM_GFX_INDEX_DATA__SH_BROADCAST_WRITES_MASK
| (count << SYS_GRBM_GFX_INDEX_DATA__SE_INDEX__SHIFT);
cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value);
if (hwmgr->chip_id == CHIP_POLARIS10) {
result = polaris10_program_pt_config_registers(hwmgr, GCCACConfig_Polaris10);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
result = polaris10_program_pt_config_registers(hwmgr, DIDTConfig_Polaris10);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
} else if (hwmgr->chip_id == CHIP_POLARIS11) {
result = polaris10_program_pt_config_registers(hwmgr, GCCACConfig_Polaris11);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
result = polaris10_program_pt_config_registers(hwmgr, DIDTConfig_Polaris11);
PP_ASSERT_WITH_CODE((result == 0), "DIDT Config failed.", return result);
}
}
cgs_write_register(hwmgr->device, mmGRBM_GFX_INDEX, value2);
result = polaris10_enable_didt(hwmgr, true);
PP_ASSERT_WITH_CODE((result == 0), "EnableDiDt failed.", return result);
/* TO DO Post DIDT enable clock gating */
}
return 0;
}
int polaris10_disable_didt_config(struct pp_hwmgr *hwmgr)
{
int result;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SQRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_DBRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TDRamping) ||
phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_TCPRamping)) {
/* TO DO Pre DIDT disable clock gating */
result = polaris10_enable_didt(hwmgr, false);
PP_ASSERT_WITH_CODE((result == 0), "Post DIDT enable clock gating failed.", return result);
/* TO DO Post DIDT enable clock gating */
}
return 0;
}
static int polaris10_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
uint16_t hi_sidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
uint16_t lo_sidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
return 0;
}
int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
uint32_t pm_fuse_table_offset;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (polaris10_read_smc_sram_dword(hwmgr->smumgr,
SMU7_FIRMWARE_HEADER_LOCATION +
offsetof(SMU74_Firmware_Header, PmFuseTable),
&pm_fuse_table_offset, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to get pm_fuse_table_offset Failed!",
return -EINVAL);
if (polaris10_populate_svi_load_line(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate SviLoadLine Failed!",
return -EINVAL);
if (polaris10_populate_tdc_limit(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TDCLimit Failed!", return -EINVAL);
if (polaris10_populate_dw8(hwmgr, pm_fuse_table_offset))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TdcWaterfallCtl, "
"LPMLTemperature Min and Max Failed!",
return -EINVAL);
if (0 != polaris10_populate_temperature_scaler(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate LPMLTemperatureScaler Failed!",
return -EINVAL);
if (polaris10_populate_fuzzy_fan(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate Fuzzy Fan Control parameters Failed!",
return -EINVAL);
if (polaris10_populate_gnb_lpml(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Failed!",
return -EINVAL);
if (polaris10_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Min and Max Vid Failed!",
return -EINVAL);
if (polaris10_populate_bapm_vddc_base_leakage_sidd(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate BapmVddCBaseLeakage Hi and Lo "
"Sidd Failed!", return -EINVAL);
if (polaris10_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
(uint8_t *)&data->power_tune_table,
(sizeof(struct SMU74_Discrete_PmFuses) - 92), data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to download PmFuseTable Failed!",
return -EINVAL);
}
return 0;
}
int polaris10_enable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC)) {
int smc_result;
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableCac));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable CAC in SMC.", result = -1);
data->cac_enabled = (0 == smc_result) ? true : false;
}
return result;
}
int polaris10_disable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC) && data->cac_enabled) {
int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableCac));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable CAC in SMC.", result = -1);
data->cac_enabled = false;
}
return result;
}
int polaris10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_PkgPwrSetLimit, n);
return 0;
}
static int polaris10_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
{
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
}
int polaris10_enable_power_containment(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
int smc_result;
int result = 0;
data->power_containment_features = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (data->enable_tdc_limit_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable TDCLimit in SMC.", result = -1;);
if (0 == smc_result)
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_TDCLimit;
}
if (data->enable_pkg_pwr_tracking_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
PP_ASSERT_WITH_CODE((0 == smc_result),
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
if (0 == smc_result) {
struct phm_cac_tdp_table *cac_table =
table_info->cac_dtp_table;
uint32_t default_limit =
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
if (polaris10_set_power_limit(hwmgr, default_limit))
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
}
}
}
return result;
}
int polaris10_disable_power_containment(struct pp_hwmgr *hwmgr)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment) &&
data->power_containment_features) {
int smc_result;
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_TDCLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable TDCLimit in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_DTE) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableDTE));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable DTE in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable PkgPwrTracking in SMC.",
result = smc_result);
}
data->power_containment_features = 0;
}
return result;
}
int polaris10_power_control_set_level(struct pp_hwmgr *hwmgr)
{
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
int adjust_percent, target_tdp;
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
/* adjustment percentage has already been validated */
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
hwmgr->platform_descriptor.TDPAdjustment :
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
/* SMC requested that target_tdp to be 7 bit fraction in DPM table
* but message to be 8 bit fraction for messages
*/
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
result = polaris10_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
}
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef POLARIS10_POWERTUNE_H
#define POLARIS10_POWERTUNE_H
enum polaris10_pt_config_reg_type {
POLARIS10_CONFIGREG_MMR = 0,
POLARIS10_CONFIGREG_SMC_IND,
POLARIS10_CONFIGREG_DIDT_IND,
POLARIS10_CONFIGREG_GC_CAC_IND,
POLARIS10_CONFIGREG_CACHE,
POLARIS10_CONFIGREG_MAX
};
#define DIDT_SQ_CTRL0__UNUSED_0_MASK 0xfffc0000
#define DIDT_SQ_CTRL0__UNUSED_0__SHIFT 0x12
#define DIDT_TD_CTRL0__UNUSED_0_MASK 0xfffc0000
#define DIDT_TD_CTRL0__UNUSED_0__SHIFT 0x12
#define DIDT_TCP_CTRL0__UNUSED_0_MASK 0xfffc0000
#define DIDT_TCP_CTRL0__UNUSED_0__SHIFT 0x12
#define DIDT_SQ_TUNING_CTRL__UNUSED_0_MASK 0xc0000000
#define DIDT_SQ_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001e
#define DIDT_TD_TUNING_CTRL__UNUSED_0_MASK 0xc0000000
#define DIDT_TD_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001e
#define DIDT_TCP_TUNING_CTRL__UNUSED_0_MASK 0xc0000000
#define DIDT_TCP_TUNING_CTRL__UNUSED_0__SHIFT 0x0000001e
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
#define ixGC_CAC_CNTL 0x0000
#define ixDIDT_SQ_STALL_CTRL 0x0004
#define ixDIDT_SQ_TUNING_CTRL 0x0005
#define ixDIDT_TD_STALL_CTRL 0x0044
#define ixDIDT_TD_TUNING_CTRL 0x0045
#define ixDIDT_TCP_STALL_CTRL 0x0064
#define ixDIDT_TCP_TUNING_CTRL 0x0065
struct polaris10_pt_config_reg {
uint32_t offset;
uint32_t mask;
uint32_t shift;
uint32_t value;
enum polaris10_pt_config_reg_type type;
};
void polaris10_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
int polaris10_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
int polaris10_populate_pm_fuses(struct pp_hwmgr *hwmgr);
int polaris10_enable_smc_cac(struct pp_hwmgr *hwmgr);
int polaris10_disable_smc_cac(struct pp_hwmgr *hwmgr);
int polaris10_enable_power_containment(struct pp_hwmgr *hwmgr);
int polaris10_disable_power_containment(struct pp_hwmgr *hwmgr);
int polaris10_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
int polaris10_power_control_set_level(struct pp_hwmgr *hwmgr);
int polaris10_enable_didt_config(struct pp_hwmgr *hwmgr);
#endif /* POLARIS10_POWERTUNE_H */
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <asm/div64.h>
#include "polaris10_thermal.h"
#include "polaris10_hwmgr.h"
#include "polaris10_smumgr.h"
#include "polaris10_ppsmc.h"
#include "smu/smu_7_1_3_d.h"
#include "smu/smu_7_1_3_sh_mask.h"
int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr,
struct phm_fan_speed_info *fan_speed_info)
{
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
fan_speed_info->supports_percent_read = true;
fan_speed_info->supports_percent_write = true;
fan_speed_info->min_percent = 0;
fan_speed_info->max_percent = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_FanSpeedInTableIsRPM) &&
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
fan_speed_info->supports_rpm_read = true;
fan_speed_info->supports_rpm_write = true;
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
} else {
fan_speed_info->min_rpm = 0;
fan_speed_info->max_rpm = 0;
}
return 0;
}
int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
uint32_t *speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_STATUS, FDO_PWM_DUTY);
if (duty100 == 0)
return -EINVAL;
tmp64 = (uint64_t)duty * 100;
do_div(tmp64, duty100);
*speed = (uint32_t)tmp64;
if (*speed > 100)
*speed = 100;
return 0;
}
int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
uint32_t tach_period;
uint32_t crystal_clock_freq;
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
(hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution == 0))
return 0;
tach_period = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_STATUS, TACH_PERIOD);
if (tach_period == 0)
return -EINVAL;
crystal_clock_freq = tonga_get_xclk(hwmgr);
*speed = 60 * crystal_clock_freq * 10000 / tach_period;
return 0;
}
/**
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
* @param hwmgr the address of the powerplay hardware manager.
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
* @exception Should always succeed.
*/
int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
{
if (hwmgr->fan_ctrl_is_in_default_mode) {
hwmgr->fan_ctrl_default_mode =
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE);
hwmgr->tmin =
PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN);
hwmgr->fan_ctrl_is_in_default_mode = false;
}
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN, 0);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE, mode);
return 0;
}
/**
* Reset Fan Speed Control to default mode.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Should always succeed.
*/
int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->fan_ctrl_is_in_default_mode) {
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TMIN, hwmgr->tmin);
hwmgr->fan_ctrl_is_in_default_mode = true;
}
return 0;
}
static int polaris10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
{
int result;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_FanSpeedInTableIsRPM))
hwmgr->hwmgr_func->set_max_fan_rpm_output(hwmgr,
hwmgr->thermal_controller.
advanceFanControlParameters.usMaxFanRPM);
else
hwmgr->hwmgr_func->set_max_fan_pwm_output(hwmgr,
hwmgr->thermal_controller.
advanceFanControlParameters.usMaxFanPWM);
} else {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
result = smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl);
}
if (!result && hwmgr->thermal_controller.
advanceFanControlParameters.ucTargetTemperature)
result = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanTemperatureTarget,
hwmgr->thermal_controller.
advanceFanControlParameters.ucTargetTemperature);
return result;
}
int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
{
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl);
}
/**
* Set Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (0% - 100%) to be set.
* @exception Fails is the 100% setting appears to be 0.
*/
int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr,
uint32_t speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (speed > 100)
speed = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl))
polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
if (duty100 == 0)
return -EINVAL;
tmp64 = (uint64_t)speed * duty100;
do_div(tmp64, 100);
duty = (uint32_t)tmp64;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reset Fan Speed to default.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Always succeeds.
*/
int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
{
int result;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl)) {
result = polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
if (!result)
result = polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
} else
result = polaris10_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (min - max) to be set.
* @exception Fails is the speed not lie between min and max.
*/
int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
{
uint32_t tach_period;
uint32_t crystal_clock_freq;
if (hwmgr->thermal_controller.fanInfo.bNoFan ||
(hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution == 0) ||
(speed < hwmgr->thermal_controller.fanInfo.ulMinRPM) ||
(speed > hwmgr->thermal_controller.fanInfo.ulMaxRPM))
return 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl))
polaris10_fan_ctrl_stop_smc_fan_control(hwmgr);
crystal_clock_freq = tonga_get_xclk(hwmgr);
tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_STATUS, TACH_PERIOD, tach_period);
return polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reads the remote temperature from the SIslands thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr)
{
int temp;
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_MULT_THERMAL_STATUS, CTF_TEMP);
/* Bit 9 means the reading is lower than the lowest usable value. */
if (temp & 0x200)
temp = POLARIS10_THERMAL_MAXIMUM_TEMP_READING;
else
temp = temp & 0x1ff;
temp *= PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
return temp;
}
/**
* Set the requested temperature range for high and low alert signals
*
* @param hwmgr The address of the hardware manager.
* @param range Temperature range to be programmed for high and low alert signals
* @exception PP_Result_BadInput if the input data is not valid.
*/
static int polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
uint32_t low_temp, uint32_t high_temp)
{
uint32_t low = POLARIS10_THERMAL_MINIMUM_ALERT_TEMP *
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
uint32_t high = POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP *
PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
if (low < low_temp)
low = low_temp;
if (high > high_temp)
high = high_temp;
if (low > high)
return -EINVAL;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, DIG_THERM_INTH,
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, DIG_THERM_INTL,
(low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_CTRL, DIG_THERM_DPM,
(high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
return 0;
}
/**
* Programs thermal controller one-time setting registers
*
* @param hwmgr The address of the hardware manager.
*/
static int polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
{
if (hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_CTRL, EDGE_PER_REV,
hwmgr->thermal_controller.fanInfo.
ucTachometerPulsesPerRevolution - 1);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
return 0;
}
/**
* Enable thermal alerts on the RV770 thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
static int polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK);
alert &= ~(POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to enable internal thermal interrupts */
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable);
}
/**
* Disable thermal alerts on the RV770 thermal controller.
* @param hwmgr The address of the hardware manager.
*/
static int polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK);
alert |= (POLARIS10_THERMAL_HIGH_ALERT_MASK | POLARIS10_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to disable internal thermal interrupts */
return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable);
}
/**
* Uninitialize the thermal controller.
* Currently just disables alerts.
* @param hwmgr The address of the hardware manager.
*/
int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
{
int result = polaris10_thermal_disable_alert(hwmgr);
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
polaris10_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set up the fan table to control the fan using the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
static int tf_polaris10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
SMU74_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
uint32_t duty100;
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
uint16_t fdo_min, slope1, slope2;
uint32_t reference_clock;
int res;
uint64_t tmp64;
if (data->fan_table_start == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_FDO_CTRL1, FMAX_DUTY100);
if (duty100 == 0) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.
usPWMMin * duty100;
do_div(tmp64, 10000);
fdo_min = (uint16_t)tmp64;
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed -
hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh -
hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed -
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh -
hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
fan_table.TempMin = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMin) / 100);
fan_table.TempMed = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMed) / 100);
fan_table.TempMax = cpu_to_be16((50 + hwmgr->
thermal_controller.advanceFanControlParameters.usTMax) / 100);
fan_table.Slope1 = cpu_to_be16(slope1);
fan_table.Slope2 = cpu_to_be16(slope2);
fan_table.FdoMin = cpu_to_be16(fdo_min);
fan_table.HystDown = cpu_to_be16(hwmgr->
thermal_controller.advanceFanControlParameters.ucTHyst);
fan_table.HystUp = cpu_to_be16(1);
fan_table.HystSlope = cpu_to_be16(1);
fan_table.TempRespLim = cpu_to_be16(5);
reference_clock = tonga_get_xclk(hwmgr);
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->
thermal_controller.advanceFanControlParameters.ulCycleDelay *
reference_clock) / 1600);
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(
hwmgr->device, CGS_IND_REG__SMC,
CG_MULT_THERMAL_CTRL, TEMP_SEL);
res = polaris10_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start,
(uint8_t *)&fan_table, (uint32_t)sizeof(fan_table),
data->sram_end);
if (!res && hwmgr->thermal_controller.
advanceFanControlParameters.ucMinimumPWMLimit)
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanMinPwm,
hwmgr->thermal_controller.
advanceFanControlParameters.ucMinimumPWMLimit);
if (!res && hwmgr->thermal_controller.
advanceFanControlParameters.ulMinFanSCLKAcousticLimit)
res = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetFanSclkTarget,
hwmgr->thermal_controller.
advanceFanControlParameters.ulMinFanSCLKAcousticLimit);
if (res)
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
/**
* Start the fan control on the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
static int tf_polaris10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
/* If the fantable setup has failed we could have disabled
* PHM_PlatformCaps_MicrocodeFanControl even after
* this function was included in the table.
* Make sure that we still think controlling the fan is OK.
*/
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_MicrocodeFanControl)) {
polaris10_fan_ctrl_start_smc_fan_control(hwmgr);
polaris10_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
return 0;
}
/**
* Set temperature range for high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
if (range == NULL)
return -EINVAL;
return polaris10_thermal_set_temperature_range(hwmgr, range->min, range->max);
}
/**
* Programs one-time setting registers
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from initialize thermal controller routine
*/
int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return polaris10_thermal_initialize(hwmgr);
}
/**
* Enable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from enable alert routine
*/
int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return polaris10_thermal_enable_alert(hwmgr);
}
/**
* Disable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from disable alert routine
*/
static int tf_polaris10_thermal_disable_alert(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
return polaris10_thermal_disable_alert(hwmgr);
}
static int tf_polaris10_thermal_avfs_enable(struct pp_hwmgr *hwmgr,
void *input, void *output, void *storage, int result)
{
int ret;
struct pp_smumgr *smumgr = (struct pp_smumgr *)(hwmgr->smumgr);
struct polaris10_smumgr *smu_data = (struct polaris10_smumgr *)(smumgr->backend);
struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
if (smu_data->avfs.avfs_btc_status == AVFS_BTC_NOTSUPPORTED)
return 0;
ret = smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_SetGBDroopSettings, data->avfs_vdroop_override_setting);
ret = (smum_send_msg_to_smc(smumgr, PPSMC_MSG_EnableAvfs) == 0) ?
0 : -1;
if (!ret)
/* If this param is not changed, this function could fire unnecessarily */
smu_data->avfs.avfs_btc_status = AVFS_BTC_COMPLETED_PREVIOUSLY;
return ret;
}
static const struct phm_master_table_item
polaris10_thermal_start_thermal_controller_master_list[] = {
{NULL, tf_polaris10_thermal_initialize},
{NULL, tf_polaris10_thermal_set_temperature_range},
{NULL, tf_polaris10_thermal_enable_alert},
{NULL, tf_polaris10_thermal_avfs_enable},
/* We should restrict performance levels to low before we halt the SMC.
* On the other hand we are still in boot state when we do this
* so it would be pointless.
* If this assumption changes we have to revisit this table.
*/
{NULL, tf_polaris10_thermal_setup_fan_table},
{NULL, tf_polaris10_thermal_start_smc_fan_control},
{NULL, NULL}
};
static const struct phm_master_table_header
polaris10_thermal_start_thermal_controller_master = {
0,
PHM_MasterTableFlag_None,
polaris10_thermal_start_thermal_controller_master_list
};
static const struct phm_master_table_item
polaris10_thermal_set_temperature_range_master_list[] = {
{NULL, tf_polaris10_thermal_disable_alert},
{NULL, tf_polaris10_thermal_set_temperature_range},
{NULL, tf_polaris10_thermal_enable_alert},
{NULL, NULL}
};
static const struct phm_master_table_header
polaris10_thermal_set_temperature_range_master = {
0,
PHM_MasterTableFlag_None,
polaris10_thermal_set_temperature_range_master_list
};
int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
polaris10_fan_ctrl_set_default_mode(hwmgr);
return 0;
}
/**
* Initializes the thermal controller related functions in the Hardware Manager structure.
* @param hwmgr The address of the hardware manager.
* @exception Any error code from the low-level communication.
*/
int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr)
{
int result;
result = phm_construct_table(hwmgr,
&polaris10_thermal_set_temperature_range_master,
&(hwmgr->set_temperature_range));
if (!result) {
result = phm_construct_table(hwmgr,
&polaris10_thermal_start_thermal_controller_master,
&(hwmgr->start_thermal_controller));
if (result)
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
}
if (!result)
hwmgr->fan_ctrl_is_in_default_mode = true;
return result;
}
/*
* Copyright 2016 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _POLARIS10_THERMAL_H_
#define _POLARIS10_THERMAL_H_
#include "hwmgr.h"
#define POLARIS10_THERMAL_HIGH_ALERT_MASK 0x1
#define POLARIS10_THERMAL_LOW_ALERT_MASK 0x2
#define POLARIS10_THERMAL_MINIMUM_TEMP_READING -256
#define POLARIS10_THERMAL_MAXIMUM_TEMP_READING 255
#define POLARIS10_THERMAL_MINIMUM_ALERT_TEMP 0
#define POLARIS10_THERMAL_MAXIMUM_ALERT_TEMP 255
#define FDO_PWM_MODE_STATIC 1
#define FDO_PWM_MODE_STATIC_RPM 5
extern int tf_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_polaris10_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_polaris10_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int polaris10_thermal_get_temperature(struct pp_hwmgr *hwmgr);
extern int polaris10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
extern int polaris10_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
extern int polaris10_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int polaris10_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
extern int polaris10_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
extern int polaris10_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int polaris10_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
extern int pp_polaris10_thermal_initialize(struct pp_hwmgr *hwmgr);
extern int polaris10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
extern int polaris10_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int polaris10_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int polaris10_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
extern uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "hwmgr.h"
#include "tonga_clockpowergating.h"
#include "tonga_ppsmc.h"
#include "tonga_hwmgr.h"
int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_uvd_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_UVDPowerOFF);
return 0;
}
int tonga_phm_powerup_uvd(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_uvd_power_gating(hwmgr)) {
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_UVDDynamicPowerGating)) {
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_UVDPowerON, 1);
} else {
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_UVDPowerON, 0);
}
}
return 0;
}
int tonga_phm_powerdown_vce(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_vce_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_VCEPowerOFF);
return 0;
}
int tonga_phm_powerup_vce(struct pp_hwmgr *hwmgr)
{
if (phm_cf_want_vce_power_gating(hwmgr))
return smum_send_msg_to_smc(hwmgr->smumgr,
PPSMC_MSG_VCEPowerON);
return 0;
}
int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating)
{
int ret = 0;
switch (block) {
case PHM_AsicBlock_UVD_MVC:
case PHM_AsicBlock_UVD:
case PHM_AsicBlock_UVD_HD:
case PHM_AsicBlock_UVD_SD:
if (gating == PHM_ClockGateSetting_StaticOff)
ret = tonga_phm_powerdown_uvd(hwmgr);
else
ret = tonga_phm_powerup_uvd(hwmgr);
break;
case PHM_AsicBlock_GFX:
default:
break;
}
return ret;
}
int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
data->uvd_power_gated = false;
data->vce_power_gated = false;
tonga_phm_powerup_uvd(hwmgr);
tonga_phm_powerup_vce(hwmgr);
return 0;
}
int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
if (data->uvd_power_gated == bgate)
return 0;
data->uvd_power_gated = bgate;
if (bgate) {
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_CG_STATE_UNGATE);
cgs_set_powergating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_PG_STATE_GATE);
tonga_update_uvd_dpm(hwmgr, true);
tonga_phm_powerdown_uvd(hwmgr);
} else {
tonga_phm_powerup_uvd(hwmgr);
cgs_set_powergating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_PG_STATE_UNGATE);
cgs_set_clockgating_state(hwmgr->device,
AMD_IP_BLOCK_TYPE_UVD,
AMD_PG_STATE_GATE);
tonga_update_uvd_dpm(hwmgr, false);
}
return 0;
}
int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
struct phm_set_power_state_input states;
const struct pp_power_state *pcurrent;
struct pp_power_state *requested;
pcurrent = hwmgr->current_ps;
requested = hwmgr->request_ps;
states.pcurrent_state = &(pcurrent->hardware);
states.pnew_state = &(requested->hardware);
if (phm_cf_want_vce_power_gating(hwmgr)) {
if (data->vce_power_gated != bgate) {
if (bgate) {
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_CG_STATE_UNGATE);
cgs_set_powergating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_PG_STATE_GATE);
tonga_enable_disable_vce_dpm(hwmgr, false);
data->vce_power_gated = true;
} else {
tonga_phm_powerup_vce(hwmgr);
data->vce_power_gated = false;
cgs_set_powergating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_PG_STATE_UNGATE);
cgs_set_clockgating_state(
hwmgr->device,
AMD_IP_BLOCK_TYPE_VCE,
AMD_PG_STATE_GATE);
tonga_update_vce_dpm(hwmgr, &states);
tonga_enable_disable_vce_dpm(hwmgr, true);
return 0;
}
}
} else {
tonga_update_vce_dpm(hwmgr, &states);
tonga_enable_disable_vce_dpm(hwmgr, true);
return 0;
}
if (!data->vce_power_gated)
tonga_update_vce_dpm(hwmgr, &states);
return 0;
}
int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr,
const uint32_t *msg_id)
{
PPSMC_Msg msg;
uint32_t value;
switch ((*msg_id & PP_GROUP_MASK) >> PP_GROUP_SHIFT) {
case PP_GROUP_GFX:
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
case PP_BLOCK_GFX_CG:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_CGCG_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_GFX_CGLS_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_GFX_MG:
/* For GFX MGCG, there are three different ones;
* CPF, RLC, and all others. CPF MGCG will not be used for Tonga.
* For GFX MGLS, Tonga will not support it.
* */
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = (CG_RLC_MGCG_MASK | CG_GFX_OTHERS_MGCG_MASK);
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
default:
return -1;
}
break;
case PP_GROUP_SYS:
switch ((*msg_id & PP_BLOCK_MASK) >> PP_BLOCK_SHIFT) {
case PP_BLOCK_SYS_BIF:
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_BIF_MGLS_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_MC:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_MC_MGCG_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_MC_MGLS_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_HDP:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_HDP_MGCG_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_HDP_MGLS_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_SDMA:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_SDMA_MGCG_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
if (PP_STATE_SUPPORT_LS & *msg_id) {
msg = (*msg_id & PP_STATE_MASK) & PP_STATE_LS
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_SDMA_MGLS_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
case PP_BLOCK_SYS_ROM:
if (PP_STATE_SUPPORT_CG & *msg_id) {
msg = ((*msg_id & PP_STATE_MASK) & PP_STATE_CG)
? PPSMC_MSG_EnableClockGatingFeature
: PPSMC_MSG_DisableClockGatingFeature;
value = CG_SYS_ROM_MASK;
if (0 != smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, msg, value))
return -1;
}
break;
default:
return -1;
}
break;
default:
return -1;
}
return 0;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef _TONGA_CLOCK_POWER_GATING_H_
#define _TONGA_CLOCK_POWER_GATING_H_
#include "tonga_hwmgr.h"
#include "pp_asicblocks.h"
extern int tonga_phm_set_asic_block_gating(struct pp_hwmgr *hwmgr, enum PHM_AsicBlock block, enum PHM_ClockGateSetting gating);
extern int tonga_phm_powergate_vce(struct pp_hwmgr *hwmgr, bool bgate);
extern int tonga_phm_powergate_uvd(struct pp_hwmgr *hwmgr, bool bgate);
extern int tonga_phm_powerdown_uvd(struct pp_hwmgr *hwmgr);
extern int tonga_phm_disable_clock_power_gating(struct pp_hwmgr *hwmgr);
extern int tonga_phm_update_clock_gatings(struct pp_hwmgr *hwmgr, const uint32_t *msg_id);
#endif /* _TONGA_CLOCK_POWER_GATING_H_ */
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_DYN_DEFAULTS_H
#define TONGA_DYN_DEFAULTS_H
/** \file
* Volcanic Islands Dynamic default parameters.
*/
enum TONGAdpm_TrendDetection {
TONGAdpm_TrendDetection_AUTO,
TONGAdpm_TrendDetection_UP,
TONGAdpm_TrendDetection_DOWN
};
typedef enum TONGAdpm_TrendDetection TONGAdpm_TrendDetection;
/* Bit vector representing same fields as hardware register. */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT0 0x3FFFC102 /* CP_Gfx_busy */
/* HDP_busy */
/* IH_busy */
/* DRM_busy */
/* DRMDMA_busy */
/* UVD_busy */
/* VCE_busy */
/* ACP_busy */
/* SAMU_busy */
/* AVP_busy */
/* SDMA enabled */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT1 0x000400 /* FE_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* SH_Gfx_busy */
/* RB_Gfx_busy */
/* VCE_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT2 0xC00080 /* SH_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* FE_Gfx_busy */
/* RB_Gfx_busy */
/* ACP_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT3 0xC00200 /* RB_Gfx_busy - Intended for primary usage. Rest are for flexibility. */
/* FE_Gfx_busy */
/* SH_Gfx_busy */
/* UVD_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT4 0xC01680 /* UVD_busy */
/* VCE_busy */
/* ACP_busy */
/* SAMU_busy */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT5 0xC00033 /* GFX, HDP, DRMDMA */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT6 0xC00033 /* GFX, HDP, DRMDMA */
#define PPTONGA_VOTINGRIGHTSCLIENTS_DFLT7 0x3FFFC000 /* GFX, HDP, DRMDMA */
/* thermal protection counter (units).*/
#define PPTONGA_THERMALPROTECTCOUNTER_DFLT 0x200 /* ~19us */
/* static screen threshold unit */
#define PPTONGA_STATICSCREENTHRESHOLDUNIT_DFLT 0
/* static screen threshold */
#define PPTONGA_STATICSCREENTHRESHOLD_DFLT 0x00C8
/* gfx idle clock stop threshold */
#define PPTONGA_GFXIDLECLOCKSTOPTHRESHOLD_DFLT 0x200 /* ~19us with static screen threshold unit of 0 */
/* Fixed reference divider to use when building baby stepping tables. */
#define PPTONGA_REFERENCEDIVIDER_DFLT 4
/*
* ULV voltage change delay time
* Used to be delay_vreg in N.I. split for S.I.
* Using N.I. delay_vreg value as default
* ReferenceClock = 2700
* VoltageResponseTime = 1000
* VDDCDelayTime = (VoltageResponseTime * ReferenceClock) / 1600 = 1687
*/
#define PPTONGA_ULVVOLTAGECHANGEDELAY_DFLT 1687
#define PPTONGA_CGULVPARAMETER_DFLT 0x00040035
#define PPTONGA_CGULVCONTROL_DFLT 0x00007450
#define PPTONGA_TARGETACTIVITY_DFLT 30 /*30% */
#define PPTONGA_MCLK_TARGETACTIVITY_DFLT 10 /*10% */
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_HWMGR_H
#define TONGA_HWMGR_H
#include "hwmgr.h"
#include "smu72_discrete.h"
#include "ppatomctrl.h"
#include "ppinterrupt.h"
#include "tonga_powertune.h"
#include "pp_endian.h"
#define TONGA_MAX_HARDWARE_POWERLEVELS 2
#define TONGA_DYNCLK_NUMBER_OF_TREND_COEFFICIENTS 15
struct tonga_performance_level {
uint32_t memory_clock;
uint32_t engine_clock;
uint16_t pcie_gen;
uint16_t pcie_lane;
};
struct _phw_tonga_bacos {
uint32_t best_match;
uint32_t baco_flags;
struct tonga_performance_level performance_level;
};
typedef struct _phw_tonga_bacos phw_tonga_bacos;
struct _phw_tonga_uvd_clocks {
uint32_t VCLK;
uint32_t DCLK;
};
typedef struct _phw_tonga_uvd_clocks phw_tonga_uvd_clocks;
struct _phw_tonga_vce_clocks {
uint32_t EVCLK;
uint32_t ECCLK;
};
typedef struct _phw_tonga_vce_clocks phw_tonga_vce_clocks;
struct tonga_power_state {
uint32_t magic;
phw_tonga_uvd_clocks uvd_clocks;
phw_tonga_vce_clocks vce_clocks;
uint32_t sam_clk;
uint32_t acp_clk;
uint16_t performance_level_count;
bool dc_compatible;
uint32_t sclk_threshold;
struct tonga_performance_level performance_levels[TONGA_MAX_HARDWARE_POWERLEVELS];
};
struct _phw_tonga_dpm_level {
bool enabled;
uint32_t value;
uint32_t param1;
};
typedef struct _phw_tonga_dpm_level phw_tonga_dpm_level;
#define TONGA_MAX_DEEPSLEEP_DIVIDER_ID 5
#define MAX_REGULAR_DPM_NUMBER 8
#define TONGA_MINIMUM_ENGINE_CLOCK 2500
struct tonga_single_dpm_table {
uint32_t count;
phw_tonga_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER];
};
struct tonga_dpm_table {
struct tonga_single_dpm_table sclk_table;
struct tonga_single_dpm_table mclk_table;
struct tonga_single_dpm_table pcie_speed_table;
struct tonga_single_dpm_table vddc_table;
struct tonga_single_dpm_table vdd_gfx_table;
struct tonga_single_dpm_table vdd_ci_table;
struct tonga_single_dpm_table mvdd_table;
};
typedef struct _phw_tonga_dpm_table phw_tonga_dpm_table;
struct _phw_tonga_clock_regisiters {
uint32_t vCG_SPLL_FUNC_CNTL;
uint32_t vCG_SPLL_FUNC_CNTL_2;
uint32_t vCG_SPLL_FUNC_CNTL_3;
uint32_t vCG_SPLL_FUNC_CNTL_4;
uint32_t vCG_SPLL_SPREAD_SPECTRUM;
uint32_t vCG_SPLL_SPREAD_SPECTRUM_2;
uint32_t vDLL_CNTL;
uint32_t vMCLK_PWRMGT_CNTL;
uint32_t vMPLL_AD_FUNC_CNTL;
uint32_t vMPLL_DQ_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL;
uint32_t vMPLL_FUNC_CNTL_1;
uint32_t vMPLL_FUNC_CNTL_2;
uint32_t vMPLL_SS1;
uint32_t vMPLL_SS2;
};
typedef struct _phw_tonga_clock_regisiters phw_tonga_clock_registers;
struct _phw_tonga_voltage_smio_registers {
uint32_t vs0_vid_lower_smio_cntl;
};
typedef struct _phw_tonga_voltage_smio_registers phw_tonga_voltage_smio_registers;
struct _phw_tonga_mc_reg_entry {
uint32_t mclk_max;
uint32_t mc_data[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_tonga_mc_reg_entry phw_tonga_mc_reg_entry;
struct _phw_tonga_mc_reg_table {
uint8_t last; /* number of registers*/
uint8_t num_entries; /* number of entries in mc_reg_table_entry used*/
uint16_t validflag; /* indicate the corresponding register is valid or not. 1: valid, 0: invalid. bit0->address[0], bit1->address[1], etc.*/
phw_tonga_mc_reg_entry mc_reg_table_entry[MAX_AC_TIMING_ENTRIES];
SMU72_Discrete_MCRegisterAddress mc_reg_address[SMU72_DISCRETE_MC_REGISTER_ARRAY_SIZE];
};
typedef struct _phw_tonga_mc_reg_table phw_tonga_mc_reg_table;
#define DISABLE_MC_LOADMICROCODE 1
#define DISABLE_MC_CFGPROGRAMMING 2
/*Ultra Low Voltage parameter structure */
struct _phw_tonga_ulv_parm{
bool ulv_supported;
uint32_t ch_ulv_parameter;
uint32_t ulv_volt_change_delay;
struct tonga_performance_level ulv_power_level;
};
typedef struct _phw_tonga_ulv_parm phw_tonga_ulv_parm;
#define TONGA_MAX_LEAKAGE_COUNT 8
struct _phw_tonga_leakage_voltage {
uint16_t count;
uint16_t leakage_id[TONGA_MAX_LEAKAGE_COUNT];
uint16_t actual_voltage[TONGA_MAX_LEAKAGE_COUNT];
};
typedef struct _phw_tonga_leakage_voltage phw_tonga_leakage_voltage;
struct _phw_tonga_display_timing {
uint32_t min_clock_insr;
uint32_t num_existing_displays;
};
typedef struct _phw_tonga_display_timing phw_tonga_display_timing;
struct _phw_tonga_dpmlevel_enable_mask {
uint32_t uvd_dpm_enable_mask;
uint32_t vce_dpm_enable_mask;
uint32_t acp_dpm_enable_mask;
uint32_t samu_dpm_enable_mask;
uint32_t sclk_dpm_enable_mask;
uint32_t mclk_dpm_enable_mask;
uint32_t pcie_dpm_enable_mask;
};
typedef struct _phw_tonga_dpmlevel_enable_mask phw_tonga_dpmlevel_enable_mask;
struct _phw_tonga_pcie_perf_range {
uint16_t max;
uint16_t min;
};
typedef struct _phw_tonga_pcie_perf_range phw_tonga_pcie_perf_range;
struct _phw_tonga_vbios_boot_state {
uint16_t mvdd_bootup_value;
uint16_t vddc_bootup_value;
uint16_t vddci_bootup_value;
uint16_t vddgfx_bootup_value;
uint32_t sclk_bootup_value;
uint32_t mclk_bootup_value;
uint16_t pcie_gen_bootup_value;
uint16_t pcie_lane_bootup_value;
};
typedef struct _phw_tonga_vbios_boot_state phw_tonga_vbios_boot_state;
#define DPMTABLE_OD_UPDATE_SCLK 0x00000001
#define DPMTABLE_OD_UPDATE_MCLK 0x00000002
#define DPMTABLE_UPDATE_SCLK 0x00000004
#define DPMTABLE_UPDATE_MCLK 0x00000008
/* We need to review which fields are needed. */
/* This is mostly a copy of the RV7xx/Evergreen structure which is close, but not identical to the N.Islands one. */
struct tonga_hwmgr {
struct tonga_dpm_table dpm_table;
struct tonga_dpm_table golden_dpm_table;
uint32_t voting_rights_clients0;
uint32_t voting_rights_clients1;
uint32_t voting_rights_clients2;
uint32_t voting_rights_clients3;
uint32_t voting_rights_clients4;
uint32_t voting_rights_clients5;
uint32_t voting_rights_clients6;
uint32_t voting_rights_clients7;
uint32_t static_screen_threshold_unit;
uint32_t static_screen_threshold;
uint32_t voltage_control;
uint32_t vdd_gfx_control;
uint32_t vddc_vddci_delta;
uint32_t vddc_vddgfx_delta;
struct pp_interrupt_registration_info internal_high_thermal_interrupt_info;
struct pp_interrupt_registration_info internal_low_thermal_interrupt_info;
struct pp_interrupt_registration_info smc_to_host_interrupt_info;
uint32_t active_auto_throttle_sources;
struct pp_interrupt_registration_info external_throttle_interrupt;
irq_handler_func_t external_throttle_callback;
void *external_throttle_context;
struct pp_interrupt_registration_info ctf_interrupt_info;
irq_handler_func_t ctf_callback;
void *ctf_context;
phw_tonga_clock_registers clock_registers;
phw_tonga_voltage_smio_registers voltage_smio_registers;
bool is_memory_GDDR5;
uint16_t acpi_vddc;
bool pspp_notify_required; /* Flag to indicate if PSPP notification to SBIOS is required */
uint16_t force_pcie_gen; /* The forced PCI-E speed if not 0xffff */
uint16_t acpi_pcie_gen; /* The PCI-E speed at ACPI time */
uint32_t pcie_gen_cap; /* The PCI-E speed capabilities bitmap from CAIL */
uint32_t pcie_lane_cap; /* The PCI-E lane capabilities bitmap from CAIL */
uint32_t pcie_spc_cap; /* Symbol Per Clock Capabilities from registry */
phw_tonga_leakage_voltage vddc_leakage; /* The Leakage VDDC supported (based on leakage ID).*/
phw_tonga_leakage_voltage vddcgfx_leakage; /* The Leakage VDDC supported (based on leakage ID). */
phw_tonga_leakage_voltage vddci_leakage; /* The Leakage VDDCI supported (based on leakage ID). */
uint32_t mvdd_control;
uint32_t vddc_mask_low;
uint32_t mvdd_mask_low;
uint16_t max_vddc_in_pp_table; /* the maximum VDDC value in the powerplay table*/
uint16_t min_vddc_in_pp_table;
uint16_t max_vddci_in_pp_table; /* the maximum VDDCI value in the powerplay table */
uint16_t min_vddci_in_pp_table;
uint32_t mclk_strobe_mode_threshold;
uint32_t mclk_stutter_mode_threshold;
uint32_t mclk_edc_enable_threshold;
uint32_t mclk_edc_wr_enable_threshold;
bool is_uvd_enabled;
bool is_xdma_enabled;
phw_tonga_vbios_boot_state vbios_boot_state;
bool battery_state;
bool is_tlu_enabled;
bool pcie_performance_request;
/* -------------- SMC SRAM Address of firmware header tables ----------------*/
uint32_t sram_end; /* The first address after the SMC SRAM. */
uint32_t dpm_table_start; /* The start of the dpm table in the SMC SRAM. */
uint32_t soft_regs_start; /* The start of the soft registers in the SMC SRAM. */
uint32_t mc_reg_table_start; /* The start of the mc register table in the SMC SRAM. */
uint32_t fan_table_start; /* The start of the fan table in the SMC SRAM. */
uint32_t arb_table_start; /* The start of the ARB setting table in the SMC SRAM. */
SMU72_Discrete_DpmTable smc_state_table; /* The carbon copy of the SMC state table. */
SMU72_Discrete_MCRegisters mc_reg_table;
SMU72_Discrete_Ulv ulv_setting; /* The carbon copy of ULV setting. */
/* -------------- Stuff originally coming from Evergreen --------------------*/
phw_tonga_mc_reg_table tonga_mc_reg_table;
uint32_t vdd_ci_control;
pp_atomctrl_voltage_table vddc_voltage_table;
pp_atomctrl_voltage_table vddci_voltage_table;
pp_atomctrl_voltage_table vddgfx_voltage_table;
pp_atomctrl_voltage_table mvdd_voltage_table;
uint32_t mgcg_cgtt_local2;
uint32_t mgcg_cgtt_local3;
uint32_t gpio_debug;
uint32_t mc_micro_code_feature;
uint32_t highest_mclk;
uint16_t acpi_vdd_ci;
uint8_t mvdd_high_index;
uint8_t mvdd_low_index;
bool dll_defaule_on;
bool performance_request_registered;
/* ----------------- Low Power Features ---------------------*/
phw_tonga_bacos bacos;
phw_tonga_ulv_parm ulv;
/* ----------------- CAC Stuff ---------------------*/
uint32_t cac_table_start;
bool cac_configuration_required; /* TRUE if PP_CACConfigurationRequired == 1 */
bool driver_calculate_cac_leakage; /* TRUE if PP_DriverCalculateCACLeakage == 1 */
bool cac_enabled;
/* ----------------- DPM2 Parameters ---------------------*/
uint32_t power_containment_features;
bool enable_bapm_feature;
bool enable_tdc_limit_feature;
bool enable_pkg_pwr_tracking_feature;
bool disable_uvd_power_tune_feature;
struct tonga_pt_defaults *power_tune_defaults;
SMU72_Discrete_PmFuses power_tune_table;
uint32_t dte_tj_offset; /* Fudge factor in DPM table to correct HW DTE errors */
uint32_t fast_watermark_threshold; /* use fast watermark if clock is equal or above this. In percentage of the target high sclk. */
bool enable_dte_feature;
/* ----------------- Phase Shedding ---------------------*/
bool vddc_phase_shed_control;
/* --------------------- DI/DT --------------------------*/
phw_tonga_display_timing display_timing;
/* --------- ReadRegistry data for memory and engine clock margins ---- */
uint32_t engine_clock_data;
uint32_t memory_clock_data;
/* -------- Thermal Temperature Setting --------------*/
phw_tonga_dpmlevel_enable_mask dpm_level_enable_mask;
uint32_t need_update_smu7_dpm_table;
uint32_t sclk_dpm_key_disabled;
uint32_t mclk_dpm_key_disabled;
uint32_t pcie_dpm_key_disabled;
uint32_t min_engine_clocks; /* used to store the previous dal min sclock */
phw_tonga_pcie_perf_range pcie_gen_performance;
phw_tonga_pcie_perf_range pcie_lane_performance;
phw_tonga_pcie_perf_range pcie_gen_power_saving;
phw_tonga_pcie_perf_range pcie_lane_power_saving;
bool use_pcie_performance_levels;
bool use_pcie_power_saving_levels;
uint32_t activity_target[SMU72_MAX_LEVELS_GRAPHICS]; /* percentage value from 0-100, default 50 */
uint32_t mclk_activity_target;
uint32_t low_sclk_interrupt_threshold;
uint32_t last_mclk_dpm_enable_mask;
bool uvd_enabled;
uint32_t pcc_monitor_enabled;
/* --------- Power Gating States ------------*/
bool uvd_power_gated; /* 1: gated, 0:not gated */
bool vce_power_gated; /* 1: gated, 0:not gated */
bool samu_power_gated; /* 1: gated, 0:not gated */
bool acp_power_gated; /* 1: gated, 0:not gated */
bool pg_acp_init;
};
typedef struct tonga_hwmgr tonga_hwmgr;
#define TONGA_DPM2_NEAR_TDP_DEC 10
#define TONGA_DPM2_ABOVE_SAFE_INC 5
#define TONGA_DPM2_BELOW_SAFE_INC 20
#define TONGA_DPM2_LTA_WINDOW_SIZE 7 /* Log2 of the LTA window size (l2numWin_TDP). Eg. If LTA windows size is 128, then this value should be Log2(128) = 7. */
#define TONGA_DPM2_LTS_TRUNCATE 0
#define TONGA_DPM2_TDP_SAFE_LIMIT_PERCENT 80 /* Maximum 100 */
#define TONGA_DPM2_MAXPS_PERCENT_H 90 /* Maximum 0xFF */
#define TONGA_DPM2_MAXPS_PERCENT_M 90 /* Maximum 0xFF */
#define TONGA_DPM2_PWREFFICIENCYRATIO_MARGIN 50
#define TONGA_DPM2_SQ_RAMP_MAX_POWER 0x3FFF
#define TONGA_DPM2_SQ_RAMP_MIN_POWER 0x12
#define TONGA_DPM2_SQ_RAMP_MAX_POWER_DELTA 0x15
#define TONGA_DPM2_SQ_RAMP_SHORT_TERM_INTERVAL_SIZE 0x1E
#define TONGA_DPM2_SQ_RAMP_LONG_TERM_INTERVAL_RATIO 0xF
#define TONGA_VOLTAGE_CONTROL_NONE 0x0
#define TONGA_VOLTAGE_CONTROL_BY_GPIO 0x1
#define TONGA_VOLTAGE_CONTROL_BY_SVID2 0x2
#define TONGA_VOLTAGE_CONTROL_MERGED 0x3
#define TONGA_Q88_FORMAT_CONVERSION_UNIT 256 /*To convert to Q8.8 format for firmware */
#define TONGA_UNUSED_GPIO_PIN 0x7F
int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
int tonga_update_vce_dpm(struct pp_hwmgr *hwmgr, const void *input);
int tonga_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate);
int tonga_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable);
int tonga_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable);
uint32_t tonga_get_xclk(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "hwmgr.h"
#include "smumgr.h"
#include "tonga_hwmgr.h"
#include "tonga_powertune.h"
#include "tonga_smumgr.h"
#include "smu72_discrete.h"
#include "pp_debug.h"
#include "tonga_ppsmc.h"
#define VOLTAGE_SCALE 4
#define POWERTUNE_DEFAULT_SET_MAX 1
struct tonga_pt_defaults tonga_power_tune_data_set_array[POWERTUNE_DEFAULT_SET_MAX] = {
/* sviLoadLIneEn, SviLoadLineVddC, TDC_VDDC_ThrottleReleaseLimitPerc, TDC_MAWt, TdcWaterfallCtl, DTEAmbientTempBase, DisplayCac, BAPM_TEMP_GRADIENT */
{1, 0xF, 0xFD, 0x19, 5, 45, 0, 0xB0000,
{0x79, 0x253, 0x25D, 0xAE, 0x72, 0x80, 0x83, 0x86, 0x6F, 0xC8, 0xC9, 0xC9, 0x2F, 0x4D, 0x61},
{0x17C, 0x172, 0x180, 0x1BC, 0x1B3, 0x1BD, 0x206, 0x200, 0x203, 0x25D, 0x25A, 0x255, 0x2C3, 0x2C5, 0x2B4 } },
};
void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *tonga_hwmgr = (struct tonga_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
uint32_t tmp = 0;
if (table_info &&
table_info->cac_dtp_table->usPowerTuneDataSetID <= POWERTUNE_DEFAULT_SET_MAX &&
table_info->cac_dtp_table->usPowerTuneDataSetID)
tonga_hwmgr->power_tune_defaults =
&tonga_power_tune_data_set_array
[table_info->cac_dtp_table->usPowerTuneDataSetID - 1];
else
tonga_hwmgr->power_tune_defaults = &tonga_power_tune_data_set_array[0];
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_SQRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_DBRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TDRamping);
phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_TCPRamping);
tonga_hwmgr->dte_tj_offset = tmp;
if (!tmp) {
phm_cap_set(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC);
tonga_hwmgr->fast_watermark_threshold = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
tmp = 1;
tonga_hwmgr->enable_dte_feature = tmp ? false : true;
tonga_hwmgr->enable_tdc_limit_feature = tmp ? true : false;
tonga_hwmgr->enable_pkg_pwr_tracking_feature = tmp ? true : false;
}
}
}
int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
struct tonga_pt_defaults *defaults = data->power_tune_defaults;
SMU72_Discrete_DpmTable *dpm_table = &(data->smc_state_table);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_dtp_table = table_info->cac_dtp_table;
int i, j, k;
uint16_t *pdef1;
uint16_t *pdef2;
/* TDP number of fraction bits are changed from 8 to 7 for Fiji
* as requested by SMC team
*/
dpm_table->DefaultTdp = PP_HOST_TO_SMC_US(
(uint16_t)(cac_dtp_table->usTDP * 256));
dpm_table->TargetTdp = PP_HOST_TO_SMC_US(
(uint16_t)(cac_dtp_table->usConfigurableTDP * 256));
PP_ASSERT_WITH_CODE(cac_dtp_table->usTargetOperatingTemp <= 255,
"Target Operating Temp is out of Range!",
);
dpm_table->GpuTjMax = (uint8_t)(cac_dtp_table->usTargetOperatingTemp);
dpm_table->GpuTjHyst = 8;
dpm_table->DTEAmbientTempBase = defaults->dte_ambient_temp_base;
dpm_table->BAPM_TEMP_GRADIENT = PP_HOST_TO_SMC_UL(defaults->bamp_temp_gradient);
pdef1 = defaults->bapmti_r;
pdef2 = defaults->bapmti_rc;
for (i = 0; i < SMU72_DTE_ITERATIONS; i++) {
for (j = 0; j < SMU72_DTE_SOURCES; j++) {
for (k = 0; k < SMU72_DTE_SINKS; k++) {
dpm_table->BAPMTI_R[i][j][k] = PP_HOST_TO_SMC_US(*pdef1);
dpm_table->BAPMTI_RC[i][j][k] = PP_HOST_TO_SMC_US(*pdef2);
pdef1++;
pdef2++;
}
}
}
return 0;
}
static int tonga_populate_svi_load_line(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
data->power_tune_table.SviLoadLineEn = defaults->svi_load_line_en;
data->power_tune_table.SviLoadLineVddC = defaults->svi_load_line_vddC;
data->power_tune_table.SviLoadLineTrimVddC = 3;
data->power_tune_table.SviLoadLineOffsetVddC = 0;
return 0;
}
static int tonga_populate_tdc_limit(struct pp_hwmgr *hwmgr)
{
uint16_t tdc_limit;
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
/* TDC number of fraction bits are changed from 8 to 7
* for Fiji as requested by SMC team
*/
tdc_limit = (uint16_t)(table_info->cac_dtp_table->usTDC * 256);
data->power_tune_table.TDC_VDDC_PkgLimit =
CONVERT_FROM_HOST_TO_SMC_US(tdc_limit);
data->power_tune_table.TDC_VDDC_ThrottleReleaseLimitPerc =
defaults->tdc_vddc_throttle_release_limit_perc;
data->power_tune_table.TDC_MAWt = defaults->tdc_mawt;
return 0;
}
static int tonga_populate_dw8(struct pp_hwmgr *hwmgr, uint32_t fuse_table_offset)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
const struct tonga_pt_defaults *defaults = data->power_tune_defaults;
uint32_t temp;
if (tonga_read_smc_sram_dword(hwmgr->smumgr,
fuse_table_offset +
offsetof(SMU72_Discrete_PmFuses, TdcWaterfallCtl),
(uint32_t *)&temp, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to read PmFuses.DW6 (SviLoadLineEn) from SMC Failed!",
return -EINVAL);
else
data->power_tune_table.TdcWaterfallCtl = defaults->tdc_waterfall_ctl;
return 0;
}
static int tonga_populate_temperature_scaler(struct pp_hwmgr *hwmgr)
{
int i;
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.LPMLTemperatureScaler[i] = 0;
return 0;
}
static int tonga_populate_fuzzy_fan(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
if ((hwmgr->thermal_controller.advanceFanControlParameters.
usFanOutputSensitivity & (1 << 15)) ||
(hwmgr->thermal_controller.advanceFanControlParameters.usFanOutputSensitivity == 0))
hwmgr->thermal_controller.advanceFanControlParameters.
usFanOutputSensitivity = hwmgr->thermal_controller.
advanceFanControlParameters.usDefaultFanOutputSensitivity;
data->power_tune_table.FuzzyFan_PwmSetDelta =
PP_HOST_TO_SMC_US(hwmgr->thermal_controller.
advanceFanControlParameters.usFanOutputSensitivity);
return 0;
}
static int tonga_populate_gnb_lpml(struct pp_hwmgr *hwmgr)
{
int i;
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
/* Currently not used. Set all to zero. */
for (i = 0; i < 16; i++)
data->power_tune_table.GnbLPML[i] = 0;
return 0;
}
static int tonga_min_max_vgnb_lpml_id_from_bapm_vddc(struct pp_hwmgr *hwmgr)
{
return 0;
}
static int tonga_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
uint16_t hi_sidd = data->power_tune_table.BapmVddCBaseLeakageHiSidd;
uint16_t lo_sidd = data->power_tune_table.BapmVddCBaseLeakageLoSidd;
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
hi_sidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256);
lo_sidd = (uint16_t)(cac_table->usLowCACLeakage / 100 * 256);
data->power_tune_table.BapmVddCBaseLeakageHiSidd =
CONVERT_FROM_HOST_TO_SMC_US(hi_sidd);
data->power_tune_table.BapmVddCBaseLeakageLoSidd =
CONVERT_FROM_HOST_TO_SMC_US(lo_sidd);
return 0;
}
int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
uint32_t pm_fuse_table_offset;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (tonga_read_smc_sram_dword(hwmgr->smumgr,
SMU72_FIRMWARE_HEADER_LOCATION +
offsetof(SMU72_Firmware_Header, PmFuseTable),
&pm_fuse_table_offset, data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to get pm_fuse_table_offset Failed!",
return -EINVAL);
/* DW6 */
if (tonga_populate_svi_load_line(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate SviLoadLine Failed!",
return -EINVAL);
/* DW7 */
if (tonga_populate_tdc_limit(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TDCLimit Failed!", return -EINVAL);
/* DW8 */
if (tonga_populate_dw8(hwmgr, pm_fuse_table_offset))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate TdcWaterfallCtl Failed !",
return -EINVAL);
/* DW9-DW12 */
if (tonga_populate_temperature_scaler(hwmgr) != 0)
PP_ASSERT_WITH_CODE(false,
"Attempt to populate LPMLTemperatureScaler Failed!",
return -EINVAL);
/* DW13-DW14 */
if (tonga_populate_fuzzy_fan(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate Fuzzy Fan Control parameters Failed!",
return -EINVAL);
/* DW15-DW18 */
if (tonga_populate_gnb_lpml(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Failed!",
return -EINVAL);
/* DW19 */
if (tonga_min_max_vgnb_lpml_id_from_bapm_vddc(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate GnbLPML Min and Max Vid Failed!",
return -EINVAL);
/* DW20 */
if (tonga_populate_bapm_vddc_base_leakage_sidd(hwmgr))
PP_ASSERT_WITH_CODE(false,
"Attempt to populate BapmVddCBaseLeakage Hi and Lo Sidd Failed!",
return -EINVAL);
if (tonga_copy_bytes_to_smc(hwmgr->smumgr, pm_fuse_table_offset,
(uint8_t *)&data->power_tune_table,
sizeof(struct SMU72_Discrete_PmFuses), data->sram_end))
PP_ASSERT_WITH_CODE(false,
"Attempt to download PmFuseTable Failed!",
return -EINVAL);
}
return 0;
}
int tonga_enable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC)) {
int smc_result;
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableCac));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to enable CAC in SMC.", result = -1);
data->cac_enabled = (smc_result == 0) ? true : false;
}
return result;
}
int tonga_disable_smc_cac(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_CAC) && data->cac_enabled) {
int smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableCac));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable CAC in SMC.", result = -1);
data->cac_enabled = false;
}
return result;
}
int tonga_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit)
return smum_send_msg_to_smc_with_parameter(hwmgr->smumgr,
PPSMC_MSG_PkgPwrSetLimit, n);
return 0;
}
static int tonga_set_overdriver_target_tdp(struct pp_hwmgr *pHwMgr, uint32_t target_tdp)
{
return smum_send_msg_to_smc_with_parameter(pHwMgr->smumgr,
PPSMC_MSG_OverDriveSetTargetTdp, target_tdp);
}
int tonga_enable_power_containment(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
int smc_result;
int result = 0;
data->power_containment_features = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
if (data->enable_dte_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_EnableDTE));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to enable DTE in SMC.", result = -1;);
if (smc_result == 0)
data->power_containment_features |= POWERCONTAINMENT_FEATURE_DTE;
}
if (data->enable_tdc_limit_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitEnable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to enable TDCLimit in SMC.", result = -1;);
if (smc_result == 0)
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_TDCLimit;
}
if (data->enable_pkg_pwr_tracking_feature) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitEnable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to enable PkgPwrTracking in SMC.", result = -1;);
if (smc_result == 0) {
struct phm_cac_tdp_table *cac_table =
table_info->cac_dtp_table;
uint32_t default_limit =
(uint32_t)(cac_table->usMaximumPowerDeliveryLimit * 256);
data->power_containment_features |=
POWERCONTAINMENT_FEATURE_PkgPwrLimit;
if (tonga_set_power_limit(hwmgr, default_limit))
printk(KERN_ERR "Failed to set Default Power Limit in SMC!");
}
}
}
return result;
}
int tonga_disable_power_containment(struct pp_hwmgr *hwmgr)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment) &&
data->power_containment_features) {
int smc_result;
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_TDCLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_TDCLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable TDCLimit in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_DTE) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_DisableDTE));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable DTE in SMC.",
result = smc_result);
}
if (data->power_containment_features &
POWERCONTAINMENT_FEATURE_PkgPwrLimit) {
smc_result = smum_send_msg_to_smc(hwmgr->smumgr,
(uint16_t)(PPSMC_MSG_PkgPwrLimitDisable));
PP_ASSERT_WITH_CODE((smc_result == 0),
"Failed to disable PkgPwrTracking in SMC.",
result = smc_result);
}
data->power_containment_features = 0;
}
return result;
}
int tonga_power_control_set_level(struct pp_hwmgr *hwmgr)
{
struct phm_ppt_v1_information *table_info =
(struct phm_ppt_v1_information *)(hwmgr->pptable);
struct phm_cac_tdp_table *cac_table = table_info->cac_dtp_table;
int adjust_percent, target_tdp;
int result = 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
PHM_PlatformCaps_PowerContainment)) {
/* adjustment percentage has already been validated */
adjust_percent = hwmgr->platform_descriptor.TDPAdjustmentPolarity ?
hwmgr->platform_descriptor.TDPAdjustment :
(-1 * hwmgr->platform_descriptor.TDPAdjustment);
/* SMC requested that target_tdp to be 7 bit fraction in DPM table
* but message to be 8 bit fraction for messages
*/
target_tdp = ((100 + adjust_percent) * (int)(cac_table->usTDP * 256)) / 100;
result = tonga_set_overdriver_target_tdp(hwmgr, (uint32_t)target_tdp);
}
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_POWERTUNE_H
#define TONGA_POWERTUNE_H
enum _phw_tonga_ptc_config_reg_type {
TONGA_CONFIGREG_MMR = 0,
TONGA_CONFIGREG_SMC_IND,
TONGA_CONFIGREG_DIDT_IND,
TONGA_CONFIGREG_CACHE,
TONGA_CONFIGREG_MAX
};
typedef enum _phw_tonga_ptc_config_reg_type phw_tonga_ptc_config_reg_type;
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_DTE 0x00000001
/* PowerContainment Features */
#define POWERCONTAINMENT_FEATURE_BAPM 0x00000001
#define POWERCONTAINMENT_FEATURE_TDCLimit 0x00000002
#define POWERCONTAINMENT_FEATURE_PkgPwrLimit 0x00000004
struct tonga_pt_config_reg {
uint32_t Offset;
uint32_t Mask;
uint32_t Shift;
uint32_t Value;
phw_tonga_ptc_config_reg_type Type;
};
struct tonga_pt_defaults {
uint8_t svi_load_line_en;
uint8_t svi_load_line_vddC;
uint8_t tdc_vddc_throttle_release_limit_perc;
uint8_t tdc_mawt;
uint8_t tdc_waterfall_ctl;
uint8_t dte_ambient_temp_base;
uint32_t display_cac;
uint32_t bamp_temp_gradient;
uint16_t bapmti_r[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
uint16_t bapmti_rc[SMU72_DTE_ITERATIONS * SMU72_DTE_SOURCES * SMU72_DTE_SINKS];
};
void tonga_initialize_power_tune_defaults(struct pp_hwmgr *hwmgr);
int tonga_populate_bapm_parameters_in_dpm_table(struct pp_hwmgr *hwmgr);
int tonga_populate_pm_fuses(struct pp_hwmgr *hwmgr);
int tonga_enable_smc_cac(struct pp_hwmgr *hwmgr);
int tonga_disable_smc_cac(struct pp_hwmgr *hwmgr);
int tonga_enable_power_containment(struct pp_hwmgr *hwmgr);
int tonga_disable_power_containment(struct pp_hwmgr *hwmgr);
int tonga_set_power_limit(struct pp_hwmgr *hwmgr, uint32_t n);
int tonga_power_control_set_level(struct pp_hwmgr *hwmgr);
#endif
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include <asm/div64.h>
#include "tonga_thermal.h"
#include "tonga_hwmgr.h"
#include "tonga_smumgr.h"
#include "tonga_ppsmc.h"
#include "smu/smu_7_1_2_d.h"
#include "smu/smu_7_1_2_sh_mask.h"
/**
* Get Fan Speed Control Parameters.
* @param hwmgr the address of the powerplay hardware manager.
* @param pSpeed is the address of the structure where the result is to be placed.
* @exception Always succeeds except if we cannot zero out the output structure.
*/
int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info)
{
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
fan_speed_info->supports_percent_read = true;
fan_speed_info->supports_percent_write = true;
fan_speed_info->min_percent = 0;
fan_speed_info->max_percent = 100;
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution) {
fan_speed_info->supports_rpm_read = true;
fan_speed_info->supports_rpm_write = true;
fan_speed_info->min_rpm = hwmgr->thermal_controller.fanInfo.ulMinRPM;
fan_speed_info->max_rpm = hwmgr->thermal_controller.fanInfo.ulMaxRPM;
} else {
fan_speed_info->min_rpm = 0;
fan_speed_info->max_rpm = 0;
}
return 0;
}
/**
* Get Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param pSpeed is the address of the structure where the result is to be placed.
* @exception Fails is the 100% setting appears to be 0.
*/
int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
duty = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_STATUS, FDO_PWM_DUTY);
if (0 == duty100)
return -EINVAL;
tmp64 = (uint64_t)duty * 100;
do_div(tmp64, duty100);
*speed = (uint32_t)tmp64;
if (*speed > 100)
*speed = 100;
return 0;
}
/**
* Get Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the address of the structure where the result is to be placed.
* @exception Returns not supported if no fan is found or if pulses per revolution are not set
*/
int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed)
{
return 0;
}
/**
* Set Fan Speed Control to static mode, so that the user can decide what speed to use.
* @param hwmgr the address of the powerplay hardware manager.
* mode the fan control mode, 0 default, 1 by percent, 5, by RPM
* @exception Should always succeed.
*/
int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode)
{
if (hwmgr->fan_ctrl_is_in_default_mode) {
hwmgr->fan_ctrl_default_mode = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE);
hwmgr->tmin = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN);
hwmgr->fan_ctrl_is_in_default_mode = false;
}
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, 0);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, mode);
return 0;
}
/**
* Reset Fan Speed Control to default mode.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Should always succeed.
*/
int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->fan_ctrl_is_in_default_mode) {
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, FDO_PWM_MODE, hwmgr->fan_ctrl_default_mode);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TMIN, hwmgr->tmin);
hwmgr->fan_ctrl_is_in_default_mode = true;
}
return 0;
}
int tonga_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr)
{
int result;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ODFuzzyFanControlSupport)) {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_FUZZY);
result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
/*
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_FanSpeedInTableIsRPM))
hwmgr->set_max_fan_rpm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM);
else
hwmgr->set_max_fan_pwm_output(hwmgr, hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanPWM);
*/
} else {
cgs_write_register(hwmgr->device, mmSMC_MSG_ARG_0, FAN_CONTROL_TABLE);
result = (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StartFanControl) == 0) ? 0 : -EINVAL;
}
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
if (result == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature != 0)
result = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanTemperatureTarget, \
hwmgr->thermal_controller.advanceFanControlParameters.ucTargetTemperature) ? 0 : -EINVAL);
*/
return result;
}
int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr)
{
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_StopFanControl) == 0) ? 0 : -EINVAL;
}
/**
* Set Fan Speed in percent.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (0% - 100%) to be set.
* @exception Fails is the 100% setting appears to be 0.
*/
int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed)
{
uint32_t duty100;
uint32_t duty;
uint64_t tmp64;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return -EINVAL;
if (speed > 100)
speed = 100;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
tonga_fan_ctrl_stop_smc_fan_control(hwmgr);
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
if (0 == duty100)
return -EINVAL;
tmp64 = (uint64_t)speed * duty100;
do_div(tmp64, 100);
duty = (uint32_t)tmp64;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL0, FDO_STATIC_DUTY, duty);
return tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
/**
* Reset Fan Speed to default.
* @param hwmgr the address of the powerplay hardware manager.
* @exception Always succeeds.
*/
int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr)
{
int result;
if (hwmgr->thermal_controller.fanInfo.bNoFan)
return 0;
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
result = tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
if (0 == result)
result = tonga_fan_ctrl_start_smc_fan_control(hwmgr);
} else
result = tonga_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set Fan Speed in RPM.
* @param hwmgr the address of the powerplay hardware manager.
* @param speed is the percentage value (min - max) to be set.
* @exception Fails is the speed not lie between min and max.
*/
int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed)
{
return 0;
}
/**
* Reads the remote temperature from the SIslands thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr)
{
int temp;
temp = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_STATUS, CTF_TEMP);
/* Bit 9 means the reading is lower than the lowest usable value. */
if (0 != (0x200 & temp))
temp = TONGA_THERMAL_MAXIMUM_TEMP_READING;
else
temp = (temp & 0x1ff);
temp = temp * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
return temp;
}
/**
* Set the requested temperature range for high and low alert signals
*
* @param hwmgr The address of the hardware manager.
* @param range Temperature range to be programmed for high and low alert signals
* @exception PP_Result_BadInput if the input data is not valid.
*/
static int tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, uint32_t low_temp, uint32_t high_temp)
{
uint32_t low = TONGA_THERMAL_MINIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
uint32_t high = TONGA_THERMAL_MAXIMUM_ALERT_TEMP * PP_TEMPERATURE_UNITS_PER_CENTIGRADES;
if (low < low_temp)
low = low_temp;
if (high > high_temp)
high = high_temp;
if (low > high)
return -EINVAL;
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTH, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, DIG_THERM_INTL, (low / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_CTRL, DIG_THERM_DPM, (high / PP_TEMPERATURE_UNITS_PER_CENTIGRADES));
return 0;
}
/**
* Programs thermal controller one-time setting registers
*
* @param hwmgr The address of the hardware manager.
*/
static int tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
{
if (0 != hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution)
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
CG_TACH_CTRL, EDGE_PER_REV,
hwmgr->thermal_controller.fanInfo.ucTachometerPulsesPerRevolution - 1);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL2, TACH_PWM_RESP_RATE, 0x28);
return 0;
}
/**
* Enable thermal alerts on the RV770 thermal controller.
*
* @param hwmgr The address of the hardware manager.
*/
static int tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
alert &= ~(TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to enable internal thermal interrupts */
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Enable) == 0) ? 0 : -1;
}
/**
* Disable thermal alerts on the RV770 thermal controller.
* @param hwmgr The address of the hardware manager.
*/
static int tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr)
{
uint32_t alert;
alert = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK);
alert |= (TONGA_THERMAL_HIGH_ALERT_MASK | TONGA_THERMAL_LOW_ALERT_MASK);
PHM_WRITE_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_THERMAL_INT, THERM_INT_MASK, alert);
/* send message to SMU to disable internal thermal interrupts */
return (smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_Thermal_Cntl_Disable) == 0) ? 0 : -1;
}
/**
* Uninitialize the thermal controller.
* Currently just disables alerts.
* @param hwmgr The address of the hardware manager.
*/
int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr)
{
int result = tonga_thermal_disable_alert(hwmgr);
if (hwmgr->thermal_controller.fanInfo.bNoFan)
tonga_fan_ctrl_set_default_mode(hwmgr);
return result;
}
/**
* Set up the fan table to control the fan using the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_tonga_thermal_setup_fan_table(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
struct tonga_hwmgr *data = (struct tonga_hwmgr *)(hwmgr->backend);
SMU72_Discrete_FanTable fan_table = { FDO_MODE_HARDWARE };
uint32_t duty100;
uint32_t t_diff1, t_diff2, pwm_diff1, pwm_diff2;
uint16_t fdo_min, slope1, slope2;
uint32_t reference_clock;
int res;
uint64_t tmp64;
if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl))
return 0;
if (0 == data->fan_table_start) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
duty100 = PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_FDO_CTRL1, FMAX_DUTY100);
if (0 == duty100) {
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
return 0;
}
tmp64 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin * duty100;
do_div(tmp64, 10000);
fdo_min = (uint16_t)tmp64;
t_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usTMed - hwmgr->thermal_controller.advanceFanControlParameters.usTMin;
t_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usTHigh - hwmgr->thermal_controller.advanceFanControlParameters.usTMed;
pwm_diff1 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin;
pwm_diff2 = hwmgr->thermal_controller.advanceFanControlParameters.usPWMHigh - hwmgr->thermal_controller.advanceFanControlParameters.usPWMMed;
slope1 = (uint16_t)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (uint16_t)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
fan_table.TempMin = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMin) / 100);
fan_table.TempMed = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMed) / 100);
fan_table.TempMax = cpu_to_be16((50 + hwmgr->thermal_controller.advanceFanControlParameters.usTMax) / 100);
fan_table.Slope1 = cpu_to_be16(slope1);
fan_table.Slope2 = cpu_to_be16(slope2);
fan_table.FdoMin = cpu_to_be16(fdo_min);
fan_table.HystDown = cpu_to_be16(hwmgr->thermal_controller.advanceFanControlParameters.ucTHyst);
fan_table.HystUp = cpu_to_be16(1);
fan_table.HystSlope = cpu_to_be16(1);
fan_table.TempRespLim = cpu_to_be16(5);
reference_clock = tonga_get_xclk(hwmgr);
fan_table.RefreshPeriod = cpu_to_be32((hwmgr->thermal_controller.advanceFanControlParameters.ulCycleDelay * reference_clock) / 1600);
fan_table.FdoMax = cpu_to_be16((uint16_t)duty100);
fan_table.TempSrc = (uint8_t)PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, CG_MULT_THERMAL_CTRL, TEMP_SEL);
fan_table.FanControl_GL_Flag = 1;
res = tonga_copy_bytes_to_smc(hwmgr->smumgr, data->fan_table_start, (uint8_t *)&fan_table, (uint32_t)sizeof(fan_table), data->sram_end);
/* TO DO FOR SOME DEVICE ID 0X692b, send this msg return invalid command.
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit != 0)
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanMinPwm, \
hwmgr->thermal_controller.advanceFanControlParameters.ucMinimumPWMLimit) ? 0 : -1);
if (res == 0 && hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit != 0)
res = (0 == smum_send_msg_to_smc_with_parameter(hwmgr->smumgr, PPSMC_MSG_SetFanSclkTarget, \
hwmgr->thermal_controller.advanceFanControlParameters.ulMinFanSCLKAcousticLimit) ? 0 : -1);
if (0 != res)
phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl);
*/
return 0;
}
/**
* Start the fan control on the SMC.
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_tonga_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
/* If the fantable setup has failed we could have disabled PHM_PlatformCaps_MicrocodeFanControl even after this function was included in the table.
* Make sure that we still think controlling the fan is OK.
*/
if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_MicrocodeFanControl)) {
tonga_fan_ctrl_start_smc_fan_control(hwmgr);
tonga_fan_ctrl_set_static_mode(hwmgr, FDO_PWM_MODE_STATIC);
}
return 0;
}
/**
* Set temperature range for high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from set temperature range routine
*/
int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
struct PP_TemperatureRange *range = (struct PP_TemperatureRange *)input;
if (range == NULL)
return -EINVAL;
return tonga_thermal_set_temperature_range(hwmgr, range->min, range->max);
}
/**
* Programs one-time setting registers
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from initialize thermal controller routine
*/
int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
return tonga_thermal_initialize(hwmgr);
}
/**
* Enable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from enable alert routine
*/
int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
return tonga_thermal_enable_alert(hwmgr);
}
/**
* Disable high and low alerts
* @param hwmgr the address of the powerplay hardware manager.
* @param pInput the pointer to input data
* @param pOutput the pointer to output data
* @param pStorage the pointer to temporary storage
* @param Result the last failure code
* @return result from disable alert routine
*/
static int tf_tonga_thermal_disable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result)
{
return tonga_thermal_disable_alert(hwmgr);
}
static const struct phm_master_table_item tonga_thermal_start_thermal_controller_master_list[] = {
{ NULL, tf_tonga_thermal_initialize },
{ NULL, tf_tonga_thermal_set_temperature_range },
{ NULL, tf_tonga_thermal_enable_alert },
/* We should restrict performance levels to low before we halt the SMC.
* On the other hand we are still in boot state when we do this so it would be pointless.
* If this assumption changes we have to revisit this table.
*/
{ NULL, tf_tonga_thermal_setup_fan_table},
{ NULL, tf_tonga_thermal_start_smc_fan_control},
{ NULL, NULL }
};
static const struct phm_master_table_header tonga_thermal_start_thermal_controller_master = {
0,
PHM_MasterTableFlag_None,
tonga_thermal_start_thermal_controller_master_list
};
static const struct phm_master_table_item tonga_thermal_set_temperature_range_master_list[] = {
{ NULL, tf_tonga_thermal_disable_alert},
{ NULL, tf_tonga_thermal_set_temperature_range},
{ NULL, tf_tonga_thermal_enable_alert},
{ NULL, NULL }
};
static const struct phm_master_table_header tonga_thermal_set_temperature_range_master = {
0,
PHM_MasterTableFlag_None,
tonga_thermal_set_temperature_range_master_list
};
int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr)
{
if (!hwmgr->thermal_controller.fanInfo.bNoFan)
tonga_fan_ctrl_set_default_mode(hwmgr);
return 0;
}
/**
* Initializes the thermal controller related functions in the Hardware Manager structure.
* @param hwmgr The address of the hardware manager.
* @exception Any error code from the low-level communication.
*/
int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr)
{
int result;
result = phm_construct_table(hwmgr, &tonga_thermal_set_temperature_range_master, &(hwmgr->set_temperature_range));
if (0 == result) {
result = phm_construct_table(hwmgr,
&tonga_thermal_start_thermal_controller_master,
&(hwmgr->start_thermal_controller));
if (0 != result)
phm_destroy_table(hwmgr, &(hwmgr->set_temperature_range));
}
if (0 == result)
hwmgr->fan_ctrl_is_in_default_mode = true;
return result;
}
/*
* Copyright 2015 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef TONGA_THERMAL_H
#define TONGA_THERMAL_H
#include "hwmgr.h"
#define TONGA_THERMAL_HIGH_ALERT_MASK 0x1
#define TONGA_THERMAL_LOW_ALERT_MASK 0x2
#define TONGA_THERMAL_MINIMUM_TEMP_READING -256
#define TONGA_THERMAL_MAXIMUM_TEMP_READING 255
#define TONGA_THERMAL_MINIMUM_ALERT_TEMP 0
#define TONGA_THERMAL_MAXIMUM_ALERT_TEMP 255
#define FDO_PWM_MODE_STATIC 1
#define FDO_PWM_MODE_STATIC_RPM 5
extern int tf_tonga_thermal_initialize(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_tonga_thermal_set_temperature_range(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tf_tonga_thermal_enable_alert(struct pp_hwmgr *hwmgr, void *input, void *output, void *storage, int result);
extern int tonga_thermal_get_temperature(struct pp_hwmgr *hwmgr);
extern int tonga_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr);
extern int tonga_fan_ctrl_get_fan_speed_info(struct pp_hwmgr *hwmgr, struct phm_fan_speed_info *fan_speed_info);
extern int tonga_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int tonga_fan_ctrl_set_default_mode(struct pp_hwmgr *hwmgr);
extern int tonga_fan_ctrl_set_static_mode(struct pp_hwmgr *hwmgr, uint32_t mode);
extern int tonga_fan_ctrl_set_fan_speed_percent(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int tonga_fan_ctrl_reset_fan_speed_to_default(struct pp_hwmgr *hwmgr);
extern int pp_tonga_thermal_initialize(struct pp_hwmgr *hwmgr);
extern int tonga_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr);
extern int tonga_fan_ctrl_set_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t speed);
extern int tonga_fan_ctrl_get_fan_speed_rpm(struct pp_hwmgr *hwmgr, uint32_t *speed);
extern int tonga_fan_ctrl_stop_smc_fan_control(struct pp_hwmgr *hwmgr);
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment