Commit 025f8bfb authored by Huang Rui's avatar Huang Rui Committed by Alex Deucher

drm/amd/powerplay: add iceland HW manager

This patch introduces the iceland HW manager of powerplay which
includes HW manager, clockpowergating, thermal, and powertune.
Signed-off-by: default avatarHuang Rui <ray.huang@amd.com>
Reviewed-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent d550df0b
......@@ -10,7 +10,9 @@ HARDWARE_MGR = hwmgr.o processpptables.o functiontables.o \
fiji_powertune.o fiji_hwmgr.o tonga_clockpowergating.o \
fiji_clockpowergating.o fiji_thermal.o \
polaris10_hwmgr.o polaris10_powertune.o polaris10_thermal.o \
polaris10_clockpowergating.o
polaris10_clockpowergating.o iceland_hwmgr.o \
iceland_clockpowergating.o iceland_thermal.o \
iceland_powertune.o
AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR))
......
......@@ -39,6 +39,7 @@ extern int cz_hwmgr_init(struct pp_hwmgr *hwmgr);
extern int tonga_hwmgr_init(struct pp_hwmgr *hwmgr);
extern int fiji_hwmgr_init(struct pp_hwmgr *hwmgr);
extern int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr);
extern int iceland_hwmgr_init(struct pp_hwmgr *hwmgr);
int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
{
......@@ -67,6 +68,9 @@ int hwmgr_init(struct amd_pp_init *pp_init, struct pp_instance *handle)
break;
case AMDGPU_FAMILY_VI:
switch (hwmgr->chip_id) {
case CHIP_TOPAZ:
iceland_hwmgr_init(hwmgr);
break;
case CHIP_TONGA:
tonga_hwmgr_init(hwmgr);
break;
......
/*
* 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_ */
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 (hwmgr->powercontainment_enabled) {
phm_cap_set(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 (iceland_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 (iceland_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 (iceland_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;
};
struct iceland_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[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
uint16_t bapmti_rc[SMU71_DTE_ITERATIONS * SMU71_DTE_SOURCES * SMU71_DTE_SINKS];
};
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 = iceland_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
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