diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay')
62 files changed, 11101 insertions, 1799 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile index 727c5cff231c..390345f2d601 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/powerplay/Makefile @@ -35,7 +35,7 @@ AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$( include $(AMD_POWERPLAY) -POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o vega20_ppt.o navi10_ppt.o +POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o smu_v12_0.o vega20_ppt.o arcturus_ppt.o navi10_ppt.o renoir_ppt.o AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index bea1587d352d..c195575366a3 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -48,7 +48,6 @@ static int amd_powerplay_create(struct amdgpu_device *adev) hwmgr->adev = adev; hwmgr->not_vf = !amdgpu_sriov_vf(adev); - hwmgr->pm_en = (amdgpu_dpm && hwmgr->not_vf) ? true : false; hwmgr->device = amdgpu_cgs_create_device(adev); mutex_init(&hwmgr->smu_lock); hwmgr->chip_family = adev->family; @@ -924,6 +923,22 @@ static int pp_odn_edit_dpm_table(void *handle, uint32_t type, long *input, uint3 return hwmgr->hwmgr_func->odn_edit_dpm_table(hwmgr, type, input, size); } +static int pp_dpm_set_mp1_state(void *handle, enum pp_mp1_state mp1_state) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr) + return -EINVAL; + + if (!hwmgr->pm_en) + return 0; + + if (hwmgr->hwmgr_func->set_mp1_state) + return hwmgr->hwmgr_func->set_mp1_state(hwmgr, mp1_state); + + return 0; +} + static int pp_dpm_switch_power_profile(void *handle, enum PP_SMC_POWER_PROFILE type, bool en) { @@ -956,6 +971,14 @@ static int pp_dpm_switch_power_profile(void *handle, workload = hwmgr->workload_setting[index]; } + if (type == PP_SMC_POWER_PROFILE_COMPUTE && + hwmgr->hwmgr_func->disable_power_features_for_compute_performance) { + if (hwmgr->hwmgr_func->disable_power_features_for_compute_performance(hwmgr, en)) { + mutex_unlock(&hwmgr->smu_lock); + return -EINVAL; + } + } + if (hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) hwmgr->hwmgr_func->set_power_profile_mode(hwmgr, &workload, 0); mutex_unlock(&hwmgr->smu_lock); @@ -1408,6 +1431,7 @@ static int pp_get_asic_baco_capability(void *handle, bool *cap) { struct pp_hwmgr *hwmgr = handle; + *cap = false; if (!hwmgr) return -EINVAL; @@ -1495,6 +1519,80 @@ static int pp_set_ppfeature_status(void *handle, uint64_t ppfeature_masks) return ret; } +static int pp_asic_reset_mode_2(void *handle) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL; + + if (hwmgr->hwmgr_func->asic_reset == NULL) { + pr_info_ratelimited("%s was not implemented.\n", __func__); + return -EINVAL; + } + + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->asic_reset(hwmgr, SMU_ASIC_RESET_MODE_2); + mutex_unlock(&hwmgr->smu_lock); + + return ret; +} + +static int pp_smu_i2c_bus_access(void *handle, bool acquire) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL; + + if (hwmgr->hwmgr_func->smu_i2c_bus_access == NULL) { + pr_info_ratelimited("%s was not implemented.\n", __func__); + return -EINVAL; + } + + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->smu_i2c_bus_access(hwmgr, acquire); + mutex_unlock(&hwmgr->smu_lock); + + return ret; +} + +static int pp_set_df_cstate(void *handle, enum pp_df_cstate state) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr) + return -EINVAL; + + if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_df_cstate) + return 0; + + mutex_lock(&hwmgr->smu_lock); + hwmgr->hwmgr_func->set_df_cstate(hwmgr, state); + mutex_unlock(&hwmgr->smu_lock); + + return 0; +} + +static int pp_set_xgmi_pstate(void *handle, uint32_t pstate) +{ + struct pp_hwmgr *hwmgr = handle; + + if (!hwmgr) + return -EINVAL; + + if (!hwmgr->pm_en || !hwmgr->hwmgr_func->set_xgmi_pstate) + return 0; + + mutex_lock(&hwmgr->smu_lock); + hwmgr->hwmgr_func->set_xgmi_pstate(hwmgr, pstate); + mutex_unlock(&hwmgr->smu_lock); + + return 0; +} + static const struct amd_pm_funcs pp_dpm_funcs = { .load_firmware = pp_dpm_load_fw, .wait_for_fw_loading_complete = pp_dpm_fw_loading_complete, @@ -1525,6 +1623,7 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .get_power_profile_mode = pp_get_power_profile_mode, .set_power_profile_mode = pp_set_power_profile_mode, .odn_edit_dpm_table = pp_odn_edit_dpm_table, + .set_mp1_state = pp_dpm_set_mp1_state, .set_power_limit = pp_set_power_limit, .get_power_limit = pp_get_power_limit, /* export to DC */ @@ -1550,4 +1649,8 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .set_asic_baco_state = pp_set_asic_baco_state, .get_ppfeature_status = pp_get_ppfeature_status, .set_ppfeature_status = pp_set_ppfeature_status, + .asic_reset_mode_2 = pp_asic_reset_mode_2, + .smu_i2c_bus_access = pp_smu_i2c_bus_access, + .set_df_cstate = pp_set_df_cstate, + .set_xgmi_pstate = pp_set_xgmi_pstate, }; diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c index 8a3eadeebdcb..99ad4ddbe12f 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c @@ -21,14 +21,171 @@ */ #include <linux/firmware.h> +#include <linux/pci.h> #include "pp_debug.h" #include "amdgpu.h" #include "amdgpu_smu.h" +#include "smu_internal.h" #include "soc15_common.h" #include "smu_v11_0.h" +#include "smu_v12_0.h" #include "atom.h" #include "amd_pcie.h" +#include "vega20_ppt.h" +#include "arcturus_ppt.h" +#include "navi10_ppt.h" +#include "renoir_ppt.h" + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(type) #type +static const char* __smu_message_names[] = { + SMU_MESSAGE_TYPES +}; + +const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type) +{ + if (type < 0 || type >= SMU_MSG_MAX_COUNT) + return "unknown smu message"; + return __smu_message_names[type]; +} + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(fea) #fea +static const char* __smu_feature_names[] = { + SMU_FEATURE_MASKS +}; + +const char *smu_get_feature_name(struct smu_context *smu, enum smu_feature_mask feature) +{ + if (feature < 0 || feature >= SMU_FEATURE_COUNT) + return "unknown smu feature"; + return __smu_feature_names[feature]; +} + +size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf) +{ + size_t size = 0; + int ret = 0, i = 0; + uint32_t feature_mask[2] = { 0 }; + int32_t feature_index = 0; + uint32_t count = 0; + uint32_t sort_feature[SMU_FEATURE_COUNT]; + uint64_t hw_feature_count = 0; + + mutex_lock(&smu->mutex); + + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + if (ret) + goto failed; + + size = sprintf(buf + size, "features high: 0x%08x low: 0x%08x\n", + feature_mask[1], feature_mask[0]); + + for (i = 0; i < SMU_FEATURE_COUNT; i++) { + feature_index = smu_feature_get_index(smu, i); + if (feature_index < 0) + continue; + sort_feature[feature_index] = i; + hw_feature_count++; + } + + for (i = 0; i < hw_feature_count; i++) { + size += sprintf(buf + size, "%02d. %-20s (%2d) : %s\n", + count++, + smu_get_feature_name(smu, sort_feature[i]), + i, + !!smu_feature_is_enabled(smu, sort_feature[i]) ? + "enabled" : "disabled"); + } + +failed: + mutex_unlock(&smu->mutex); + + return size; +} + +static int smu_feature_update_enable_state(struct smu_context *smu, + uint64_t feature_mask, + bool enabled) +{ + struct smu_feature *feature = &smu->smu_feature; + uint32_t feature_low = 0, feature_high = 0; + int ret = 0; + + if (!smu->pm_enabled) + return ret; + + feature_low = (feature_mask >> 0 ) & 0xffffffff; + feature_high = (feature_mask >> 32) & 0xffffffff; + + if (enabled) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, + feature_low); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, + feature_high); + if (ret) + return ret; + } else { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, + feature_low); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, + feature_high); + if (ret) + return ret; + } + + mutex_lock(&feature->mutex); + if (enabled) + bitmap_or(feature->enabled, feature->enabled, + (unsigned long *)(&feature_mask), SMU_FEATURE_MAX); + else + bitmap_andnot(feature->enabled, feature->enabled, + (unsigned long *)(&feature_mask), SMU_FEATURE_MAX); + mutex_unlock(&feature->mutex); + + return ret; +} + +int smu_sys_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) +{ + int ret = 0; + uint32_t feature_mask[2] = { 0 }; + uint64_t feature_2_enabled = 0; + uint64_t feature_2_disabled = 0; + uint64_t feature_enables = 0; + + mutex_lock(&smu->mutex); + + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + if (ret) + goto out; + + feature_enables = ((uint64_t)feature_mask[1] << 32 | (uint64_t)feature_mask[0]); + + feature_2_enabled = ~feature_enables & new_mask; + feature_2_disabled = feature_enables & ~new_mask; + + if (feature_2_enabled) { + ret = smu_feature_update_enable_state(smu, feature_2_enabled, true); + if (ret) + goto out; + } + if (feature_2_disabled) { + ret = smu_feature_update_enable_state(smu, feature_2_disabled, false); + if (ret) + goto out; + } + +out: + mutex_unlock(&smu->mutex); + + return ret; +} int smu_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t *smu_version) { @@ -63,8 +220,7 @@ int smu_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max) { - int ret = 0, clk_id = 0; - uint32_t param; + int ret = 0; if (min <= 0 && max <= 0) return -EINVAL; @@ -72,27 +228,7 @@ int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, if (!smu_clk_dpm_is_enabled(smu, clk_type)) return 0; - clk_id = smu_clk_get_index(smu, clk_type); - if (clk_id < 0) - return clk_id; - - if (max > 0) { - param = (uint32_t)((clk_id << 16) | (max & 0xffff)); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, - param); - if (ret) - return ret; - } - - if (min > 0) { - param = (uint32_t)((clk_id << 16) | (min & 0xffff)); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, - param); - if (ret) - return ret; - } - - + ret = smu_set_soft_freq_limited_range(smu, clk_type, min, max); return ret; } @@ -133,15 +269,17 @@ int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, } int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t *min, uint32_t *max) + uint32_t *min, uint32_t *max, bool lock_needed) { - int ret = 0, clk_id = 0; - uint32_t param = 0; uint32_t clock_limit; + int ret = 0; if (!min && !max) return -EINVAL; + if (lock_needed) + mutex_lock(&smu->mutex); + if (!smu_clk_dpm_is_enabled(smu, clk_type)) { switch (clk_type) { case SMU_MCLK: @@ -165,39 +303,17 @@ int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, *min = clock_limit / 100; if (max) *max = clock_limit / 100; - - return 0; - } - - mutex_lock(&smu->mutex); - clk_id = smu_clk_get_index(smu, clk_type); - if (clk_id < 0) { - ret = -EINVAL; - goto failed; - } - - param = (clk_id & 0xffff) << 16; - - if (max) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, param); - if (ret) - goto failed; - ret = smu_read_smc_arg(smu, max); - if (ret) - goto failed; + } else { + /* + * Todo: Use each asic(ASIC_ppt funcs) control the callbacks exposed to the + * core driver and then have helpers for stuff that is common(SMU_v11_x | SMU_v12_x funcs). + */ + ret = smu_get_dpm_ultimate_freq(smu, clk_type, min, max); } - if (min) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param); - if (ret) - goto failed; - ret = smu_read_smc_arg(smu, min); - if (ret) - goto failed; - } + if (lock_needed) + mutex_unlock(&smu->mutex); -failed: - mutex_unlock(&smu->mutex); return ret; } @@ -241,6 +357,35 @@ int smu_get_dpm_level_count(struct smu_context *smu, enum smu_clk_type clk_type, return smu_get_dpm_freq_by_index(smu, clk_type, 0xff, value); } +int smu_get_dpm_level_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min_value, uint32_t *max_value) +{ + int ret = 0; + uint32_t level_count = 0; + + if (!min_value && !max_value) + return -EINVAL; + + if (min_value) { + /* by default, level 0 clock value as min value */ + ret = smu_get_dpm_freq_by_index(smu, clk_type, 0, min_value); + if (ret) + return ret; + } + + if (max_value) { + ret = smu_get_dpm_level_count(smu, clk_type, &level_count); + if (ret) + return ret; + + ret = smu_get_dpm_freq_by_index(smu, clk_type, level_count - 1, max_value); + if (ret) + return ret; + } + + return ret; +} + bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type) { enum smu_feature_mask feature_id = 0; @@ -262,14 +407,26 @@ bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type) } if(!smu_feature_is_enabled(smu, feature_id)) { - pr_warn("smu %d clk dpm feature %d is not enabled\n", clk_type, feature_id); return false; } return true; } - +/** + * smu_dpm_set_power_gate - power gate/ungate the specific IP block + * + * @smu: smu_context pointer + * @block_type: the IP block to power gate/ungate + * @gate: to power gate if true, ungate otherwise + * + * This API uses no smu->mutex lock protection due to: + * 1. It is either called by other IP block(gfx/sdma/vcn/uvd/vce). + * This is guarded to be race condition free by the caller. + * 2. Or get called on user setting request of power_dpm_force_performance_level. + * Under this case, the smu->mutex lock protection is already enforced on + * the parent API smu_force_performance_level of the call path. + */ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, bool gate) { @@ -277,14 +434,20 @@ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, switch (block_type) { case AMD_IP_BLOCK_TYPE_UVD: - ret = smu_dpm_set_uvd_enable(smu, gate); + ret = smu_dpm_set_uvd_enable(smu, !gate); break; case AMD_IP_BLOCK_TYPE_VCE: - ret = smu_dpm_set_vce_enable(smu, gate); + ret = smu_dpm_set_vce_enable(smu, !gate); break; case AMD_IP_BLOCK_TYPE_GFX: ret = smu_gfx_off_control(smu, gate); break; + case AMD_IP_BLOCK_TYPE_SDMA: + ret = smu_powergate_sdma(smu, gate); + break; + case AMD_IP_BLOCK_TYPE_JPEG: + ret = smu_dpm_set_jpeg_enable(smu, !gate); + break; default: break; } @@ -292,12 +455,6 @@ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, return ret; } -enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu) -{ - /* not support power state */ - return POWER_STATE_TYPE_DEFAULT; -} - int smu_get_power_num_states(struct smu_context *smu, struct pp_states_info *state_info) { @@ -319,6 +476,9 @@ int smu_common_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, struct smu_power_gate *power_gate = &smu_power->power_gate; int ret = 0; + if(!data || !size) + return -EINVAL; + switch (sensor) { case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: *((uint32_t *)data) = smu->pstate_sclk; @@ -359,26 +519,26 @@ int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int void *table_data, bool drv2smu) { struct smu_table_context *smu_table = &smu->smu_table; - struct smu_table *table = NULL; - int ret = 0; + struct amdgpu_device *adev = smu->adev; + struct smu_table *table = &smu_table->driver_table; int table_id = smu_table_get_index(smu, table_index); + uint32_t table_size; + int ret = 0; - if (!table_data || table_id >= smu_table->table_count) + if (!table_data || table_id >= SMU_TABLE_COUNT || table_id < 0) return -EINVAL; - table = &smu_table->tables[table_index]; + table_size = smu_table->tables[table_index].size; - if (drv2smu) - memcpy(table->cpu_addr, table_data, table->size); + if (drv2smu) { + memcpy(table->cpu_addr, table_data, table_size); + /* + * Flush hdp cache: to guard the content seen by + * GPU is consitent with CPU. + */ + amdgpu_asic_flush_hdp(adev, NULL); + } - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrHigh, - upper_32_bits(table->mc_address)); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrLow, - lower_32_bits(table->mc_address)); - if (ret) - return ret; ret = smu_send_smc_msg_with_param(smu, drv2smu ? SMU_MSG_TransferTableDram2Smu : SMU_MSG_TransferTableSmu2Dram, @@ -386,8 +546,10 @@ int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int if (ret) return ret; - if (!drv2smu) - memcpy(table_data, table->cpu_addr, table->size); + if (!drv2smu) { + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table_data, table->cpu_addr, table_size); + } return ret; } @@ -396,25 +558,46 @@ bool is_support_sw_smu(struct amdgpu_device *adev) { if (adev->asic_type == CHIP_VEGA20) return (amdgpu_dpm == 2) ? true : false; - else if (adev->asic_type >= CHIP_NAVI10) - return true; - else + else if (adev->asic_type >= CHIP_ARCTURUS) { + if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) + return false; + else + return true; + } else + return false; +} + +bool is_support_sw_smu_xgmi(struct amdgpu_device *adev) +{ + if (!is_support_sw_smu(adev)) return false; + + if (adev->asic_type == CHIP_VEGA20) + return true; + + return false; } int smu_sys_get_pp_table(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; + uint32_t powerplay_table_size; if (!smu_table->power_play_table && !smu_table->hardcode_pptable) return -EINVAL; + mutex_lock(&smu->mutex); + if (smu_table->hardcode_pptable) *table = smu_table->hardcode_pptable; else *table = smu_table->power_play_table; - return smu_table->power_play_table_size; + powerplay_table_size = smu_table->power_play_table_size; + + mutex_unlock(&smu->mutex); + + return powerplay_table_size; } int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size) @@ -441,13 +624,18 @@ int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size) memcpy(smu_table->hardcode_pptable, buf, size); smu_table->power_play_table = smu_table->hardcode_pptable; smu_table->power_play_table_size = size; - mutex_unlock(&smu->mutex); + + /* + * Special hw_fini action(for Navi1x, the DPMs disablement will be + * skipped) may be needed for custom pptable uploading. + */ + smu->uploading_custom_pp_table = true; ret = smu_reset(smu); if (ret) pr_info("smu reset failed, ret = %d\n", ret); - return ret; + smu->uploading_custom_pp_table = false; failed: mutex_unlock(&smu->mutex); @@ -480,13 +668,19 @@ int smu_feature_init_dpm(struct smu_context *smu) return ret; } + int smu_feature_is_enabled(struct smu_context *smu, enum smu_feature_mask mask) { struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_id; + int feature_id; int ret = 0; + if (smu->is_apu) + return 1; + feature_id = smu_feature_get_index(smu, mask); + if (feature_id < 0) + return 0; WARN_ON(feature_id > feature->feature_num); @@ -501,36 +695,28 @@ int smu_feature_set_enabled(struct smu_context *smu, enum smu_feature_mask mask, bool enable) { struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_id; - int ret = 0; + int feature_id; feature_id = smu_feature_get_index(smu, mask); + if (feature_id < 0) + return -EINVAL; WARN_ON(feature_id > feature->feature_num); - mutex_lock(&feature->mutex); - ret = smu_feature_update_enable_state(smu, feature_id, enable); - if (ret) - goto failed; - - if (enable) - test_and_set_bit(feature_id, feature->enabled); - else - test_and_clear_bit(feature_id, feature->enabled); - -failed: - mutex_unlock(&feature->mutex); - - return ret; + return smu_feature_update_enable_state(smu, + 1ULL << feature_id, + enable); } int smu_feature_is_supported(struct smu_context *smu, enum smu_feature_mask mask) { struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_id; + int feature_id; int ret = 0; feature_id = smu_feature_get_index(smu, mask); + if (feature_id < 0) + return 0; WARN_ON(feature_id > feature->feature_num); @@ -546,10 +732,12 @@ int smu_feature_set_supported(struct smu_context *smu, bool enable) { struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_id; + int feature_id; int ret = 0; feature_id = smu_feature_get_index(smu, mask); + if (feature_id < 0) + return -EINVAL; WARN_ON(feature_id > feature->feature_num); @@ -567,12 +755,27 @@ static int smu_set_funcs(struct amdgpu_device *adev) { struct smu_context *smu = &adev->smu; + if (adev->pm.pp_feature & PP_OVERDRIVE_MASK) + smu->od_enabled = true; + switch (adev->asic_type) { case CHIP_VEGA20: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; + vega20_set_ppt_funcs(smu); + break; case CHIP_NAVI10: - if (adev->pm.pp_feature & PP_OVERDRIVE_MASK) - smu->od_enabled = true; - smu_v11_0_set_smu_funcs(smu); + case CHIP_NAVI14: + case CHIP_NAVI12: + navi10_set_ppt_funcs(smu); + break; + case CHIP_ARCTURUS: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; + arcturus_set_ppt_funcs(smu); + /* OD is not supported on Arcturus */ + smu->od_enabled =false; + break; + case CHIP_RENOIR: + renoir_set_ppt_funcs(smu); break; default: return -EINVAL; @@ -588,6 +791,7 @@ static int smu_early_init(void *handle) smu->adev = adev; smu->pm_enabled = !!amdgpu_dpm; + smu->is_apu = false; mutex_init(&smu->mutex); return smu_set_funcs(adev); @@ -600,11 +804,11 @@ static int smu_late_init(void *handle) if (!smu->pm_enabled) return 0; - mutex_lock(&smu->mutex); + smu_handle_task(&adev->smu, smu->smu_dpm.dpm_level, - AMD_PP_TASK_COMPLETE_INIT); - mutex_unlock(&smu->mutex); + AMD_PP_TASK_COMPLETE_INIT, + false); return 0; } @@ -694,6 +898,9 @@ static int smu_sw_init(void *handle) smu->smu_baco.state = SMU_BACO_STATE_EXIT; smu->smu_baco.platform_support = false; + mutex_init(&smu->sensor_lock); + mutex_init(&smu->metrics_lock); + smu->watermarks_bitmap = 0; smu->power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; smu->default_power_profile_mode = PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT; @@ -768,37 +975,56 @@ static int smu_init_fb_allocations(struct smu_context *smu) struct amdgpu_device *adev = smu->adev; struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; - uint32_t table_count = smu_table->table_count; - uint32_t i = 0; - int32_t ret = 0; - - if (table_count <= 0) - return -EINVAL; + struct smu_table *driver_table = &(smu_table->driver_table); + uint32_t max_table_size = 0; + int ret, i; - for (i = 0 ; i < table_count; i++) { - if (tables[i].size == 0) - continue; + /* VRAM allocation for tool table */ + if (tables[SMU_TABLE_PMSTATUSLOG].size) { ret = amdgpu_bo_create_kernel(adev, - tables[i].size, - tables[i].align, - tables[i].domain, - &tables[i].bo, - &tables[i].mc_address, - &tables[i].cpu_addr); - if (ret) - goto failed; + tables[SMU_TABLE_PMSTATUSLOG].size, + tables[SMU_TABLE_PMSTATUSLOG].align, + tables[SMU_TABLE_PMSTATUSLOG].domain, + &tables[SMU_TABLE_PMSTATUSLOG].bo, + &tables[SMU_TABLE_PMSTATUSLOG].mc_address, + &tables[SMU_TABLE_PMSTATUSLOG].cpu_addr); + if (ret) { + pr_err("VRAM allocation for tool table failed!\n"); + return ret; + } } - return 0; -failed: - for (; i > 0; i--) { + /* VRAM allocation for driver table */ + for (i = 0; i < SMU_TABLE_COUNT; i++) { if (tables[i].size == 0) continue; - amdgpu_bo_free_kernel(&tables[i].bo, - &tables[i].mc_address, - &tables[i].cpu_addr); + if (i == SMU_TABLE_PMSTATUSLOG) + continue; + + if (max_table_size < tables[i].size) + max_table_size = tables[i].size; + } + + driver_table->size = max_table_size; + driver_table->align = PAGE_SIZE; + driver_table->domain = AMDGPU_GEM_DOMAIN_VRAM; + + ret = amdgpu_bo_create_kernel(adev, + driver_table->size, + driver_table->align, + driver_table->domain, + &driver_table->bo, + &driver_table->mc_address, + &driver_table->cpu_addr); + if (ret) { + pr_err("VRAM allocation for driver table failed!\n"); + if (tables[SMU_TABLE_PMSTATUSLOG].mc_address) + amdgpu_bo_free_kernel(&tables[SMU_TABLE_PMSTATUSLOG].bo, + &tables[SMU_TABLE_PMSTATUSLOG].mc_address, + &tables[SMU_TABLE_PMSTATUSLOG].cpu_addr); } + return ret; } @@ -806,62 +1032,21 @@ static int smu_fini_fb_allocations(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = smu_table->tables; - uint32_t table_count = smu_table->table_count; - uint32_t i = 0; + struct smu_table *driver_table = &(smu_table->driver_table); - if (table_count == 0 || tables == NULL) + if (!tables) return 0; - for (i = 0 ; i < table_count; i++) { - if (tables[i].size == 0) - continue; - amdgpu_bo_free_kernel(&tables[i].bo, - &tables[i].mc_address, - &tables[i].cpu_addr); - } - - return 0; -} + if (tables[SMU_TABLE_PMSTATUSLOG].mc_address) + amdgpu_bo_free_kernel(&tables[SMU_TABLE_PMSTATUSLOG].bo, + &tables[SMU_TABLE_PMSTATUSLOG].mc_address, + &tables[SMU_TABLE_PMSTATUSLOG].cpu_addr); -static int smu_override_pcie_parameters(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t pcie_gen = 0, pcie_width = 0, smu_pcie_arg; - int ret; + amdgpu_bo_free_kernel(&driver_table->bo, + &driver_table->mc_address, + &driver_table->cpu_addr); - if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) - pcie_gen = 3; - else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) - pcie_gen = 2; - else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) - pcie_gen = 1; - else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1) - pcie_gen = 0; - - /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1 - * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4 - * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32 - */ - if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16) - pcie_width = 6; - else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12) - pcie_width = 5; - else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8) - pcie_width = 4; - else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4) - pcie_width = 3; - else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2) - pcie_width = 2; - else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1) - pcie_width = 1; - - smu_pcie_arg = (1 << 16) | (pcie_gen << 8) | pcie_width; - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_OverridePcieParameters, - smu_pcie_arg); - if (ret) - pr_err("[%s] Attempt to override pcie params failed!\n", __func__); - return ret; + return 0; } static int smu_smc_table_hw_init(struct smu_context *smu, @@ -875,9 +1060,11 @@ static int smu_smc_table_hw_init(struct smu_context *smu, return 0; } - ret = smu_init_display_count(smu, 0); - if (ret) - return ret; + if (adev->asic_type != CHIP_ARCTURUS) { + ret = smu_init_display_count(smu, 0); + if (ret) + return ret; + } if (initialize) { /* get boot_values from vbios to set revision, gfxclk, and etc. */ @@ -926,42 +1113,62 @@ static int smu_smc_table_hw_init(struct smu_context *smu, return ret; } - /* - * Copy pptable bo in the vram to smc with SMU MSGs such as - * SetDriverDramAddr and TransferTableDram2Smu. - */ - ret = smu_write_pptable(smu); - if (ret) - return ret; - - /* issue RunAfllBtc msg */ - ret = smu_run_afll_btc(smu); - if (ret) - return ret; + /* smu_dump_pptable(smu); */ + if (!amdgpu_sriov_vf(adev)) { + ret = smu_set_driver_table_location(smu); + if (ret) + return ret; - ret = smu_feature_set_allowed_mask(smu); - if (ret) - return ret; + /* + * Copy pptable bo in the vram to smc with SMU MSGs such as + * SetDriverDramAddr and TransferTableDram2Smu. + */ + ret = smu_write_pptable(smu); + if (ret) + return ret; - ret = smu_system_features_control(smu, true); - if (ret) - return ret; + /* issue Run*Btc msg */ + ret = smu_run_btc(smu); + if (ret) + return ret; + ret = smu_feature_set_allowed_mask(smu); + if (ret) + return ret; - ret = smu_override_pcie_parameters(smu); - if (ret) - return ret; + ret = smu_system_features_control(smu, true); + if (ret) + return ret; - ret = smu_notify_display_change(smu); - if (ret) - return ret; + if (adev->asic_type == CHIP_NAVI10) { + if ((adev->pdev->device == 0x731f && (adev->pdev->revision == 0xc2 || + adev->pdev->revision == 0xc3 || + adev->pdev->revision == 0xca || + adev->pdev->revision == 0xcb)) || + (adev->pdev->device == 0x66af && (adev->pdev->revision == 0xf3 || + adev->pdev->revision == 0xf4 || + adev->pdev->revision == 0xf5 || + adev->pdev->revision == 0xf6))) { + ret = smu_disable_umc_cdr_12gbps_workaround(smu); + if (ret) { + pr_err("Workaround failed to disable UMC CDR feature on 12Gbps SKU!\n"); + return ret; + } + } + } + } + if (adev->asic_type != CHIP_ARCTURUS) { + ret = smu_notify_display_change(smu); + if (ret) + return ret; - /* - * Set min deep sleep dce fclk with bootup value from vbios via - * SetMinDeepSleepDcefclk MSG. - */ - ret = smu_set_min_dcef_deep_sleep(smu); - if (ret) - return ret; + /* + * Set min deep sleep dce fclk with bootup value from vbios via + * SetMinDeepSleepDcefclk MSG. + */ + ret = smu_set_min_dcef_deep_sleep(smu); + if (ret) + return ret; + } /* * Set initialized values (get from vbios) to dpm tables context such as @@ -969,7 +1176,7 @@ static int smu_smc_table_hw_init(struct smu_context *smu, * type of clks. */ if (initialize) { - ret = smu_populate_smc_pptable(smu); + ret = smu_populate_smc_tables(smu); if (ret) return ret; @@ -978,6 +1185,12 @@ static int smu_smc_table_hw_init(struct smu_context *smu, return ret; } + if (adev->asic_type != CHIP_ARCTURUS) { + ret = smu_override_pcie_parameters(smu); + if (ret) + return ret; + } + ret = smu_set_default_od_settings(smu, initialize); if (ret) return ret; @@ -987,7 +1200,7 @@ static int smu_smc_table_hw_init(struct smu_context *smu, if (ret) return ret; - ret = smu_get_power_limit(smu, &smu->default_power_limit, false); + ret = smu_get_power_limit(smu, &smu->default_power_limit, false, false); if (ret) return ret; } @@ -995,8 +1208,9 @@ static int smu_smc_table_hw_init(struct smu_context *smu, /* * Set PMSTATUSLOG table bo address with SetToolsDramAddr MSG for tools. */ - ret = smu_set_tool_table_location(smu); - + if (!amdgpu_sriov_vf(adev)) { + ret = smu_set_tool_table_location(smu); + } if (!smu_is_dpm_running(smu)) pr_info("dpm has been disabled\n"); @@ -1052,10 +1266,9 @@ static int smu_free_memory_pool(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *memory_pool = &smu_table->memory_pool; - int ret = 0; if (memory_pool->size == SMU_MEMORY_POOL_SIZE_ZERO) - return ret; + return 0; amdgpu_bo_free_kernel(&memory_pool->bo, &memory_pool->mc_address, @@ -1063,6 +1276,30 @@ static int smu_free_memory_pool(struct smu_context *smu) memset(memory_pool, 0, sizeof(struct smu_table)); + return 0; +} + +static int smu_start_smc_engine(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (adev->firmware.load_type != AMDGPU_FW_LOAD_PSP) { + if (adev->asic_type < CHIP_NAVI10) { + if (smu->ppt_funcs->load_microcode) { + ret = smu->ppt_funcs->load_microcode(smu); + if (ret) + return ret; + } + } + } + + if (smu->ppt_funcs->check_fw_status) { + ret = smu->ppt_funcs->check_fw_status(smu); + if (ret) + pr_err("SMC is not ready\n"); + } + return ret; } @@ -1072,14 +1309,25 @@ static int smu_hw_init(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = &adev->smu; - if (adev->firmware.load_type == AMDGPU_FW_LOAD_PSP) { - ret = smu_check_fw_status(smu); - if (ret) { - pr_err("SMC firmware status is not correct\n"); - return ret; - } + ret = smu_start_smc_engine(smu); + if (ret) { + pr_err("SMU is not ready yet!\n"); + return ret; + } + + if (smu->is_apu) { + smu_powergate_sdma(&adev->smu, false); + smu_powergate_vcn(&adev->smu, false); + smu_powergate_jpeg(&adev->smu, false); + smu_set_gfx_cgpg(&adev->smu, true); } + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + + if (!smu->pm_enabled) + return 0; + ret = smu_feature_init_dpm(smu); if (ret) goto failed; @@ -1117,6 +1365,11 @@ failed: return ret; } +static int smu_stop_dpms(struct smu_context *smu) +{ + return smu_system_features_control(smu, false); +} + static int smu_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -1124,6 +1377,47 @@ static int smu_hw_fini(void *handle) struct smu_table_context *table_context = &smu->smu_table; int ret = 0; + if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + + if (smu->is_apu) { + smu_powergate_sdma(&adev->smu, true); + smu_powergate_vcn(&adev->smu, true); + smu_powergate_jpeg(&adev->smu, true); + } + + if (!smu->pm_enabled) + return 0; + + if (!amdgpu_sriov_vf(adev)){ + ret = smu_stop_thermal_control(smu); + if (ret) { + pr_warn("Fail to stop thermal control!\n"); + return ret; + } + + /* + * For custom pptable uploading, skip the DPM features + * disable process on Navi1x ASICs. + * - As the gfx related features are under control of + * RLC on those ASICs. RLC reinitialization will be + * needed to reenable them. That will cost much more + * efforts. + * + * - SMU firmware can handle the DPM reenablement + * properly. + */ + if (!smu->uploading_custom_pp_table || + !((adev->asic_type >= CHIP_NAVI10) && + (adev->asic_type <= CHIP_NAVI12))) { + ret = smu_stop_dpms(smu); + if (ret) { + pr_warn("Fail to stop Dpms!\n"); + return ret; + } + } + } + kfree(table_context->driver_pptable); table_context->driver_pptable = NULL; @@ -1165,13 +1459,19 @@ static int smu_suspend(void *handle) int ret; struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = &adev->smu; - bool baco_feature_is_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT); + bool baco_feature_is_enabled = false; + + if (!smu->pm_enabled) + return 0; + + if(!smu->is_apu) + baco_feature_is_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT); ret = smu_system_features_control(smu, false); if (ret) return ret; - if (adev->in_gpu_reset && baco_feature_is_enabled) { + if (baco_feature_is_enabled) { ret = smu_feature_set_enabled(smu, SMU_FEATURE_BACO_BIT, true); if (ret) { pr_warn("set BACO feature enabled failed, return %d\n", ret); @@ -1184,6 +1484,8 @@ static int smu_suspend(void *handle) if (adev->asic_type >= CHIP_NAVI10 && adev->gfx.rlc.funcs->stop) adev->gfx.rlc.funcs->stop(adev); + if (smu->is_apu) + smu_set_gfx_cgpg(&adev->smu, false); return 0; } @@ -1194,9 +1496,19 @@ static int smu_resume(void *handle) struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = &adev->smu; + if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) + return 0; + + if (!smu->pm_enabled) + return 0; + pr_info("SMU is resuming...\n"); - mutex_lock(&smu->mutex); + ret = smu_start_smc_engine(smu); + if (ret) { + pr_err("SMU is not ready yet!\n"); + goto failed; + } ret = smu_smc_table_hw_init(smu, false); if (ret) @@ -1206,13 +1518,16 @@ static int smu_resume(void *handle) if (ret) goto failed; - mutex_unlock(&smu->mutex); + if (smu->is_apu) + smu_set_gfx_cgpg(&adev->smu, true); + + smu->disable_uclk_switch = 0; pr_info("SMU is resumed successfully!\n"); return 0; + failed: - mutex_unlock(&smu->mutex); return ret; } @@ -1230,8 +1545,9 @@ int smu_display_configuration_change(struct smu_context *smu, mutex_lock(&smu->mutex); - smu_set_deep_sleep_dcefclk(smu, - display_config->min_dcef_deep_sleep_set_clk / 100); + if (smu->ppt_funcs->set_deep_sleep_dcefclk) + smu->ppt_funcs->set_deep_sleep_dcefclk(smu, + display_config->min_dcef_deep_sleep_set_clk / 100); for (index = 0; index < display_config->num_path_including_non_display; index++) { if (display_config->displays[index].controller_id != 0) @@ -1350,7 +1666,8 @@ static int smu_enable_umd_pstate(void *handle, struct smu_context *smu = (struct smu_context*)(handle); struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - if (!smu->pm_enabled || !smu_dpm_ctx->dpm_context) + + if (!smu->is_apu && (!smu->pm_enabled || !smu_dpm_ctx->dpm_context)) return -EINVAL; if (!(smu_dpm_ctx->dpm_level & profile_mode_mask)) { @@ -1383,43 +1700,6 @@ static int smu_enable_umd_pstate(void *handle, return 0; } -static int smu_default_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) -{ - int ret = 0; - uint32_t sclk_mask, mclk_mask, soc_mask; - - switch (level) { - case AMD_DPM_FORCED_LEVEL_HIGH: - ret = smu_force_dpm_limit_value(smu, true); - break; - case AMD_DPM_FORCED_LEVEL_LOW: - ret = smu_force_dpm_limit_value(smu, false); - break; - case AMD_DPM_FORCED_LEVEL_AUTO: - case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: - ret = smu_unforce_dpm_levels(smu); - break; - case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: - case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: - case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - ret = smu_get_profiling_clk_mask(smu, level, - &sclk_mask, - &mclk_mask, - &soc_mask); - if (ret) - return ret; - smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask); - smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask); - smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask); - break; - case AMD_DPM_FORCED_LEVEL_MANUAL: - case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: - default: - break; - } - return ret; -} - int smu_adjust_power_state_dynamic(struct smu_context *smu, enum amd_dpm_forced_level level, bool skip_display_settings) @@ -1431,6 +1711,7 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, if (!smu->pm_enabled) return -EINVAL; + if (!skip_display_settings) { ret = smu_display_config_changed(smu); if (ret) { @@ -1439,8 +1720,6 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, } } - if (!smu->pm_enabled) - return -EINVAL; ret = smu_apply_clocks_adjust_rules(smu); if (ret) { pr_err("Failed to apply clocks adjust rules!"); @@ -1448,7 +1727,7 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, } if (!skip_display_settings) { - ret = smu_notify_smc_dispaly_config(smu); + ret = smu_notify_smc_display_config(smu); if (ret) { pr_err("Failed to notify smc display config!"); return ret; @@ -1458,10 +1737,12 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, if (smu_dpm_ctx->dpm_level != level) { ret = smu_asic_set_performance_level(smu, level); if (ret) { - ret = smu_default_set_performance_level(smu, level); + pr_err("Failed to set performance level!"); + return ret; } - if (!ret) - smu_dpm_ctx->dpm_level = level; + + /* update the saved copy */ + smu_dpm_ctx->dpm_level = level; } if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { @@ -1470,7 +1751,7 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, workload = smu->workload_setting[index]; if (smu->power_profile_mode != workload) - smu_set_power_profile_mode(smu, &workload, 0); + smu_set_power_profile_mode(smu, &workload, 0, false); } return ret; @@ -1478,18 +1759,22 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, int smu_handle_task(struct smu_context *smu, enum amd_dpm_forced_level level, - enum amd_pp_task task_id) + enum amd_pp_task task_id, + bool lock_needed) { int ret = 0; + if (lock_needed) + mutex_lock(&smu->mutex); + switch (task_id) { case AMD_PP_TASK_DISPLAY_CONFIG_CHANGE: ret = smu_pre_display_config_changed(smu); if (ret) - return ret; + goto out; ret = smu_set_cpu_power_state(smu); if (ret) - return ret; + goto out; ret = smu_adjust_power_state_dynamic(smu, level, false); break; case AMD_PP_TASK_COMPLETE_INIT: @@ -1500,15 +1785,55 @@ int smu_handle_task(struct smu_context *smu, break; } +out: + if (lock_needed) + mutex_unlock(&smu->mutex); + return ret; } +int smu_switch_power_profile(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE type, + bool en) +{ + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + long workload; + uint32_t index; + + if (!smu->pm_enabled) + return -EINVAL; + + if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) + return -EINVAL; + + mutex_lock(&smu->mutex); + + if (!en) { + smu->workload_mask &= ~(1 << smu->workload_prority[type]); + index = fls(smu->workload_mask); + index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; + workload = smu->workload_setting[index]; + } else { + smu->workload_mask |= (1 << smu->workload_prority[type]); + index = fls(smu->workload_mask); + index = index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; + workload = smu->workload_setting[index]; + } + + if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) + smu_set_power_profile_mode(smu, &workload, 0, false); + + mutex_unlock(&smu->mutex); + + return 0; +} + enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu) { struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); enum amd_dpm_forced_level level; - if (!smu_dpm_ctx->dpm_context) + if (!smu->is_apu && !smu_dpm_ctx->dpm_context) return -EINVAL; mutex_lock(&(smu->mutex)); @@ -1520,27 +1845,24 @@ enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu) int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) { - int ret = 0; - int i; struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + int ret = 0; - if (!smu_dpm_ctx->dpm_context) + if (!smu->is_apu && !smu_dpm_ctx->dpm_context) return -EINVAL; - for (i = 0; i < smu->adev->num_ip_blocks; i++) { - if (smu->adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) - break; - } + mutex_lock(&smu->mutex); + ret = smu_enable_umd_pstate(smu, &level); + if (ret) { + mutex_unlock(&smu->mutex); + return ret; + } - smu->adev->ip_blocks[i].version->funcs->enable_umd_pstate(smu, &level); ret = smu_handle_task(smu, level, - AMD_PP_TASK_READJUST_POWER_STATE); - if (ret) - return ret; + AMD_PP_TASK_READJUST_POWER_STATE, + false); - mutex_lock(&smu->mutex); - smu_dpm_ctx->dpm_level = level; mutex_unlock(&smu->mutex); return ret; @@ -1557,6 +1879,142 @@ int smu_set_display_count(struct smu_context *smu, uint32_t count) return ret; } +int smu_force_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t mask, + bool lock_needed) +{ + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + int ret = 0; + + if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { + pr_debug("force clock level is for dpm manual mode only.\n"); + return -EINVAL; + } + + if (lock_needed) + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels) + ret = smu->ppt_funcs->force_clk_levels(smu, clk_type, mask); + + if (lock_needed) + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state) +{ + uint16_t msg; + int ret; + + /* + * The SMC is not fully ready. That may be + * expected as the IP may be masked. + * So, just return without error. + */ + if (!smu->pm_enabled) + return 0; + + mutex_lock(&smu->mutex); + + switch (mp1_state) { + case PP_MP1_STATE_SHUTDOWN: + msg = SMU_MSG_PrepareMp1ForShutdown; + break; + case PP_MP1_STATE_UNLOAD: + msg = SMU_MSG_PrepareMp1ForUnload; + break; + case PP_MP1_STATE_RESET: + msg = SMU_MSG_PrepareMp1ForReset; + break; + case PP_MP1_STATE_NONE: + default: + mutex_unlock(&smu->mutex); + return 0; + } + + /* some asics may not support those messages */ + if (smu_msg_get_index(smu, msg) < 0) { + mutex_unlock(&smu->mutex); + return 0; + } + + ret = smu_send_smc_msg(smu, msg); + if (ret) + pr_err("[PrepareMp1] Failed!\n"); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state) +{ + int ret = 0; + + /* + * The SMC is not fully ready. That may be + * expected as the IP may be masked. + * So, just return without error. + */ + if (!smu->pm_enabled) + return 0; + + if (!smu->ppt_funcs || !smu->ppt_funcs->set_df_cstate) + return 0; + + mutex_lock(&smu->mutex); + + ret = smu->ppt_funcs->set_df_cstate(smu, state); + if (ret) + pr_err("[SetDfCstate] failed!\n"); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_write_watermarks_table(struct smu_context *smu) +{ + void *watermarks_table = smu->smu_table.watermarks_table; + + if (!watermarks_table) + return -EINVAL; + + return smu_update_table(smu, + SMU_TABLE_WATERMARKS, + 0, + watermarks_table, + true); +} + +int smu_set_watermarks_for_clock_ranges(struct smu_context *smu, + struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges) +{ + void *table = smu->smu_table.watermarks_table; + + if (!table) + return -EINVAL; + + mutex_lock(&smu->mutex); + + if (!smu->disable_watermark && + smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && + smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + smu_set_watermarks_table(smu, table, clock_ranges); + smu->watermarks_bitmap |= WATERMARKS_EXIST; + smu->watermarks_bitmap &= ~WATERMARKS_LOADED; + } + + mutex_unlock(&smu->mutex); + + return 0; +} + const struct amd_ip_funcs smu_ip_funcs = { .name = "smu", .early_init = smu_early_init, @@ -1584,3 +2042,587 @@ const struct amdgpu_ip_block_version smu_v11_0_ip_block = .rev = 0, .funcs = &smu_ip_funcs, }; + +const struct amdgpu_ip_block_version smu_v12_0_ip_block = +{ + .type = AMD_IP_BLOCK_TYPE_SMC, + .major = 12, + .minor = 0, + .rev = 0, + .funcs = &smu_ip_funcs, +}; + +int smu_load_microcode(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->load_microcode) + ret = smu->ppt_funcs->load_microcode(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_check_fw_status(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->check_fw_status) + ret = smu->ppt_funcs->check_fw_status(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_gfx_cgpg) + ret = smu->ppt_funcs->set_gfx_cgpg(smu, enabled); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_fan_speed_rpm) + ret = smu->ppt_funcs->set_fan_speed_rpm(smu, speed); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_power_limit(struct smu_context *smu, + uint32_t *limit, + bool def, + bool lock_needed) +{ + int ret = 0; + + if (lock_needed) + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_power_limit) + ret = smu->ppt_funcs->get_power_limit(smu, limit, def); + + if (lock_needed) + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_power_limit(struct smu_context *smu, uint32_t limit) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_power_limit) + ret = smu->ppt_funcs->set_power_limit(smu, limit); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->print_clk_levels) + ret = smu->ppt_funcs->print_clk_levels(smu, clk_type, buf); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_od_percentage(struct smu_context *smu, enum smu_clk_type type) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_od_percentage) + ret = smu->ppt_funcs->get_od_percentage(smu, type); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_od_percentage(struct smu_context *smu, enum smu_clk_type type, uint32_t value) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_od_percentage) + ret = smu->ppt_funcs->set_od_percentage(smu, type, value); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_od_edit_dpm_table(struct smu_context *smu, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->od_edit_dpm_table) + ret = smu->ppt_funcs->od_edit_dpm_table(smu, type, input, size); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->read_sensor) + ret = smu->ppt_funcs->read_sensor(smu, sensor, data, size); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_power_profile_mode(struct smu_context *smu, char *buf) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_power_profile_mode) + ret = smu->ppt_funcs->get_power_profile_mode(smu, buf); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_power_profile_mode(struct smu_context *smu, + long *param, + uint32_t param_size, + bool lock_needed) +{ + int ret = 0; + + if (lock_needed) + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_power_profile_mode) + ret = smu->ppt_funcs->set_power_profile_mode(smu, param, param_size); + + if (lock_needed) + mutex_unlock(&smu->mutex); + + return ret; +} + + +int smu_get_fan_control_mode(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_fan_control_mode) + ret = smu->ppt_funcs->get_fan_control_mode(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_fan_control_mode(struct smu_context *smu, int value) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_fan_control_mode) + ret = smu->ppt_funcs->set_fan_control_mode(smu, value); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_fan_speed_percent) + ret = smu->ppt_funcs->get_fan_speed_percent(smu, speed); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_fan_speed_percent) + ret = smu->ppt_funcs->set_fan_speed_percent(smu, speed); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_fan_speed_rpm(struct smu_context *smu, uint32_t *speed) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_fan_speed_rpm) + ret = smu->ppt_funcs->get_fan_speed_rpm(smu, speed); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_deep_sleep_dcefclk(struct smu_context *smu, int clk) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_deep_sleep_dcefclk) + ret = smu->ppt_funcs->set_deep_sleep_dcefclk(smu, clk); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_active_display_count(struct smu_context *smu, uint32_t count) +{ + int ret = 0; + + if (smu->ppt_funcs->set_active_display_count) + ret = smu->ppt_funcs->set_active_display_count(smu, count); + + return ret; +} + +int smu_get_clock_by_type(struct smu_context *smu, + enum amd_pp_clock_type type, + struct amd_pp_clocks *clocks) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_clock_by_type) + ret = smu->ppt_funcs->get_clock_by_type(smu, type, clocks); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_max_high_clocks(struct smu_context *smu, + struct amd_pp_simple_clock_info *clocks) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_max_high_clocks) + ret = smu->ppt_funcs->get_max_high_clocks(smu, clocks); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_clock_by_type_with_latency(struct smu_context *smu, + enum smu_clk_type clk_type, + struct pp_clock_levels_with_latency *clocks) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_clock_by_type_with_latency) + ret = smu->ppt_funcs->get_clock_by_type_with_latency(smu, clk_type, clocks); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_clock_by_type_with_voltage(struct smu_context *smu, + enum amd_pp_clock_type type, + struct pp_clock_levels_with_voltage *clocks) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_clock_by_type_with_voltage) + ret = smu->ppt_funcs->get_clock_by_type_with_voltage(smu, type, clocks); + + mutex_unlock(&smu->mutex); + + return ret; +} + + +int smu_display_clock_voltage_request(struct smu_context *smu, + struct pp_display_clock_request *clock_req) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->display_clock_voltage_request) + ret = smu->ppt_funcs->display_clock_voltage_request(smu, clock_req); + + mutex_unlock(&smu->mutex); + + return ret; +} + + +int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disable_memory_clock_switch) +{ + int ret = -EINVAL; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->display_disable_memory_clock_switch) + ret = smu->ppt_funcs->display_disable_memory_clock_switch(smu, disable_memory_clock_switch); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_notify_smu_enable_pwe(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->notify_smu_enable_pwe) + ret = smu->ppt_funcs->notify_smu_enable_pwe(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_xgmi_pstate(struct smu_context *smu, + uint32_t pstate) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_xgmi_pstate) + ret = smu->ppt_funcs->set_xgmi_pstate(smu, pstate); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_set_azalia_d3_pme(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->set_azalia_d3_pme) + ret = smu->ppt_funcs->set_azalia_d3_pme(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +bool smu_baco_is_support(struct smu_context *smu) +{ + bool ret = false; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) + ret = smu->ppt_funcs->baco_is_support(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state) +{ + if (smu->ppt_funcs->baco_get_state) + return -EINVAL; + + mutex_lock(&smu->mutex); + *state = smu->ppt_funcs->baco_get_state(smu); + mutex_unlock(&smu->mutex); + + return 0; +} + +int smu_baco_enter(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_enter) + ret = smu->ppt_funcs->baco_enter(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_baco_exit(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->baco_exit) + ret = smu->ppt_funcs->baco_exit(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_mode2_reset(struct smu_context *smu) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->mode2_reset) + ret = smu->ppt_funcs->mode2_reset(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_max_sustainable_clocks_by_dc(struct smu_context *smu, + struct pp_smu_nv_clock_table *max_clocks) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_max_sustainable_clocks_by_dc) + ret = smu->ppt_funcs->get_max_sustainable_clocks_by_dc(smu, max_clocks); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_get_uclk_dpm_states(struct smu_context *smu, + unsigned int *clock_values_in_khz, + unsigned int *num_states) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_uclk_dpm_states) + ret = smu->ppt_funcs->get_uclk_dpm_states(smu, clock_values_in_khz, num_states); + + mutex_unlock(&smu->mutex); + + return ret; +} + +enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu) +{ + enum amd_pm_state_type pm_state = POWER_STATE_TYPE_DEFAULT; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_current_power_state) + pm_state = smu->ppt_funcs->get_current_power_state(smu); + + mutex_unlock(&smu->mutex); + + return pm_state; +} + +int smu_get_dpm_clock_table(struct smu_context *smu, + struct dpm_clocks *clock_table) +{ + int ret = 0; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->get_dpm_clock_table) + ret = smu->ppt_funcs->get_dpm_clock_table(smu, clock_table); + + mutex_unlock(&smu->mutex); + + return ret; +} + +uint32_t smu_get_pptable_power_limit(struct smu_context *smu) +{ + uint32_t ret = 0; + + if (smu->ppt_funcs->get_pptable_power_limit) + ret = smu->ppt_funcs->get_pptable_power_limit(smu); + + return ret; +} + +int smu_send_smc_msg(struct smu_context *smu, + enum smu_message_type msg) +{ + int ret; + + ret = smu_send_smc_msg_with_param(smu, msg, 0); + return ret; +} diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c new file mode 100644 index 000000000000..14ba6aa876e2 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c @@ -0,0 +1,2315 @@ +/* + * Copyright 2019 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 "pp_debug.h" +#include <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_internal.h" +#include "atomfirmware.h" +#include "amdgpu_atomfirmware.h" +#include "smu_v11_0.h" +#include "smu11_driver_if_arcturus.h" +#include "soc15_common.h" +#include "atom.h" +#include "power_state.h" +#include "arcturus_ppt.h" +#include "smu_v11_0_pptable.h" +#include "arcturus_ppsmc.h" +#include "nbio/nbio_7_4_sh_mask.h" +#include "amdgpu_xgmi.h" +#include <linux/i2c.h> +#include <linux/pci.h> +#include "amdgpu_ras.h" + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_ras, eeprom_control.eeprom_accessor))->adev + +#define CTF_OFFSET_EDGE 5 +#define CTF_OFFSET_HOTSPOT 5 +#define CTF_OFFSET_HBM 5 + +#define MSG_MAP(msg, index) \ + [SMU_MSG_##msg] = {1, (index)} +#define ARCTURUS_FEA_MAP(smu_feature, arcturus_feature) \ + [smu_feature] = {1, (arcturus_feature)} + +#define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF +#define SMU_FEATURES_LOW_SHIFT 0 +#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 +#define SMU_FEATURES_HIGH_SHIFT 32 + +#define SMC_DPM_FEATURE ( \ + FEATURE_DPM_PREFETCHER_MASK | \ + FEATURE_DPM_GFXCLK_MASK | \ + FEATURE_DPM_UCLK_MASK | \ + FEATURE_DPM_SOCCLK_MASK | \ + FEATURE_DPM_MP0CLK_MASK | \ + FEATURE_DPM_FCLK_MASK | \ + FEATURE_DPM_XGMI_MASK) + +/* possible frequency drift (1Mhz) */ +#define EPSILON 1 + +static struct smu_11_0_cmn2aisc_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion), + MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow), + MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures), + MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures), + MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow), + MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh), + MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow), + MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow), + MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh), + MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu), + MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable), + MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable), + MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh), + MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow), + MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), + MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), + MSG_MAP(ArmD3, PPSMC_MSG_ArmD3), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq), + MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask), + MSG_MAP(SetDfSwitchType, PPSMC_MSG_SetDfSwitchType), + MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm), + MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit), + MSG_MAP(PowerUpVcn0, PPSMC_MSG_PowerUpVcn0), + MSG_MAP(PowerDownVcn0, PPSMC_MSG_PowerDownVcn0), + MSG_MAP(PowerUpVcn1, PPSMC_MSG_PowerUpVcn1), + MSG_MAP(PowerDownVcn1, PPSMC_MSG_PowerDownVcn1), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload), + MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset), + MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown), + MSG_MAP(SoftReset, PPSMC_MSG_SoftReset), + MSG_MAP(RunAfllBtc, PPSMC_MSG_RunAfllBtc), + MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc), + MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh), + MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow), + MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize), + MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData), + MSG_MAP(WaflTest, PPSMC_MSG_WaflTest), + MSG_MAP(SetXgmiMode, PPSMC_MSG_SetXgmiMode), + MSG_MAP(SetMemoryChannelEnable, PPSMC_MSG_SetMemoryChannelEnable), +}; + +static struct smu_11_0_cmn2aisc_mapping arcturus_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(GFXCLK, PPCLK_GFXCLK), + CLK_MAP(SCLK, PPCLK_GFXCLK), + CLK_MAP(SOCCLK, PPCLK_SOCCLK), + CLK_MAP(FCLK, PPCLK_FCLK), + CLK_MAP(UCLK, PPCLK_UCLK), + CLK_MAP(MCLK, PPCLK_UCLK), + CLK_MAP(DCLK, PPCLK_DCLK), + CLK_MAP(VCLK, PPCLK_VCLK), +}; + +static struct smu_11_0_cmn2aisc_mapping arcturus_feature_mask_map[SMU_FEATURE_COUNT] = { + FEA_MAP(DPM_PREFETCHER), + FEA_MAP(DPM_GFXCLK), + FEA_MAP(DPM_UCLK), + FEA_MAP(DPM_SOCCLK), + FEA_MAP(DPM_FCLK), + FEA_MAP(DPM_MP0CLK), + ARCTURUS_FEA_MAP(SMU_FEATURE_XGMI_BIT, FEATURE_DPM_XGMI_BIT), + FEA_MAP(DS_GFXCLK), + FEA_MAP(DS_SOCCLK), + FEA_MAP(DS_LCLK), + FEA_MAP(DS_FCLK), + FEA_MAP(DS_UCLK), + FEA_MAP(GFX_ULV), + ARCTURUS_FEA_MAP(SMU_FEATURE_VCN_PG_BIT, FEATURE_DPM_VCN_BIT), + FEA_MAP(RSMU_SMN_CG), + FEA_MAP(WAFL_CG), + FEA_MAP(PPT), + FEA_MAP(TDC), + FEA_MAP(APCC_PLUS), + FEA_MAP(VR0HOT), + FEA_MAP(VR1HOT), + FEA_MAP(FW_CTF), + FEA_MAP(FAN_CONTROL), + FEA_MAP(THERMAL), + FEA_MAP(OUT_OF_BAND_MONITOR), + FEA_MAP(TEMP_DEPENDENT_VMIN), +}; + +static struct smu_11_0_cmn2aisc_mapping arcturus_table_map[SMU_TABLE_COUNT] = { + TAB_MAP(PPTABLE), + TAB_MAP(AVFS), + TAB_MAP(AVFS_PSM_DEBUG), + TAB_MAP(AVFS_FUSE_OVERRIDE), + TAB_MAP(PMSTATUSLOG), + TAB_MAP(SMU_METRICS), + TAB_MAP(DRIVER_SMU_CONFIG), + TAB_MAP(OVERDRIVE), + TAB_MAP(I2C_COMMANDS), + TAB_MAP(ACTIVITY_MONITOR_COEFF), +}; + +static struct smu_11_0_cmn2aisc_mapping arcturus_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { + PWR_MAP(AC), + PWR_MAP(DC), +}; + +static struct smu_11_0_cmn2aisc_mapping arcturus_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_PPLIB_DEFAULT_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), +}; + +static int arcturus_get_smu_msg_index(struct smu_context *smc, uint32_t index) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_MSG_MAX_COUNT) + return -EINVAL; + + mapping = arcturus_message_map[index]; + if (!(mapping.valid_mapping)) + return -EINVAL; + + return mapping.map_to; +} + +static int arcturus_get_smu_clk_index(struct smu_context *smc, uint32_t index) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_CLK_COUNT) + return -EINVAL; + + mapping = arcturus_clk_map[index]; + if (!(mapping.valid_mapping)) { + pr_warn("Unsupported SMU clk: %d\n", index); + return -EINVAL; + } + + return mapping.map_to; +} + +static int arcturus_get_smu_feature_index(struct smu_context *smc, uint32_t index) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_FEATURE_COUNT) + return -EINVAL; + + mapping = arcturus_feature_mask_map[index]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } + + return mapping.map_to; +} + +static int arcturus_get_smu_table_index(struct smu_context *smc, uint32_t index) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_TABLE_COUNT) + return -EINVAL; + + mapping = arcturus_table_map[index]; + if (!(mapping.valid_mapping)) { + pr_warn("Unsupported SMU table: %d\n", index); + return -EINVAL; + } + + return mapping.map_to; +} + +static int arcturus_get_pwr_src_index(struct smu_context *smc, uint32_t index) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_POWER_SOURCE_COUNT) + return -EINVAL; + + mapping = arcturus_pwr_src_map[index]; + if (!(mapping.valid_mapping)) { + pr_warn("Unsupported SMU power source: %d\n", index); + return -EINVAL; + } + + return mapping.map_to; +} + + +static int arcturus_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile) +{ + struct smu_11_0_cmn2aisc_mapping mapping; + + if (profile > PP_SMC_POWER_PROFILE_CUSTOM) + return -EINVAL; + + mapping = arcturus_workload_map[profile]; + if (!(mapping.valid_mapping)) + return -EINVAL; + + return mapping.map_to; +} + +static int arcturus_tables_init(struct smu_context *smu, struct smu_table *tables) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + SMU_TABLE_INIT(tables, SMU_TABLE_ACTIVITY_MONITOR_COEFF, + sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE, + AMDGPU_GEM_DOMAIN_VRAM); + + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + if (!smu_table->metrics_table) + return -ENOMEM; + smu_table->metrics_time = 0; + + return 0; +} + +static int arcturus_allocate_dpm_context(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + if (smu_dpm->dpm_context) + return -EINVAL; + + smu_dpm->dpm_context = kzalloc(sizeof(struct arcturus_dpm_table), + GFP_KERNEL); + if (!smu_dpm->dpm_context) + return -ENOMEM; + + if (smu_dpm->golden_dpm_context) + return -EINVAL; + + smu_dpm->golden_dpm_context = kzalloc(sizeof(struct arcturus_dpm_table), + GFP_KERNEL); + if (!smu_dpm->golden_dpm_context) + return -ENOMEM; + + smu_dpm->dpm_context_size = sizeof(struct arcturus_dpm_table); + + smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state), + GFP_KERNEL); + if (!smu_dpm->dpm_current_power_state) + return -ENOMEM; + + smu_dpm->dpm_request_power_state = kzalloc(sizeof(struct smu_power_state), + GFP_KERNEL); + if (!smu_dpm->dpm_request_power_state) + return -ENOMEM; + + return 0; +} + +static int +arcturus_get_allowed_feature_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num) +{ + if (num > 2) + return -EINVAL; + + /* pptable will handle the features to enable */ + memset(feature_mask, 0xFF, sizeof(uint32_t) * num); + + return 0; +} + +static int +arcturus_set_single_dpm_table(struct smu_context *smu, + struct arcturus_single_dpm_table *single_dpm_table, + PPCLK_e clk_id) +{ + int ret = 0; + uint32_t i, num_of_levels = 0, clk; + + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_GetDpmFreqByIndex, + (clk_id << 16 | 0xFF)); + if (ret) { + pr_err("[%s] failed to get dpm levels!\n", __func__); + return ret; + } + + smu_read_smc_arg(smu, &num_of_levels); + if (!num_of_levels) { + pr_err("[%s] number of clk levels is invalid!\n", __func__); + return -EINVAL; + } + + single_dpm_table->count = num_of_levels; + for (i = 0; i < num_of_levels; i++) { + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_GetDpmFreqByIndex, + (clk_id << 16 | i)); + if (ret) { + pr_err("[%s] failed to get dpm freq by index!\n", __func__); + return ret; + } + smu_read_smc_arg(smu, &clk); + if (!clk) { + pr_err("[%s] clk value is invalid!\n", __func__); + return -EINVAL; + } + single_dpm_table->dpm_levels[i].value = clk; + single_dpm_table->dpm_levels[i].enabled = true; + } + return 0; +} + +static void arcturus_init_single_dpm_state(struct arcturus_dpm_state *dpm_state) +{ + dpm_state->soft_min_level = 0x0; + dpm_state->soft_max_level = 0xffff; + dpm_state->hard_min_level = 0x0; + dpm_state->hard_max_level = 0xffff; +} + +static int arcturus_set_default_dpm_table(struct smu_context *smu) +{ + int ret; + + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct arcturus_dpm_table *dpm_table = NULL; + struct arcturus_single_dpm_table *single_dpm_table; + + dpm_table = smu_dpm->dpm_context; + + /* socclk */ + single_dpm_table = &(dpm_table->soc_table); + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = arcturus_set_single_dpm_table(smu, single_dpm_table, + PPCLK_SOCCLK); + if (ret) { + pr_err("[%s] failed to get socclk dpm levels!\n", __func__); + return ret; + } + } else { + single_dpm_table->count = 1; + single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + } + arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); + + /* gfxclk */ + single_dpm_table = &(dpm_table->gfx_table); + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = arcturus_set_single_dpm_table(smu, single_dpm_table, + PPCLK_GFXCLK); + if (ret) { + pr_err("[SetupDefaultDpmTable] failed to get gfxclk dpm levels!"); + return ret; + } + } else { + single_dpm_table->count = 1; + single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + } + arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); + + /* memclk */ + single_dpm_table = &(dpm_table->mem_table); + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = arcturus_set_single_dpm_table(smu, single_dpm_table, + PPCLK_UCLK); + if (ret) { + pr_err("[SetupDefaultDpmTable] failed to get memclk dpm levels!"); + return ret; + } + } else { + single_dpm_table->count = 1; + single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + } + arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); + + /* fclk */ + single_dpm_table = &(dpm_table->fclk_table); + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + ret = arcturus_set_single_dpm_table(smu, single_dpm_table, + PPCLK_FCLK); + if (ret) { + pr_err("[SetupDefaultDpmTable] failed to get fclk dpm levels!"); + return ret; + } + } else { + single_dpm_table->count = 1; + single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; + } + arcturus_init_single_dpm_state(&(single_dpm_table->dpm_state)); + + memcpy(smu_dpm->golden_dpm_context, dpm_table, + sizeof(struct arcturus_dpm_table)); + + return 0; +} + +static int arcturus_check_powerplay_table(struct smu_context *smu) +{ + return 0; +} + +static int arcturus_store_powerplay_table(struct smu_context *smu) +{ + struct smu_11_0_powerplay_table *powerplay_table = NULL; + struct smu_table_context *table_context = &smu->smu_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; + int ret = 0; + + if (!table_context->power_play_table) + return -EINVAL; + + powerplay_table = table_context->power_play_table; + + memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, + sizeof(PPTable_t)); + + table_context->thermal_controller_type = powerplay_table->thermal_controller_type; + + mutex_lock(&smu_baco->mutex); + if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO || + powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO) + smu_baco->platform_support = true; + mutex_unlock(&smu_baco->mutex); + + return ret; +} + +static int arcturus_append_powerplay_table(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *smc_pptable = table_context->driver_pptable; + struct atom_smc_dpm_info_v4_6 *smc_dpm_table; + int index, ret; + + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + smc_dpm_info); + + ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, + (uint8_t **)&smc_dpm_table); + if (ret) + return ret; + + pr_info("smc_dpm_info table revision(format.content): %d.%d\n", + smc_dpm_table->table_header.format_revision, + smc_dpm_table->table_header.content_revision); + + if ((smc_dpm_table->table_header.format_revision == 4) && + (smc_dpm_table->table_header.content_revision == 6)) + memcpy(&smc_pptable->MaxVoltageStepGfx, + &smc_dpm_table->maxvoltagestepgfx, + sizeof(*smc_dpm_table) - offsetof(struct atom_smc_dpm_info_v4_6, maxvoltagestepgfx)); + + return 0; +} + +static int arcturus_run_btc(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc); + if (ret) { + pr_err("RunAfllBtc failed!\n"); + return ret; + } + + return smu_send_smc_msg(smu, SMU_MSG_RunDcBtc); +} + +static int arcturus_populate_umd_state_clk(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct arcturus_dpm_table *dpm_table = NULL; + struct arcturus_single_dpm_table *gfx_table = NULL; + struct arcturus_single_dpm_table *mem_table = NULL; + + dpm_table = smu_dpm->dpm_context; + gfx_table = &(dpm_table->gfx_table); + mem_table = &(dpm_table->mem_table); + + smu->pstate_sclk = gfx_table->dpm_levels[0].value; + smu->pstate_mclk = mem_table->dpm_levels[0].value; + + if (gfx_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL && + mem_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL) { + smu->pstate_sclk = gfx_table->dpm_levels[ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL].value; + smu->pstate_mclk = mem_table->dpm_levels[ARCTURUS_UMD_PSTATE_MCLK_LEVEL].value; + } + + smu->pstate_sclk = smu->pstate_sclk * 100; + smu->pstate_mclk = smu->pstate_mclk * 100; + + return 0; +} + +static int arcturus_get_clk_table(struct smu_context *smu, + struct pp_clock_levels_with_latency *clocks, + struct arcturus_single_dpm_table *dpm_table) +{ + int i, count; + + count = (dpm_table->count > MAX_NUM_CLOCKS) ? MAX_NUM_CLOCKS : dpm_table->count; + clocks->num_levels = count; + + for (i = 0; i < count; i++) { + clocks->data[i].clocks_in_khz = + dpm_table->dpm_levels[i].value * 1000; + clocks->data[i].latency_in_us = 0; + } + + return 0; +} + +static int arcturus_freqs_in_same_level(int32_t frequency1, + int32_t frequency2) +{ + return (abs(frequency1 - frequency2) <= EPSILON); +} + +static int arcturus_print_clk_levels(struct smu_context *smu, + enum smu_clk_type type, char *buf) +{ + int i, now, size = 0; + int ret = 0; + struct pp_clock_levels_with_latency clocks; + struct arcturus_single_dpm_table *single_dpm_table; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct arcturus_dpm_table *dpm_table = NULL; + + dpm_table = smu_dpm->dpm_context; + + switch (type) { + case SMU_SCLK: + ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now); + if (ret) { + pr_err("Attempt to get current gfx clk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_table->gfx_table); + ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + pr_err("Attempt to get gfx clk levels Failed!"); + return ret; + } + + /* + * For DPM disabled case, there will be only one clock level. + * And it's safe to assume that is always the current clock. + */ + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", i, + clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (arcturus_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now / 100) ? "*" : "")); + break; + + case SMU_MCLK: + ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now); + if (ret) { + pr_err("Attempt to get current mclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_table->mem_table); + ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + pr_err("Attempt to get memory clk levels Failed!"); + return ret; + } + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (arcturus_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now / 100) ? "*" : "")); + break; + + case SMU_SOCCLK: + ret = smu_get_current_clk_freq(smu, SMU_SOCCLK, &now); + if (ret) { + pr_err("Attempt to get current socclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_table->soc_table); + ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + pr_err("Attempt to get socclk levels Failed!"); + return ret; + } + + for (i = 0; i < clocks.num_levels; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, clocks.data[i].clocks_in_khz / 1000, + (clocks.num_levels == 1) ? "*" : + (arcturus_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now / 100) ? "*" : "")); + break; + + case SMU_FCLK: + ret = smu_get_current_clk_freq(smu, SMU_FCLK, &now); + if (ret) { + pr_err("Attempt to get current fclk Failed!"); + return ret; + } + + single_dpm_table = &(dpm_table->fclk_table); + ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); + if (ret) { + pr_err("Attempt to get fclk levels Failed!"); + return ret; + } + + for (i = 0; i < single_dpm_table->count; i++) + size += sprintf(buf + size, "%d: %uMhz %s\n", + i, single_dpm_table->dpm_levels[i].value, + (clocks.num_levels == 1) ? "*" : + (arcturus_freqs_in_same_level( + clocks.data[i].clocks_in_khz / 1000, + now / 100) ? "*" : "")); + break; + + default: + break; + } + + return size; +} + +static int arcturus_upload_dpm_level(struct smu_context *smu, bool max, + uint32_t feature_mask) +{ + struct arcturus_single_dpm_table *single_dpm_table; + struct arcturus_dpm_table *dpm_table = + smu->smu_dpm.dpm_context; + uint32_t freq; + int ret = 0; + + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) && + (feature_mask & FEATURE_DPM_GFXCLK_MASK)) { + single_dpm_table = &(dpm_table->gfx_table); + freq = max ? single_dpm_table->dpm_state.soft_max_level : + single_dpm_table->dpm_state.soft_min_level; + ret = smu_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_GFXCLK << 16) | (freq & 0xffff)); + if (ret) { + pr_err("Failed to set soft %s gfxclk !\n", + max ? "max" : "min"); + return ret; + } + } + + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && + (feature_mask & FEATURE_DPM_UCLK_MASK)) { + single_dpm_table = &(dpm_table->mem_table); + freq = max ? single_dpm_table->dpm_state.soft_max_level : + single_dpm_table->dpm_state.soft_min_level; + ret = smu_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_UCLK << 16) | (freq & 0xffff)); + if (ret) { + pr_err("Failed to set soft %s memclk !\n", + max ? "max" : "min"); + return ret; + } + } + + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) && + (feature_mask & FEATURE_DPM_SOCCLK_MASK)) { + single_dpm_table = &(dpm_table->soc_table); + freq = max ? single_dpm_table->dpm_state.soft_max_level : + single_dpm_table->dpm_state.soft_min_level; + ret = smu_send_smc_msg_with_param(smu, + (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), + (PPCLK_SOCCLK << 16) | (freq & 0xffff)); + if (ret) { + pr_err("Failed to set soft %s socclk !\n", + max ? "max" : "min"); + return ret; + } + } + + return ret; +} + +static int arcturus_force_clk_levels(struct smu_context *smu, + enum smu_clk_type type, uint32_t mask) +{ + struct arcturus_dpm_table *dpm_table; + struct arcturus_single_dpm_table *single_dpm_table; + uint32_t soft_min_level, soft_max_level; + int ret = 0; + + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + dpm_table = smu->smu_dpm.dpm_context; + + switch (type) { + case SMU_SCLK: + single_dpm_table = &(dpm_table->gfx_table); + + if (soft_max_level >= single_dpm_table->count) { + pr_err("Clock level specified %d is over max allowed %d\n", + soft_max_level, single_dpm_table->count - 1); + ret = -EINVAL; + break; + } + + single_dpm_table->dpm_state.soft_min_level = + single_dpm_table->dpm_levels[soft_min_level].value; + single_dpm_table->dpm_state.soft_max_level = + single_dpm_table->dpm_levels[soft_max_level].value; + + ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK); + if (ret) { + pr_err("Failed to upload boot level to lowest!\n"); + break; + } + + ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK); + if (ret) + pr_err("Failed to upload dpm max level to highest!\n"); + + break; + + case SMU_MCLK: + case SMU_SOCCLK: + case SMU_FCLK: + /* + * Should not arrive here since Arcturus does not + * support mclk/socclk/fclk softmin/softmax settings + */ + ret = -EINVAL; + break; + + default: + break; + } + + return ret; +} + +static int arcturus_get_thermal_temperature_range(struct smu_context *smu, + struct smu_temperature_range *range) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + + if (!range) + return -EINVAL; + + range->max = pptable->TedgeLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_crit_max = pptable->ThotspotLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_crit_max = pptable->TmemLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_HBM)* + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int arcturus_get_metrics_table(struct smu_context *smu, + SmuMetrics_t *metrics_table) +{ + struct smu_table_context *smu_table= &smu->smu_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + if (!smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + HZ / 1000)) { + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, + (void *)smu_table->metrics_table, false); + if (ret) { + pr_info("Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); + return ret; + } + smu_table->metrics_time = jiffies; + } + + memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int arcturus_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + SmuMetrics_t metrics; + int ret = 0; + + if (!value) + return -EINVAL; + + ret = arcturus_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + *value = metrics.AverageGfxActivity; + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + *value = metrics.AverageUclkActivity; + break; + default: + pr_err("Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return 0; +} + +static int arcturus_get_gpu_power(struct smu_context *smu, uint32_t *value) +{ + SmuMetrics_t metrics; + int ret = 0; + + if (!value) + return -EINVAL; + + ret = arcturus_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + *value = metrics.AverageSocketPower << 8; + + return 0; +} + +static int arcturus_thermal_get_temperature(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + SmuMetrics_t metrics; + int ret = 0; + + if (!value) + return -EINVAL; + + ret = arcturus_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (sensor) { + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + *value = metrics.TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case AMDGPU_PP_SENSOR_EDGE_TEMP: + *value = metrics.TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case AMDGPU_PP_SENSOR_MEM_TEMP: + *value = metrics.TemperatureHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + default: + pr_err("Invalid sensor for retrieving temp\n"); + return -EINVAL; + } + + return 0; +} + +static int arcturus_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + int ret = 0; + + if (!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); + switch (sensor) { + case AMDGPU_PP_SENSOR_MAX_FAN_RPM: + *(uint32_t *)data = pptable->FanMaximumRpm; + *size = 4; + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = arcturus_get_current_activity_percent(smu, + sensor, + (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_POWER: + ret = arcturus_get_gpu_power(smu, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + case AMDGPU_PP_SENSOR_EDGE_TEMP: + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = arcturus_thermal_get_temperature(smu, sensor, + (uint32_t *)data); + *size = 4; + break; + default: + ret = smu_v11_0_read_sensor(smu, sensor, data, size); + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + +static int arcturus_get_fan_speed_rpm(struct smu_context *smu, + uint32_t *speed) +{ + SmuMetrics_t metrics; + int ret = 0; + + if (!speed) + return -EINVAL; + + ret = arcturus_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + *speed = metrics.CurrFanSpeed; + + return ret; +} + +static int arcturus_get_fan_speed_percent(struct smu_context *smu, + uint32_t *speed) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t percent, current_rpm; + int ret = 0; + + if (!speed) + return -EINVAL; + + ret = arcturus_get_fan_speed_rpm(smu, ¤t_rpm); + if (ret) + return ret; + + percent = current_rpm * 100 / pptable->FanMaximumRpm; + *speed = percent > 100 ? 100 : percent; + + return ret; +} + +static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + static SmuMetrics_t metrics; + int ret = 0, clk_id = 0; + + if (!value) + return -EINVAL; + + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) + return -EINVAL; + + ret = arcturus_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (clk_id) { + case PPCLK_GFXCLK: + /* + * CurrClock[clk_id] can provide accurate + * output only when the dpm feature is enabled. + * We can use Average_* for dpm disabled case. + * But this is available for gfxclk/uclk/socclk. + */ + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) + *value = metrics.CurrClock[PPCLK_GFXCLK]; + else + *value = metrics.AverageGfxclkFrequency; + break; + case PPCLK_UCLK: + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) + *value = metrics.CurrClock[PPCLK_UCLK]; + else + *value = metrics.AverageUclkFrequency; + break; + case PPCLK_SOCCLK: + if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) + *value = metrics.CurrClock[PPCLK_SOCCLK]; + else + *value = metrics.AverageSocclkFrequency; + break; + default: + *value = metrics.CurrClock[clk_id]; + break; + } + + return ret; +} + +static uint32_t arcturus_find_lowest_dpm_level(struct arcturus_single_dpm_table *table) +{ + uint32_t i; + + for (i = 0; i < table->count; i++) { + if (table->dpm_levels[i].enabled) + break; + } + if (i >= table->count) { + i = 0; + table->dpm_levels[i].enabled = true; + } + + return i; +} + +static uint32_t arcturus_find_highest_dpm_level(struct arcturus_single_dpm_table *table) +{ + int i = 0; + + if (table->count <= 0) { + pr_err("[%s] DPM Table has no entry!", __func__); + return 0; + } + if (table->count > MAX_DPM_NUMBER) { + pr_err("[%s] DPM Table has too many entries!", __func__); + return MAX_DPM_NUMBER - 1; + } + + for (i = table->count - 1; i >= 0; i--) { + if (table->dpm_levels[i].enabled) + break; + } + if (i < 0) { + i = 0; + table->dpm_levels[i].enabled = true; + } + + return i; +} + + + +static int arcturus_force_dpm_limit_value(struct smu_context *smu, bool highest) +{ + struct arcturus_dpm_table *dpm_table = + (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(smu->adev, 0); + uint32_t soft_level; + int ret = 0; + + /* gfxclk */ + if (highest) + soft_level = arcturus_find_highest_dpm_level(&(dpm_table->gfx_table)); + else + soft_level = arcturus_find_lowest_dpm_level(&(dpm_table->gfx_table)); + + dpm_table->gfx_table.dpm_state.soft_min_level = + dpm_table->gfx_table.dpm_state.soft_max_level = + dpm_table->gfx_table.dpm_levels[soft_level].value; + + ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK); + if (ret) { + pr_err("Failed to upload boot level to %s!\n", + highest ? "highest" : "lowest"); + return ret; + } + + ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK); + if (ret) { + pr_err("Failed to upload dpm max level to %s!\n!", + highest ? "highest" : "lowest"); + return ret; + } + + if (hive) + /* + * Force XGMI Pstate to highest or lowest + * TODO: revise this when xgmi dpm is functional + */ + ret = smu_v11_0_set_xgmi_pstate(smu, highest ? 1 : 0); + + return ret; +} + +static int arcturus_unforce_dpm_levels(struct smu_context *smu) +{ + struct arcturus_dpm_table *dpm_table = + (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; + struct amdgpu_hive_info *hive = amdgpu_get_xgmi_hive(smu->adev, 0); + uint32_t soft_min_level, soft_max_level; + int ret = 0; + + /* gfxclk */ + soft_min_level = arcturus_find_lowest_dpm_level(&(dpm_table->gfx_table)); + soft_max_level = arcturus_find_highest_dpm_level(&(dpm_table->gfx_table)); + dpm_table->gfx_table.dpm_state.soft_min_level = + dpm_table->gfx_table.dpm_levels[soft_min_level].value; + dpm_table->gfx_table.dpm_state.soft_max_level = + dpm_table->gfx_table.dpm_levels[soft_max_level].value; + + ret = arcturus_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK); + if (ret) { + pr_err("Failed to upload DPM Bootup Levels!"); + return ret; + } + + ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK); + if (ret) { + pr_err("Failed to upload DPM Max Levels!"); + return ret; + } + + if (hive) + /* + * Reset XGMI Pstate back to default + * TODO: revise this when xgmi dpm is functional + */ + ret = smu_v11_0_set_xgmi_pstate(smu, 0); + + return ret; +} + +static int +arcturus_get_profiling_clk_mask(struct smu_context *smu, + enum amd_dpm_forced_level level, + uint32_t *sclk_mask, + uint32_t *mclk_mask, + uint32_t *soc_mask) +{ + struct arcturus_dpm_table *dpm_table = + (struct arcturus_dpm_table *)smu->smu_dpm.dpm_context; + struct arcturus_single_dpm_table *gfx_dpm_table; + struct arcturus_single_dpm_table *mem_dpm_table; + struct arcturus_single_dpm_table *soc_dpm_table; + + if (!smu->smu_dpm.dpm_context) + return -EINVAL; + + gfx_dpm_table = &dpm_table->gfx_table; + mem_dpm_table = &dpm_table->mem_table; + soc_dpm_table = &dpm_table->soc_table; + + *sclk_mask = 0; + *mclk_mask = 0; + *soc_mask = 0; + + if (gfx_dpm_table->count > ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL && + mem_dpm_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL && + soc_dpm_table->count > ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL) { + *sclk_mask = ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL; + *mclk_mask = ARCTURUS_UMD_PSTATE_MCLK_LEVEL; + *soc_mask = ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL; + } + + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + *sclk_mask = 0; + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { + *mclk_mask = 0; + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + *sclk_mask = gfx_dpm_table->count - 1; + *mclk_mask = mem_dpm_table->count - 1; + *soc_mask = soc_dpm_table->count - 1; + } + + return 0; +} + +static int arcturus_get_power_limit(struct smu_context *smu, + uint32_t *limit, + bool cap) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t asic_default_power_limit = 0; + int ret = 0; + int power_src; + + if (!smu->power_limit) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { + power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC); + if (power_src < 0) + return -EINVAL; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit, + power_src << 16); + if (ret) { + pr_err("[%s] get PPT limit failed!", __func__); + return ret; + } + smu_read_smc_arg(smu, &asic_default_power_limit); + } else { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + pr_err("Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + asic_default_power_limit = + pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; + } + + smu->power_limit = asic_default_power_limit; + } + + if (cap) + *limit = smu_v11_0_get_max_power_limit(smu); + else + *limit = smu->power_limit; + + return 0; +} + +static int arcturus_get_power_profile_mode(struct smu_context *smu, + char *buf) +{ + struct amdgpu_device *adev = smu->adev; + DpmActivityMonitorCoeffInt_t activity_monitor; + static const char *profile_name[] = { + "BOOTUP_DEFAULT", + "3D_FULL_SCREEN", + "POWER_SAVING", + "VIDEO", + "VR", + "COMPUTE", + "CUSTOM"}; + static const char *title[] = { + "PROFILE_INDEX(NAME)", + "CLOCK_TYPE(NAME)", + "FPS", + "UseRlcBusy", + "MinActiveFreqType", + "MinActiveFreq", + "BoosterFreqType", + "BoosterFreq", + "PD_Data_limit_c", + "PD_Data_error_coeff", + "PD_Data_error_rate_coeff"}; + uint32_t i, size = 0; + int16_t workload_type = 0; + int result = 0; + uint32_t smu_version; + + if (!buf) + return -EINVAL; + + result = smu_get_smc_version(smu, NULL, &smu_version); + if (result) + return result; + + if (smu_version >= 0x360d00 && !amdgpu_sriov_vf(adev)) + size += sprintf(buf + size, "%16s %s %s %s %s %s %s %s %s %s %s\n", + title[0], title[1], title[2], title[3], title[4], title[5], + title[6], title[7], title[8], title[9], title[10]); + else + size += sprintf(buf + size, "%16s\n", + title[0]); + + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { + /* + * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT + * Not all profile modes are supported on arcturus. + */ + workload_type = smu_workload_get_type(smu, i); + if (workload_type < 0) + continue; + + if (smu_version >= 0x360d00 && !amdgpu_sriov_vf(adev)) { + result = smu_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + workload_type, + (void *)(&activity_monitor), + false); + if (result) { + pr_err("[%s] Failed to get activity monitor!", __func__); + return result; + } + } + + size += sprintf(buf + size, "%2d %14s%s\n", + i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); + + if (smu_version >= 0x360d00 && !amdgpu_sriov_vf(adev)) { + size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", + " ", + 0, + "GFXCLK", + activity_monitor.Gfx_FPS, + activity_monitor.Gfx_UseRlcBusy, + activity_monitor.Gfx_MinActiveFreqType, + activity_monitor.Gfx_MinActiveFreq, + activity_monitor.Gfx_BoosterFreqType, + activity_monitor.Gfx_BoosterFreq, + activity_monitor.Gfx_PD_Data_limit_c, + activity_monitor.Gfx_PD_Data_error_coeff, + activity_monitor.Gfx_PD_Data_error_rate_coeff); + + size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", + " ", + 1, + "UCLK", + activity_monitor.Mem_FPS, + activity_monitor.Mem_UseRlcBusy, + activity_monitor.Mem_MinActiveFreqType, + activity_monitor.Mem_MinActiveFreq, + activity_monitor.Mem_BoosterFreqType, + activity_monitor.Mem_BoosterFreq, + activity_monitor.Mem_PD_Data_limit_c, + activity_monitor.Mem_PD_Data_error_coeff, + activity_monitor.Mem_PD_Data_error_rate_coeff); + } + } + + return size; +} + +static int arcturus_set_power_profile_mode(struct smu_context *smu, + long *input, + uint32_t size) +{ + DpmActivityMonitorCoeffInt_t activity_monitor; + int workload_type = 0; + uint32_t profile_mode = input[size]; + int ret = 0; + uint32_t smu_version; + + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { + pr_err("Invalid power profile mode %d\n", profile_mode); + return -EINVAL; + } + + ret = smu_get_smc_version(smu, NULL, &smu_version); + if (ret) + return ret; + + if ((profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) && + (smu_version >=0x360d00)) { + ret = smu_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), + false); + if (ret) { + pr_err("[%s] Failed to get activity monitor!", __func__); + return ret; + } + + switch (input[0]) { + case 0: /* Gfxclk */ + activity_monitor.Gfx_FPS = input[1]; + activity_monitor.Gfx_UseRlcBusy = input[2]; + activity_monitor.Gfx_MinActiveFreqType = input[3]; + activity_monitor.Gfx_MinActiveFreq = input[4]; + activity_monitor.Gfx_BoosterFreqType = input[5]; + activity_monitor.Gfx_BoosterFreq = input[6]; + activity_monitor.Gfx_PD_Data_limit_c = input[7]; + activity_monitor.Gfx_PD_Data_error_coeff = input[8]; + activity_monitor.Gfx_PD_Data_error_rate_coeff = input[9]; + break; + case 1: /* Uclk */ + activity_monitor.Mem_FPS = input[1]; + activity_monitor.Mem_UseRlcBusy = input[2]; + activity_monitor.Mem_MinActiveFreqType = input[3]; + activity_monitor.Mem_MinActiveFreq = input[4]; + activity_monitor.Mem_BoosterFreqType = input[5]; + activity_monitor.Mem_BoosterFreq = input[6]; + activity_monitor.Mem_PD_Data_limit_c = input[7]; + activity_monitor.Mem_PD_Data_error_coeff = input[8]; + activity_monitor.Mem_PD_Data_error_rate_coeff = input[9]; + break; + } + + ret = smu_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, + WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), + true); + if (ret) { + pr_err("[%s] Failed to set activity monitor!", __func__); + return ret; + } + } + + /* + * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT + * Not all profile modes are supported on arcturus. + */ + workload_type = smu_workload_get_type(smu, profile_mode); + if (workload_type < 0) { + pr_err("Unsupported power profile mode %d on arcturus\n", profile_mode); + return -EINVAL; + } + + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_SetWorkloadMask, + 1 << workload_type); + if (ret) { + pr_err("Fail to set workload type %d\n", workload_type); + return ret; + } + + smu->power_profile_mode = profile_mode; + + return 0; +} + +static void arcturus_dump_pptable(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + int i; + + pr_info("Dumped PPTable:\n"); + + pr_info("Version = 0x%08x\n", pptable->Version); + + pr_info("FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); + pr_info("FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); + + for (i = 0; i < PPT_THROTTLER_COUNT; i++) { + pr_info("SocketPowerLimitAc[%d] = %d\n", i, pptable->SocketPowerLimitAc[i]); + pr_info("SocketPowerLimitAcTau[%d] = %d\n", i, pptable->SocketPowerLimitAcTau[i]); + } + + pr_info("TdcLimitSoc = %d\n", pptable->TdcLimitSoc); + pr_info("TdcLimitSocTau = %d\n", pptable->TdcLimitSocTau); + pr_info("TdcLimitGfx = %d\n", pptable->TdcLimitGfx); + pr_info("TdcLimitGfxTau = %d\n", pptable->TdcLimitGfxTau); + + pr_info("TedgeLimit = %d\n", pptable->TedgeLimit); + pr_info("ThotspotLimit = %d\n", pptable->ThotspotLimit); + pr_info("TmemLimit = %d\n", pptable->TmemLimit); + pr_info("Tvr_gfxLimit = %d\n", pptable->Tvr_gfxLimit); + pr_info("Tvr_memLimit = %d\n", pptable->Tvr_memLimit); + pr_info("Tvr_socLimit = %d\n", pptable->Tvr_socLimit); + pr_info("FitLimit = %d\n", pptable->FitLimit); + + pr_info("PpmPowerLimit = %d\n", pptable->PpmPowerLimit); + pr_info("PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); + + pr_info("ThrottlerControlMask = %d\n", pptable->ThrottlerControlMask); + + pr_info("UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); + pr_info("UlvPadding = 0x%08x\n", pptable->UlvPadding); + + pr_info("UlvGfxclkBypass = %d\n", pptable->UlvGfxclkBypass); + pr_info("Padding234[0] = 0x%02x\n", pptable->Padding234[0]); + pr_info("Padding234[1] = 0x%02x\n", pptable->Padding234[1]); + pr_info("Padding234[2] = 0x%02x\n", pptable->Padding234[2]); + + pr_info("MinVoltageGfx = %d\n", pptable->MinVoltageGfx); + pr_info("MinVoltageSoc = %d\n", pptable->MinVoltageSoc); + pr_info("MaxVoltageGfx = %d\n", pptable->MaxVoltageGfx); + pr_info("MaxVoltageSoc = %d\n", pptable->MaxVoltageSoc); + + pr_info("LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); + pr_info("LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); + + pr_info("[PPCLK_GFXCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_GFXCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_GFXCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_GFXCLK].padding, + pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_GFXCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_GFXCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); + + pr_info("[PPCLK_VCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_VCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_VCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_VCLK].padding, + pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_VCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_VCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_VCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_VCLK].Padding16); + + pr_info("[PPCLK_DCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_DCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_DCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_DCLK].padding, + pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_DCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_DCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_DCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_DCLK].Padding16); + + pr_info("[PPCLK_SOCCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_SOCCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_SOCCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_SOCCLK].padding, + pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_SOCCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_SOCCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); + + pr_info("[PPCLK_UCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_UCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_UCLK].padding, + pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_UCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_UCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_UCLK].Padding16); + + pr_info("[PPCLK_FCLK]\n" + " .VoltageMode = 0x%02x\n" + " .SnapToDiscrete = 0x%02x\n" + " .NumDiscreteLevels = 0x%02x\n" + " .padding = 0x%02x\n" + " .ConversionToAvfsClk{m = 0x%08x b = 0x%08x}\n" + " .SsCurve {a = 0x%08x b = 0x%08x c = 0x%08x}\n" + " .SsFmin = 0x%04x\n" + " .Padding_16 = 0x%04x\n", + pptable->DpmDescriptor[PPCLK_FCLK].VoltageMode, + pptable->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_FCLK].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_FCLK].padding, + pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_FCLK].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.a, + pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.b, + pptable->DpmDescriptor[PPCLK_FCLK].SsCurve.c, + pptable->DpmDescriptor[PPCLK_FCLK].SsFmin, + pptable->DpmDescriptor[PPCLK_FCLK].Padding16); + + + pr_info("FreqTableGfx\n"); + for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); + + pr_info("FreqTableVclk\n"); + for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); + + pr_info("FreqTableDclk\n"); + for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); + + pr_info("FreqTableSocclk\n"); + for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); + + pr_info("FreqTableUclk\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); + + pr_info("FreqTableFclk\n"); + for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) + pr_info(" .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); + + pr_info("Mp0clkFreq\n"); + for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); + + pr_info("Mp0DpmVoltage\n"); + for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->Mp0DpmVoltage[i]); + + pr_info("GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); + pr_info("GfxclkSlewRate = 0x%x\n", pptable->GfxclkSlewRate); + pr_info("Padding567[0] = 0x%x\n", pptable->Padding567[0]); + pr_info("Padding567[1] = 0x%x\n", pptable->Padding567[1]); + pr_info("Padding567[2] = 0x%x\n", pptable->Padding567[2]); + pr_info("Padding567[3] = 0x%x\n", pptable->Padding567[3]); + pr_info("GfxclkDsMaxFreq = %d\n", pptable->GfxclkDsMaxFreq); + pr_info("GfxclkSource = 0x%x\n", pptable->GfxclkSource); + pr_info("Padding456 = 0x%x\n", pptable->Padding456); + + pr_info("EnableTdpm = %d\n", pptable->EnableTdpm); + pr_info("TdpmHighHystTemperature = %d\n", pptable->TdpmHighHystTemperature); + pr_info("TdpmLowHystTemperature = %d\n", pptable->TdpmLowHystTemperature); + pr_info("GfxclkFreqHighTempLimit = %d\n", pptable->GfxclkFreqHighTempLimit); + + pr_info("FanStopTemp = %d\n", pptable->FanStopTemp); + pr_info("FanStartTemp = %d\n", pptable->FanStartTemp); + + pr_info("FanGainEdge = %d\n", pptable->FanGainEdge); + pr_info("FanGainHotspot = %d\n", pptable->FanGainHotspot); + pr_info("FanGainVrGfx = %d\n", pptable->FanGainVrGfx); + pr_info("FanGainVrSoc = %d\n", pptable->FanGainVrSoc); + pr_info("FanGainVrMem = %d\n", pptable->FanGainVrMem); + pr_info("FanGainHbm = %d\n", pptable->FanGainHbm); + + pr_info("FanPwmMin = %d\n", pptable->FanPwmMin); + pr_info("FanAcousticLimitRpm = %d\n", pptable->FanAcousticLimitRpm); + pr_info("FanThrottlingRpm = %d\n", pptable->FanThrottlingRpm); + pr_info("FanMaximumRpm = %d\n", pptable->FanMaximumRpm); + pr_info("FanTargetTemperature = %d\n", pptable->FanTargetTemperature); + pr_info("FanTargetGfxclk = %d\n", pptable->FanTargetGfxclk); + pr_info("FanZeroRpmEnable = %d\n", pptable->FanZeroRpmEnable); + pr_info("FanTachEdgePerRev = %d\n", pptable->FanTachEdgePerRev); + pr_info("FanTempInputSelect = %d\n", pptable->FanTempInputSelect); + + pr_info("FuzzyFan_ErrorSetDelta = %d\n", pptable->FuzzyFan_ErrorSetDelta); + pr_info("FuzzyFan_ErrorRateSetDelta = %d\n", pptable->FuzzyFan_ErrorRateSetDelta); + pr_info("FuzzyFan_PwmSetDelta = %d\n", pptable->FuzzyFan_PwmSetDelta); + pr_info("FuzzyFan_Reserved = %d\n", pptable->FuzzyFan_Reserved); + + pr_info("OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); + pr_info("OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); + pr_info("Padding8_Avfs[0] = %d\n", pptable->Padding8_Avfs[0]); + pr_info("Padding8_Avfs[1] = %d\n", pptable->Padding8_Avfs[1]); + + pr_info("dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbGfxPll.a, + pptable->dBtcGbGfxPll.b, + pptable->dBtcGbGfxPll.c); + pr_info("dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbGfxAfll.a, + pptable->dBtcGbGfxAfll.b, + pptable->dBtcGbGfxAfll.c); + pr_info("dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbSoc.a, + pptable->dBtcGbSoc.b, + pptable->dBtcGbSoc.c); + + pr_info("qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", + pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, + pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); + pr_info("qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", + pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, + pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); + + pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].a, + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].b, + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_GFX].c); + pr_info("qStaticVoltageOffset[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].a, + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].b, + pptable->qStaticVoltageOffset[AVFS_VOLTAGE_SOC].c); + + pr_info("DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); + pr_info("DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); + + pr_info("DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); + pr_info("DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); + pr_info("Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); + pr_info("Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); + + pr_info("DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); + pr_info("DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); + pr_info("DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); + pr_info("DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); + + pr_info("DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); + pr_info("DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); + + pr_info("XgmiDpmPstates\n"); + for (i = 0; i < NUM_XGMI_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->XgmiDpmPstates[i]); + pr_info("XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); + pr_info("XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); + + pr_info("VDDGFX_TVmin = %d\n", pptable->VDDGFX_TVmin); + pr_info("VDDSOC_TVmin = %d\n", pptable->VDDSOC_TVmin); + pr_info("VDDGFX_Vmin_HiTemp = %d\n", pptable->VDDGFX_Vmin_HiTemp); + pr_info("VDDGFX_Vmin_LoTemp = %d\n", pptable->VDDGFX_Vmin_LoTemp); + pr_info("VDDSOC_Vmin_HiTemp = %d\n", pptable->VDDSOC_Vmin_HiTemp); + pr_info("VDDSOC_Vmin_LoTemp = %d\n", pptable->VDDSOC_Vmin_LoTemp); + pr_info("VDDGFX_TVminHystersis = %d\n", pptable->VDDGFX_TVminHystersis); + pr_info("VDDSOC_TVminHystersis = %d\n", pptable->VDDSOC_TVminHystersis); + + pr_info("DebugOverrides = 0x%x\n", pptable->DebugOverrides); + pr_info("ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation0.a, + pptable->ReservedEquation0.b, + pptable->ReservedEquation0.c); + pr_info("ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation1.a, + pptable->ReservedEquation1.b, + pptable->ReservedEquation1.c); + pr_info("ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation2.a, + pptable->ReservedEquation2.b, + pptable->ReservedEquation2.c); + pr_info("ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation3.a, + pptable->ReservedEquation3.b, + pptable->ReservedEquation3.c); + + pr_info("MinVoltageUlvGfx = %d\n", pptable->MinVoltageUlvGfx); + pr_info("PaddingUlv = %d\n", pptable->PaddingUlv); + + pr_info("TotalPowerConfig = %d\n", pptable->TotalPowerConfig); + pr_info("TotalPowerSpare1 = %d\n", pptable->TotalPowerSpare1); + pr_info("TotalPowerSpare2 = %d\n", pptable->TotalPowerSpare2); + + pr_info("PccThresholdLow = %d\n", pptable->PccThresholdLow); + pr_info("PccThresholdHigh = %d\n", pptable->PccThresholdHigh); + + pr_info("Board Parameters:\n"); + pr_info("MaxVoltageStepGfx = 0x%x\n", pptable->MaxVoltageStepGfx); + pr_info("MaxVoltageStepSoc = 0x%x\n", pptable->MaxVoltageStepSoc); + + pr_info("VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); + pr_info("VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); + pr_info("VddMemVrMapping = 0x%x\n", pptable->VddMemVrMapping); + pr_info("BoardVrMapping = 0x%x\n", pptable->BoardVrMapping); + + pr_info("GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); + pr_info("ExternalSensorPresent = 0x%x\n", pptable->ExternalSensorPresent); + + pr_info("GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); + pr_info("GfxOffset = 0x%x\n", pptable->GfxOffset); + pr_info("Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); + + pr_info("SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); + pr_info("SocOffset = 0x%x\n", pptable->SocOffset); + pr_info("Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); + + pr_info("MemMaxCurrent = 0x%x\n", pptable->MemMaxCurrent); + pr_info("MemOffset = 0x%x\n", pptable->MemOffset); + pr_info("Padding_TelemetryMem = 0x%x\n", pptable->Padding_TelemetryMem); + + pr_info("BoardMaxCurrent = 0x%x\n", pptable->BoardMaxCurrent); + pr_info("BoardOffset = 0x%x\n", pptable->BoardOffset); + pr_info("Padding_TelemetryBoardInput = 0x%x\n", pptable->Padding_TelemetryBoardInput); + + pr_info("VR0HotGpio = %d\n", pptable->VR0HotGpio); + pr_info("VR0HotPolarity = %d\n", pptable->VR0HotPolarity); + pr_info("VR1HotGpio = %d\n", pptable->VR1HotGpio); + pr_info("VR1HotPolarity = %d\n", pptable->VR1HotPolarity); + + pr_info("PllGfxclkSpreadEnabled = %d\n", pptable->PllGfxclkSpreadEnabled); + pr_info("PllGfxclkSpreadPercent = %d\n", pptable->PllGfxclkSpreadPercent); + pr_info("PllGfxclkSpreadFreq = %d\n", pptable->PllGfxclkSpreadFreq); + + pr_info("UclkSpreadEnabled = %d\n", pptable->UclkSpreadEnabled); + pr_info("UclkSpreadPercent = %d\n", pptable->UclkSpreadPercent); + pr_info("UclkSpreadFreq = %d\n", pptable->UclkSpreadFreq); + + pr_info("FclkSpreadEnabled = %d\n", pptable->FclkSpreadEnabled); + pr_info("FclkSpreadPercent = %d\n", pptable->FclkSpreadPercent); + pr_info("FclkSpreadFreq = %d\n", pptable->FclkSpreadFreq); + + pr_info("FllGfxclkSpreadEnabled = %d\n", pptable->FllGfxclkSpreadEnabled); + pr_info("FllGfxclkSpreadPercent = %d\n", pptable->FllGfxclkSpreadPercent); + pr_info("FllGfxclkSpreadFreq = %d\n", pptable->FllGfxclkSpreadFreq); + + for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { + pr_info("I2cControllers[%d]:\n", i); + pr_info(" .Enabled = %d\n", + pptable->I2cControllers[i].Enabled); + pr_info(" .SlaveAddress = 0x%x\n", + pptable->I2cControllers[i].SlaveAddress); + pr_info(" .ControllerPort = %d\n", + pptable->I2cControllers[i].ControllerPort); + pr_info(" .ControllerName = %d\n", + pptable->I2cControllers[i].ControllerName); + pr_info(" .ThermalThrottler = %d\n", + pptable->I2cControllers[i].ThermalThrotter); + pr_info(" .I2cProtocol = %d\n", + pptable->I2cControllers[i].I2cProtocol); + pr_info(" .Speed = %d\n", + pptable->I2cControllers[i].Speed); + } + + pr_info("MemoryChannelEnabled = %d\n", pptable->MemoryChannelEnabled); + pr_info("DramBitWidth = %d\n", pptable->DramBitWidth); + + pr_info("TotalBoardPower = %d\n", pptable->TotalBoardPower); + + pr_info("XgmiLinkSpeed\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); + pr_info("XgmiLinkWidth\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); + pr_info("XgmiFclkFreq\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); + pr_info("XgmiSocVoltage\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + pr_info(" .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); + +} + +static bool arcturus_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + uint32_t feature_mask[2]; + unsigned long feature_enabled; + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + feature_enabled = (unsigned long)((uint64_t)feature_mask[0] | + ((uint64_t)feature_mask[1] << 32)); + return !!(feature_enabled & SMC_DPM_FEATURE); +} + +static int arcturus_dpm_set_uvd_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (!smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 1); + if (ret) { + pr_err("[EnableVCNDPM] failed!\n"); + return ret; + } + } + power_gate->vcn_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 0); + if (ret) { + pr_err("[DisableVCNDPM] failed!\n"); + return ret; + } + } + power_gate->vcn_gated = true; + } + + return ret; +} + + +static void arcturus_fill_eeprom_i2c_req(SwI2cRequest_t *req, bool write, + uint8_t address, uint32_t numbytes, + uint8_t *data) +{ + int i; + + BUG_ON(numbytes > MAX_SW_I2C_COMMANDS); + + req->I2CcontrollerPort = 0; + req->I2CSpeed = 2; + req->SlaveAddress = address; + req->NumCmds = numbytes; + + for (i = 0; i < numbytes; i++) { + SwI2cCmd_t *cmd = &req->SwI2cCmds[i]; + + /* First 2 bytes are always write for lower 2b EEPROM address */ + if (i < 2) + cmd->Cmd = 1; + else + cmd->Cmd = write; + + + /* Add RESTART for read after address filled */ + cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0; + + /* Add STOP in the end */ + cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0; + + /* Fill with data regardless if read or write to simplify code */ + cmd->RegisterAddr = data[i]; + } +} + +static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control, + uint8_t address, + uint8_t *data, + uint32_t numbytes) +{ + uint32_t i, ret = 0; + SwI2cRequest_t req; + struct amdgpu_device *adev = to_amdgpu_device(control); + struct smu_table_context *smu_table = &adev->smu.smu_table; + struct smu_table *table = &smu_table->driver_table; + + memset(&req, 0, sizeof(req)); + arcturus_fill_eeprom_i2c_req(&req, false, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + /* Now read data starting with that address */ + ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, + true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr; + + /* Assume SMU fills res.SwI2cCmds[i].Data with read bytes */ + for (i = 0; i < numbytes; i++) + data[i] = res->SwI2cCmds[i].Data; + + pr_debug("arcturus_i2c_eeprom_read_data, address = %x, bytes = %d, data :", + (uint16_t)address, numbytes); + + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, + 8, 1, data, numbytes, false); + } else + pr_err("arcturus_i2c_eeprom_read_data - error occurred :%x", ret); + + return ret; +} + +static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control, + uint8_t address, + uint8_t *data, + uint32_t numbytes) +{ + uint32_t ret; + SwI2cRequest_t req; + struct amdgpu_device *adev = to_amdgpu_device(control); + + memset(&req, 0, sizeof(req)); + arcturus_fill_eeprom_i2c_req(&req, true, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + ret = smu_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + pr_debug("arcturus_i2c_write(), address = %x, bytes = %d , data: ", + (uint16_t)address, numbytes); + + print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, + 8, 1, data, numbytes, false); + /* + * According to EEPROM spec there is a MAX of 10 ms required for + * EEPROM to flush internal RX buffer after STOP was issued at the + * end of write transaction. During this time the EEPROM will not be + * responsive to any more commands - so wait a bit more. + */ + msleep(10); + + } else + pr_err("arcturus_i2c_write- error occurred :%x", ret); + + return ret; +} + +static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap, + struct i2c_msg *msgs, int num) +{ + uint32_t i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0; + uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 }; + + for (i = 0; i < num; i++) { + /* + * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at + * once and hence the data needs to be spliced into chunks and sent each + * chunk separately + */ + data_size = msgs[i].len - 2; + data_chunk_size = MAX_SW_I2C_COMMANDS - 2; + next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff); + data_ptr = msgs[i].buf + 2; + + for (j = 0; j < data_size / data_chunk_size; j++) { + /* Insert the EEPROM dest addess, bits 0-15 */ + data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff); + data_chunk[1] = (next_eeprom_addr & 0xff); + + if (msgs[i].flags & I2C_M_RD) { + ret = arcturus_i2c_eeprom_read_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, MAX_SW_I2C_COMMANDS); + + memcpy(data_ptr, data_chunk + 2, data_chunk_size); + } else { + + memcpy(data_chunk + 2, data_ptr, data_chunk_size); + + ret = arcturus_i2c_eeprom_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, MAX_SW_I2C_COMMANDS); + } + + if (ret) { + num = -EIO; + goto fail; + } + + next_eeprom_addr += data_chunk_size; + data_ptr += data_chunk_size; + } + + if (data_size % data_chunk_size) { + data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff); + data_chunk[1] = (next_eeprom_addr & 0xff); + + if (msgs[i].flags & I2C_M_RD) { + ret = arcturus_i2c_eeprom_read_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, (data_size % data_chunk_size) + 2); + + memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size); + } else { + memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size); + + ret = arcturus_i2c_eeprom_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, (data_size % data_chunk_size) + 2); + } + + if (ret) { + num = -EIO; + goto fail; + } + } + } + +fail: + return num; +} + +static u32 arcturus_i2c_eeprom_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm arcturus_i2c_eeprom_i2c_algo = { + .master_xfer = arcturus_i2c_eeprom_i2c_xfer, + .functionality = arcturus_i2c_eeprom_i2c_func, +}; + +static int arcturus_i2c_eeprom_control_init(struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + struct smu_context *smu = &adev->smu; + int res; + + if (!smu->pm_enabled) + return -EOPNOTSUPP; + + control->owner = THIS_MODULE; + control->class = I2C_CLASS_SPD; + control->dev.parent = &adev->pdev->dev; + control->algo = &arcturus_i2c_eeprom_i2c_algo; + snprintf(control->name, sizeof(control->name), "RAS EEPROM"); + + res = i2c_add_adapter(control); + if (res) + DRM_ERROR("Failed to register hw i2c, err: %d\n", res); + + return res; +} + +static void arcturus_i2c_eeprom_control_fini(struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + struct smu_context *smu = &adev->smu; + + if (!smu->pm_enabled) + return; + + i2c_del_adapter(control); +} + +static uint32_t arcturus_get_pptable_power_limit(struct smu_context *smu) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + + return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; +} + +static const struct pptable_funcs arcturus_ppt_funcs = { + /* translate smu index into arcturus specific index */ + .get_smu_msg_index = arcturus_get_smu_msg_index, + .get_smu_clk_index = arcturus_get_smu_clk_index, + .get_smu_feature_index = arcturus_get_smu_feature_index, + .get_smu_table_index = arcturus_get_smu_table_index, + .get_smu_power_index= arcturus_get_pwr_src_index, + .get_workload_type = arcturus_get_workload_type, + /* internal structurs allocations */ + .tables_init = arcturus_tables_init, + .alloc_dpm_context = arcturus_allocate_dpm_context, + /* pptable related */ + .check_powerplay_table = arcturus_check_powerplay_table, + .store_powerplay_table = arcturus_store_powerplay_table, + .append_powerplay_table = arcturus_append_powerplay_table, + /* init dpm */ + .get_allowed_feature_mask = arcturus_get_allowed_feature_mask, + /* btc */ + .run_btc = arcturus_run_btc, + /* dpm/clk tables */ + .set_default_dpm_table = arcturus_set_default_dpm_table, + .populate_umd_state_clk = arcturus_populate_umd_state_clk, + .get_thermal_temperature_range = arcturus_get_thermal_temperature_range, + .get_current_clk_freq_by_table = arcturus_get_current_clk_freq_by_table, + .print_clk_levels = arcturus_print_clk_levels, + .force_clk_levels = arcturus_force_clk_levels, + .read_sensor = arcturus_read_sensor, + .get_fan_speed_percent = arcturus_get_fan_speed_percent, + .get_fan_speed_rpm = arcturus_get_fan_speed_rpm, + .force_dpm_limit_value = arcturus_force_dpm_limit_value, + .unforce_dpm_levels = arcturus_unforce_dpm_levels, + .get_profiling_clk_mask = arcturus_get_profiling_clk_mask, + .get_power_profile_mode = arcturus_get_power_profile_mode, + .set_power_profile_mode = arcturus_set_power_profile_mode, + .set_performance_level = smu_v11_0_set_performance_level, + /* debug (internal used) */ + .dump_pptable = arcturus_dump_pptable, + .get_power_limit = arcturus_get_power_limit, + .is_dpm_running = arcturus_is_dpm_running, + .dpm_set_uvd_enable = arcturus_dpm_set_uvd_enable, + .i2c_eeprom_init = arcturus_i2c_eeprom_control_init, + .i2c_eeprom_fini = arcturus_i2c_eeprom_control_fini, + .init_microcode = smu_v11_0_init_microcode, + .load_microcode = smu_v11_0_load_microcode, + .init_smc_tables = smu_v11_0_init_smc_tables, + .fini_smc_tables = smu_v11_0_fini_smc_tables, + .init_power = smu_v11_0_init_power, + .fini_power = smu_v11_0_fini_power, + .check_fw_status = smu_v11_0_check_fw_status, + .setup_pptable = smu_v11_0_setup_pptable, + .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, + .get_clk_info_from_vbios = smu_v11_0_get_clk_info_from_vbios, + .check_pptable = smu_v11_0_check_pptable, + .parse_pptable = smu_v11_0_parse_pptable, + .populate_smc_tables = smu_v11_0_populate_smc_pptable, + .check_fw_version = smu_v11_0_check_fw_version, + .write_pptable = smu_v11_0_write_pptable, + .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep, + .set_driver_table_location = smu_v11_0_set_driver_table_location, + .set_tool_table_location = smu_v11_0_set_tool_table_location, + .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, + .system_features_control = smu_v11_0_system_features_control, + .send_smc_msg_with_param = smu_v11_0_send_msg_with_param, + .read_smc_arg = smu_v11_0_read_arg, + .init_display_count = smu_v11_0_init_display_count, + .set_allowed_mask = smu_v11_0_set_allowed_mask, + .get_enabled_mask = smu_v11_0_get_enabled_mask, + .notify_display_change = smu_v11_0_notify_display_change, + .set_power_limit = smu_v11_0_set_power_limit, + .get_current_clk_freq = smu_v11_0_get_current_clk_freq, + .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, + .start_thermal_control = smu_v11_0_start_thermal_control, + .stop_thermal_control = smu_v11_0_stop_thermal_control, + .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk, + .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, + .get_fan_control_mode = smu_v11_0_get_fan_control_mode, + .set_fan_control_mode = smu_v11_0_set_fan_control_mode, + .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, + .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, + .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, + .gfx_off_control = smu_v11_0_gfx_off_control, + .register_irq_handler = smu_v11_0_register_irq_handler, + .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, + .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, + .baco_is_support= smu_v11_0_baco_is_support, + .baco_get_state = smu_v11_0_baco_get_state, + .baco_set_state = smu_v11_0_baco_set_state, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, + .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, + .override_pcie_parameters = smu_v11_0_override_pcie_parameters, + .get_pptable_power_limit = arcturus_get_pptable_power_limit, +}; + +void arcturus_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &arcturus_ppt_funcs; +} diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.h b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.h new file mode 100644 index 000000000000..d756b16924b8 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.h @@ -0,0 +1,72 @@ +/* + * Copyright 2019 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 __ARCTURUS_PPT_H__ +#define __ARCTURUS_PPT_H__ + +#define ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL 0x3 +#define ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL 0x3 +#define ARCTURUS_UMD_PSTATE_MCLK_LEVEL 0x2 + +#define MAX_DPM_NUMBER 16 +#define MAX_PCIE_CONF 2 + +struct arcturus_dpm_level { + bool enabled; + uint32_t value; + uint32_t param1; +}; + +struct arcturus_dpm_state { + uint32_t soft_min_level; + uint32_t soft_max_level; + uint32_t hard_min_level; + uint32_t hard_max_level; +}; + +struct arcturus_single_dpm_table { + uint32_t count; + struct arcturus_dpm_state dpm_state; + struct arcturus_dpm_level dpm_levels[MAX_DPM_NUMBER]; +}; + +struct arcturus_pcie_table { + uint16_t count; + uint8_t pcie_gen[MAX_PCIE_CONF]; + uint8_t pcie_lane[MAX_PCIE_CONF]; + uint32_t lclk[MAX_PCIE_CONF]; +}; + +struct arcturus_dpm_table { + struct arcturus_single_dpm_table soc_table; + struct arcturus_single_dpm_table gfx_table; + struct arcturus_single_dpm_table mem_table; + struct arcturus_single_dpm_table eclk_table; + struct arcturus_single_dpm_table vclk_table; + struct arcturus_single_dpm_table dclk_table; + struct arcturus_single_dpm_table fclk_table; + struct arcturus_pcie_table pcie_table; +}; + +extern void arcturus_set_ppt_funcs(struct smu_context *smu); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile index cc63705920dc..2773966ae434 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/Makefile @@ -36,7 +36,8 @@ HARDWARE_MGR = hwmgr.o processpptables.o \ pp_overdriver.o smu_helper.o \ vega20_processpptables.o vega20_hwmgr.o vega20_powertune.o \ vega20_thermal.o common_baco.o vega10_baco.o vega20_baco.o \ - vega12_baco.o smu9_baco.o + vega12_baco.o smu9_baco.o tonga_baco.o polaris_baco.o fiji_baco.o \ + ci_baco.o smu7_baco.o AMD_PP_HWMGR = $(addprefix $(AMD_PP_PATH)/hwmgr/,$(HARDWARE_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.c new file mode 100644 index 000000000000..3be40114e63d --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.c @@ -0,0 +1,195 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "ci_baco.h" + +#include "gmc/gmc_7_1_d.h" +#include "gmc/gmc_7_1_sh_mask.h" + +#include "bif/bif_4_1_d.h" +#include "bif/bif_4_1_sh_mask.h" + +#include "dce/dce_8_0_d.h" +#include "dce/dce_8_0_sh_mask.h" + +#include "smu/smu_7_0_1_d.h" +#include "smu/smu_7_0_1_sh_mask.h" + +#include "gca/gfx_7_2_d.h" +#include "gca/gfx_7_2_sh_mask.h" + +static const struct baco_cmd_entry gpio_tbl[] = +{ + { CMD_WRITE, mmGPIOPAD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PU_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_MASK, 0, 0, 0, 0xff77ffff }, + { CMD_WRITE, mmDC_GPIO_DVODATA_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmDC_GPIO_DVODATA_MASK, 0, 0, 0, 0xffffffff }, + { CMD_WRITE, mmDC_GPIO_GENERIC_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_GENERIC_MASK, 0, 0, 0, 0x03333333 }, + { CMD_WRITE, mmDC_GPIO_SYNCA_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_SYNCA_MASK, 0, 0, 0, 0x00001111 } +}; + +static const struct baco_cmd_entry enable_fb_req_rej_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0300024 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_WRITE, mmBIF_FB_EN, 0, 0, 0, 0x0 } +}; + +static const struct baco_cmd_entry use_bclk_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x4000000, 0x1a, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL_MASK, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_MCLK_SEL_MASK, MPLL_CNTL_MODE__MPLL_MCLK_SEL__SHIFT, 0, 0x0 } +}; + +static const struct baco_cmd_entry turn_off_plls_tbl[] = +{ + { CMD_READMODIFYWRITE, mmDISPPLL_BG_CNTL, DISPPLL_BG_CNTL__DISPPLL_BG_PDN_MASK, DISPPLL_BG_CNTL__DISPPLL_BG_PDN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL_DC }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_DC__OSC_EN_MASK, CG_CLKPIN_CNTL_DC__OSC_EN__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_DC__XTALIN_SEL_MASK, CG_CLKPIN_CNTL_DC__XTALIN_SEL__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmPLL_CNTL, PLL_CNTL__PLL_RESET_MASK, PLL_CNTL__PLL_RESET__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmPLL_CNTL, PLL_CNTL__PLL_POWER_DOWN_MASK, PLL_CNTL__PLL_POWER_DOWN__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmPLL_CNTL, PLL_CNTL__PLL_BYPASS_CAL_MASK, PLL_CNTL__PLL_BYPASS_CAL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_RESET_MASK, CG_SPLL_FUNC_CNTL__SPLL_RESET__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_PWRON_MASK, CG_SPLL_FUNC_CNTL__SPLL_PWRON__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x2000000, 0x19, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x8000000, 0x1b, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__GLOBAL_MPLL_RESET_MASK, MPLL_CNTL_MODE__GLOBAL_MPLL_RESET__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmMPLL_CONTROL, 0, 0, 0, 0x00000006 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY0_D0, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY0_D1, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY1_D0, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY1_D1, 0, 0, 0, 0x00007740 }, + { CMD_READMODIFYWRITE, mmMCLK_PWRMGT_CNTL, MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK, MCLK_PWRMGT_CNTL__MRDCK0_PDNB__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMCLK_PWRMGT_CNTL, MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK, MCLK_PWRMGT_CNTL__MRDCK1_PDNB__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_CNTL_2, MC_SEQ_CNTL_2__DRST_PU_MASK, MC_SEQ_CNTL_2__DRST_PU__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_CNTL_2, MC_SEQ_CNTL_2__DRST_PD_MASK, MC_SEQ_CNTL_2__DRST_PD__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN_MASK, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x4 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMISC_CLK_CTRL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL_MASK, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__ZCLK_SEL_MASK, MISC_CLK_CTRL__ZCLK_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__DFT_SMS_PG_CLK_SEL_MASK, MISC_CLK_CTRL__DFT_SMS_PG_CLK_SEL__SHIFT, 0, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixTHM_CLK_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__CMON_CLK_SEL_MASK, THM_CLK_CNTL__CMON_CLK_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__TMON_CLK_SEL_MASK, THM_CLK_CNTL__TMON_CLK_SEL__SHIFT, 0, 0x2 } +}; + +static const struct baco_cmd_entry enter_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, 0, 5, 0x02 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, 0, 5, 0x08 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x40 } +}; + +#define BACO_CNTL__PWRGOOD_MASK BACO_CNTL__PWRGOOD_GPIO_MASK+BACO_CNTL__PWRGOOD_MEM_MASK+BACO_CNTL__PWRGOOD_DVO_MASK + +static const struct baco_cmd_entry exit_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x00 }, + { CMD_DELAY_MS, 0, 0, 0, 20, 0 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_BF_MASK, 0, 0xffffffff, 0x20 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_MASK, 0, 5, 0x1c }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__RCU_BIF_CONFIG_DONE_MASK, 0, 5, 0x10 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x00 } +}; + +static const struct baco_cmd_entry clean_baco_tbl[] = +{ + { CMD_WRITE, mmBIOS_SCRATCH_6, 0, 0, 0, 0 }, + { CMD_WRITE, mmCP_PFP_UCODE_ADDR, 0, 0, 0, 0 } +}; + +int ci_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) +{ + enum BACO_STATE cur_state; + + smu7_baco_get_state(hwmgr, &cur_state); + + if (cur_state == state) + /* aisc already in the target state */ + return 0; + + if (state == BACO_STATE_IN) { + baco_program_registers(hwmgr, gpio_tbl, ARRAY_SIZE(gpio_tbl)); + baco_program_registers(hwmgr, enable_fb_req_rej_tbl, + ARRAY_SIZE(enable_fb_req_rej_tbl)); + baco_program_registers(hwmgr, use_bclk_tbl, ARRAY_SIZE(use_bclk_tbl)); + baco_program_registers(hwmgr, turn_off_plls_tbl, + ARRAY_SIZE(turn_off_plls_tbl)); + if (baco_program_registers(hwmgr, enter_baco_tbl, + ARRAY_SIZE(enter_baco_tbl))) + return 0; + + } else if (state == BACO_STATE_OUT) { + /* HW requires at least 20ms between regulator off and on */ + msleep(20); + /* Execute Hardware BACO exit sequence */ + if (baco_program_registers(hwmgr, exit_baco_tbl, + ARRAY_SIZE(exit_baco_tbl))) { + if (baco_program_registers(hwmgr, clean_baco_tbl, + ARRAY_SIZE(clean_baco_tbl))) + return 0; + } + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.h new file mode 100644 index 000000000000..17041f187020 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/ci_baco.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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 __CI_BACO_H__ +#define __CI_BACO_H__ +#include "smu7_baco.h" + +extern int ci_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c index 9c57c1f67749..1c73776bd606 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.c @@ -79,6 +79,25 @@ static bool baco_cmd_handler(struct pp_hwmgr *hwmgr, u32 command, u32 reg, u32 m return ret; } +bool baco_program_registers(struct pp_hwmgr *hwmgr, + const struct baco_cmd_entry *entry, + const u32 array_size) +{ + u32 i, reg = 0; + + for (i = 0; i < array_size; i++) { + if ((entry[i].cmd == CMD_WRITE) || + (entry[i].cmd == CMD_READMODIFYWRITE) || + (entry[i].cmd == CMD_WAITFOR)) + reg = entry[i].reg_offset; + if (!baco_cmd_handler(hwmgr, entry[i].cmd, reg, entry[i].mask, + entry[i].shift, entry[i].val, entry[i].timeout)) + return false; + } + + return true; +} + bool soc15_baco_program_registers(struct pp_hwmgr *hwmgr, const struct soc15_baco_cmd_entry *entry, const u32 array_size) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h index 95296c916f4e..8393eb62706d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/common_baco.h @@ -33,6 +33,15 @@ enum baco_cmd_type { CMD_DELAY_US, }; +struct baco_cmd_entry { + enum baco_cmd_type cmd; + uint32_t reg_offset; + uint32_t mask; + uint32_t shift; + uint32_t timeout; + uint32_t val; +}; + struct soc15_baco_cmd_entry { enum baco_cmd_type cmd; uint32_t hwip; @@ -44,6 +53,10 @@ struct soc15_baco_cmd_entry { uint32_t timeout; uint32_t val; }; + +extern bool baco_program_registers(struct pp_hwmgr *hwmgr, + const struct baco_cmd_entry *entry, + const u32 array_size); extern bool soc15_baco_program_registers(struct pp_hwmgr *hwmgr, const struct soc15_baco_cmd_entry *entry, const u32 array_size); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.c new file mode 100644 index 000000000000..c0368f2dfb21 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.c @@ -0,0 +1,196 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "fiji_baco.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 "dce/dce_10_0_d.h" +#include "dce/dce_10_0_sh_mask.h" + +#include "smu/smu_7_1_3_d.h" +#include "smu/smu_7_1_3_sh_mask.h" + + +static const struct baco_cmd_entry gpio_tbl[] = +{ + { CMD_WRITE, mmGPIOPAD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PU_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_MASK, 0, 0, 0, 0xff77ffff }, + { CMD_WRITE, mmDC_GPIO_DVODATA_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmDC_GPIO_DVODATA_MASK, 0, 0, 0, 0xffffffff }, + { CMD_WRITE, mmDC_GPIO_GENERIC_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_GENERIC_MASK, 0, 0, 0, 0x03333333 }, + { CMD_WRITE, mmDC_GPIO_SYNCA_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_SYNCA_MASK, 0, 0, 0, 0x00001111 } +}; + +static const struct baco_cmd_entry enable_fb_req_rej_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0300024 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_WRITE, mmBIF_FB_EN, 0, 0, 0, 0x0 } +}; + +static const struct baco_cmd_entry use_bclk_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x4000000, 0x1a, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x2 } +}; + +static const struct baco_cmd_entry turn_off_plls_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_RESET_MASK, CG_SPLL_FUNC_CNTL__SPLL_RESET__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_PWRON_MASK, CG_SPLL_FUNC_CNTL__SPLL_PWRON__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x2000000, 0x19, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x8000000, 0x1b, 0, 0x0 } +}; + +static const struct baco_cmd_entry clk_req_b_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN_MASK, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x4 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMISC_CLK_CTRL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL_MASK, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__ZCLK_SEL_MASK, MISC_CLK_CTRL__ZCLK_SEL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL__BCLK_AS_XCLK_MASK, CG_CLKPIN_CNTL__BCLK_AS_XCLK__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixTHM_CLK_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__CMON_CLK_SEL_MASK, THM_CLK_CNTL__CMON_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__TMON_CLK_SEL_MASK, THM_CLK_CNTL__TMON_CLK_SEL__SHIFT, 0, 0x1 } +}; + +static const struct baco_cmd_entry enter_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, 0, 5, 0x40000 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, 0, 5, 0x02 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, 0, 5, 0x08 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x40 } +}; + +#define BACO_CNTL__PWRGOOD_MASK BACO_CNTL__PWRGOOD_GPIO_MASK+BACO_CNTL__PWRGOOD_MEM_MASK+BACO_CNTL__PWRGOOD_DVO_MASK + +static const struct baco_cmd_entry exit_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_BF_MASK, 0, 0xffffffff, 0x200 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_MASK, 0, 5, 0x1c00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__RCU_BIF_CONFIG_DONE_MASK, 0, 5, 0x100 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x00 } +}; + +static const struct baco_cmd_entry clean_baco_tbl[] = +{ + { CMD_WRITE, mmBIOS_SCRATCH_0, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_1, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_2, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_3, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_4, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_5, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_6, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_7, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_8, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_9, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_10, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_11, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_12, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_13, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_14, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_15, 0, 0, 0, 0 } +}; + +int fiji_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) +{ + enum BACO_STATE cur_state; + + smu7_baco_get_state(hwmgr, &cur_state); + + if (cur_state == state) + /* aisc already in the target state */ + return 0; + + if (state == BACO_STATE_IN) { + baco_program_registers(hwmgr, gpio_tbl, ARRAY_SIZE(gpio_tbl)); + baco_program_registers(hwmgr, enable_fb_req_rej_tbl, + ARRAY_SIZE(enable_fb_req_rej_tbl)); + baco_program_registers(hwmgr, use_bclk_tbl, ARRAY_SIZE(use_bclk_tbl)); + baco_program_registers(hwmgr, turn_off_plls_tbl, + ARRAY_SIZE(turn_off_plls_tbl)); + baco_program_registers(hwmgr, clk_req_b_tbl, ARRAY_SIZE(clk_req_b_tbl)); + if (baco_program_registers(hwmgr, enter_baco_tbl, + ARRAY_SIZE(enter_baco_tbl))) + return 0; + + } else if (state == BACO_STATE_OUT) { + /* HW requires at least 20ms between regulator off and on */ + msleep(20); + /* Execute Hardware BACO exit sequence */ + if (baco_program_registers(hwmgr, exit_baco_tbl, + ARRAY_SIZE(exit_baco_tbl))) { + if (baco_program_registers(hwmgr, clean_baco_tbl, + ARRAY_SIZE(clean_baco_tbl))) + return 0; + } + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.h new file mode 100644 index 000000000000..47f402900bdb --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/fiji_baco.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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_BACO_H__ +#define __FIJI_BACO_H__ +#include "smu7_baco.h" + +extern int fiji_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c index cc57fb953e62..9454ab50f9a1 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hardwaremanager.c @@ -81,8 +81,8 @@ int phm_enable_dynamic_state_management(struct pp_hwmgr *hwmgr) adev = hwmgr->adev; /* Skip for suspend/resume case */ - if (smum_is_dpm_running(hwmgr) && !amdgpu_passthrough(adev) - && adev->in_suspend) { + if (!hwmgr->pp_one_vf && smum_is_dpm_running(hwmgr) + && !amdgpu_passthrough(adev) && adev->in_suspend) { pr_info("dpm has been enabled\n"); return 0; } @@ -99,6 +99,9 @@ int phm_disable_dynamic_state_management(struct pp_hwmgr *hwmgr) PHM_FUNC_CHECK(hwmgr); + if (!hwmgr->not_vf) + return 0; + if (!smum_is_dpm_running(hwmgr)) { pr_info("dpm has been disabled\n"); return 0; @@ -200,6 +203,9 @@ int phm_stop_thermal_controller(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->stop_thermal_controller == NULL) return -EINVAL; @@ -237,6 +243,9 @@ int phm_start_thermal_controller(struct pp_hwmgr *hwmgr) TEMP_RANGE_MAX}; struct amdgpu_device *adev = hwmgr->adev; + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->get_thermal_temperature_range) hwmgr->hwmgr_func->get_thermal_temperature_range( hwmgr, &range); @@ -263,6 +272,8 @@ int phm_start_thermal_controller(struct pp_hwmgr *hwmgr) bool phm_check_smc_update_required_for_display_configuration(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); + if (hwmgr->pp_one_vf) + return false; if (hwmgr->hwmgr_func->check_smc_update_required_for_display_configuration == NULL) return false; @@ -482,6 +493,9 @@ int phm_disable_smc_firmware_ctf(struct pp_hwmgr *hwmgr) { PHM_FUNC_CHECK(hwmgr); + if (!hwmgr->not_vf) + return 0; + if (hwmgr->hwmgr_func->disable_smc_firmware_ctf == NULL) return -EINVAL; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c index a24beaa4fb01..f48fdc7f0382 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/hwmgr.c @@ -81,6 +81,8 @@ static void hwmgr_init_workload_prority(struct pp_hwmgr *hwmgr) int hwmgr_early_init(struct pp_hwmgr *hwmgr) { + struct amdgpu_device *adev; + if (!hwmgr) return -EINVAL; @@ -94,8 +96,11 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) hwmgr_init_workload_prority(hwmgr); hwmgr->gfxoff_state_changed_by_workload = false; + adev = hwmgr->adev; + switch (hwmgr->chip_family) { case AMDGPU_FAMILY_CI: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; hwmgr->smumgr_funcs = &ci_smu_funcs; ci_set_asic_special_caps(hwmgr); hwmgr->feature_mask &= ~(PP_VBI_TIME_SUPPORT_MASK | @@ -106,12 +111,14 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) smu7_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_CZ: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; hwmgr->od_enabled = false; hwmgr->smumgr_funcs = &smu8_smu_funcs; hwmgr->feature_mask &= ~PP_GFXOFF_MASK; smu8_init_function_pointers(hwmgr); break; case AMDGPU_FAMILY_VI: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; hwmgr->feature_mask &= ~PP_GFXOFF_MASK; switch (hwmgr->chip_id) { case CHIP_TOPAZ: @@ -153,6 +160,7 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) case AMDGPU_FAMILY_AI: switch (hwmgr->chip_id) { case CHIP_VEGA10: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; hwmgr->feature_mask &= ~PP_GFXOFF_MASK; hwmgr->smumgr_funcs = &vega10_smu_funcs; vega10_hwmgr_init(hwmgr); @@ -162,6 +170,7 @@ int hwmgr_early_init(struct pp_hwmgr *hwmgr) vega12_hwmgr_init(hwmgr); break; case CHIP_VEGA20: + adev->pm.pp_feature &= ~PP_GFXOFF_MASK; hwmgr->feature_mask &= ~PP_GFXOFF_MASK; hwmgr->smumgr_funcs = &vega20_smu_funcs; vega20_hwmgr_init(hwmgr); @@ -212,6 +221,9 @@ int hwmgr_hw_init(struct pp_hwmgr *hwmgr) { int ret = 0; + hwmgr->pp_one_vf = amdgpu_sriov_is_pp_one_vf((struct amdgpu_device *)hwmgr->adev); + hwmgr->pm_en = (amdgpu_dpm && (hwmgr->not_vf || hwmgr->pp_one_vf)) + ? true : false; if (!hwmgr->pm_en) return 0; @@ -270,7 +282,7 @@ err: int hwmgr_hw_fini(struct pp_hwmgr *hwmgr) { - if (!hwmgr || !hwmgr->pm_en) + if (!hwmgr || !hwmgr->pm_en || !hwmgr->not_vf) return 0; phm_stop_thermal_controller(hwmgr); @@ -290,7 +302,7 @@ int hwmgr_suspend(struct pp_hwmgr *hwmgr) { int ret = 0; - if (!hwmgr || !hwmgr->pm_en) + if (!hwmgr || !hwmgr->pm_en || !hwmgr->not_vf) return 0; phm_disable_smc_firmware_ctf(hwmgr); @@ -312,7 +324,7 @@ int hwmgr_resume(struct pp_hwmgr *hwmgr) if (!hwmgr) return -EINVAL; - if (!hwmgr->pm_en) + if (!hwmgr->not_vf || !hwmgr->pm_en) return 0; ret = phm_setup_asic(hwmgr); @@ -356,6 +368,8 @@ int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, switch (task_id) { case AMD_PP_TASK_DISPLAY_CONFIG_CHANGE: + if (!hwmgr->not_vf) + return ret; ret = phm_pre_display_configuration_changed(hwmgr); if (ret) return ret; @@ -372,6 +386,8 @@ int hwmgr_handle_task(struct pp_hwmgr *hwmgr, enum amd_pp_task task_id, enum PP_StateUILabel requested_ui_label; struct pp_power_state *requested_ps = NULL; + if (!hwmgr->not_vf) + return ret; if (user_state == NULL) { ret = -EINVAL; break; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.c new file mode 100644 index 000000000000..8f8e296f2fe9 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.c @@ -0,0 +1,222 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "polaris_baco.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 "dce/dce_11_0_d.h" +#include "dce/dce_11_0_sh_mask.h" + +#include "smu/smu_7_1_3_d.h" +#include "smu/smu_7_1_3_sh_mask.h" + +static const struct baco_cmd_entry gpio_tbl[] = +{ + { CMD_WRITE, mmGPIOPAD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PU_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_MASK, 0, 0, 0, 0xff77ffff }, + { CMD_WRITE, mmDC_GPIO_DVODATA_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmDC_GPIO_DVODATA_MASK, 0, 0, 0, 0xffffffff }, + { CMD_WRITE, mmDC_GPIO_GENERIC_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_GENERIC_MASK, 0, 0, 0, 0x03333333 }, + { CMD_WRITE, mmDC_GPIO_SYNCA_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_SYNCA_MASK, 0, 0, 0, 0x00001111 } +}; + +static const struct baco_cmd_entry enable_fb_req_rej_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0300024 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_WRITE, mmBIF_FB_EN, 0, 0, 0, 0x0 } +}; + +static const struct baco_cmd_entry use_bclk_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x4000000, 0x1a, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixGCK_DFS_BYPASS_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, GCK_DFS_BYPASS_CNTL__BYPASSACLK_MASK, GCK_DFS_BYPASS_CNTL__BYPASSACLK__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL_MASK, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_MCLK_SEL_MASK, MPLL_CNTL_MODE__MPLL_MCLK_SEL__SHIFT, 0, 0x0 } +}; + +static const struct baco_cmd_entry turn_off_plls_tbl[] = +{ + { CMD_READMODIFYWRITE, mmDC_GPIO_PAD_STRENGTH_1, DC_GPIO_PAD_STRENGTH_1__GENLK_STRENGTH_SP_MASK, DC_GPIO_PAD_STRENGTH_1__GENLK_STRENGTH_SP__SHIFT, 0, 0x1 }, + { CMD_DELAY_US, 0, 0, 0, 1, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_DRAM, MC_SEQ_DRAM__RST_CTL_MASK, MC_SEQ_DRAM__RST_CTL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC05002B0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x10, 0x4, 0, 0x1 }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, 0x10, 0, 1, 0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC050032C }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x10, 0x4, 0, 0x1 }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, 0x10, 0, 1, 0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500080 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_READMODIFYWRITE, 0xda2, 0x40, 0x6, 0, 0x0 }, + { CMD_DELAY_US, 0, 0, 0, 3, 0x0 }, + { CMD_READMODIFYWRITE, 0xda2, 0x8, 0x3, 0, 0x0 }, + { CMD_READMODIFYWRITE, 0xda2, 0x3fff00, 0x8, 0, 0x32 }, + { CMD_DELAY_US, 0, 0, 0, 3, 0x0 }, + { CMD_READMODIFYWRITE, mmMPLL_FUNC_CNTL_2, MPLL_FUNC_CNTL_2__ISO_DIS_P_MASK, MPLL_FUNC_CNTL_2__ISO_DIS_P__SHIFT, 0, 0x0 }, + { CMD_DELAY_US, 0, 0, 0, 5, 0x0 } +}; + +static const struct baco_cmd_entry clk_req_b_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixTHM_CLK_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__CMON_CLK_SEL_MASK, THM_CLK_CNTL__CMON_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__TMON_CLK_SEL_MASK, THM_CLK_CNTL__TMON_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMISC_CLK_CTRL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL_MASK, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__ZCLK_SEL_MASK, MISC_CLK_CTRL__ZCLK_SEL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL__BCLK_AS_XCLK_MASK, CG_CLKPIN_CNTL__BCLK_AS_XCLK__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN_MASK, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x4 } +}; + +static const struct baco_cmd_entry enter_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, 0, 5, 0x40000 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, 0, 5, 0x02 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, 0, 5, 0x08 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x40 } +}; + +#define BACO_CNTL__PWRGOOD_MASK BACO_CNTL__PWRGOOD_GPIO_MASK+BACO_CNTL__PWRGOOD_MEM_MASK+BACO_CNTL__PWRGOOD_DVO_MASK + +static const struct baco_cmd_entry exit_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_BF_MASK, 0, 0xffffffff, 0x200 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_MASK, 0, 5, 0x1c00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__RCU_BIF_CONFIG_DONE_MASK, 0, 5, 0x100 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x00 } +}; + +static const struct baco_cmd_entry clean_baco_tbl[] = +{ + { CMD_WRITE, mmBIOS_SCRATCH_6, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_7, 0, 0, 0, 0 } +}; + +static const struct baco_cmd_entry use_bclk_tbl_vg[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x4000000, 0x1a, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixGCK_DFS_BYPASS_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, GCK_DFS_BYPASS_CNTL__BYPASSACLK_MASK, GCK_DFS_BYPASS_CNTL__BYPASSACLK__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x2 } +}; + +static const struct baco_cmd_entry turn_off_plls_tbl_vg[] = +{ + { CMD_READMODIFYWRITE, mmDC_GPIO_PAD_STRENGTH_1, DC_GPIO_PAD_STRENGTH_1__GENLK_STRENGTH_SP_MASK, DC_GPIO_PAD_STRENGTH_1__GENLK_STRENGTH_SP__SHIFT, 0, 0x1 }, + { CMD_DELAY_US, 0, 0, 0, 1, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_DRAM, MC_SEQ_DRAM__RST_CTL_MASK, MC_SEQ_DRAM__RST_CTL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC05002B0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x10, 0x4, 0, 0x1 }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, 0x10, 0, 1, 0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC050032C }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x10, 0x4, 0, 0x1 }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, 0x10, 0, 1, 0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500080 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_DELAY_US, 0, 0, 0, 3, 0x0 }, + { CMD_DELAY_US, 0, 0, 0, 3, 0x0 }, + { CMD_DELAY_US, 0, 0, 0, 5, 0x0 } +}; + +int polaris_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) +{ + enum BACO_STATE cur_state; + + smu7_baco_get_state(hwmgr, &cur_state); + + if (cur_state == state) + /* aisc already in the target state */ + return 0; + + if (state == BACO_STATE_IN) { + baco_program_registers(hwmgr, gpio_tbl, ARRAY_SIZE(gpio_tbl)); + baco_program_registers(hwmgr, enable_fb_req_rej_tbl, + ARRAY_SIZE(enable_fb_req_rej_tbl)); + if (hwmgr->chip_id == CHIP_VEGAM) { + baco_program_registers(hwmgr, use_bclk_tbl_vg, ARRAY_SIZE(use_bclk_tbl_vg)); + baco_program_registers(hwmgr, turn_off_plls_tbl_vg, + ARRAY_SIZE(turn_off_plls_tbl_vg)); + } else { + baco_program_registers(hwmgr, use_bclk_tbl, ARRAY_SIZE(use_bclk_tbl)); + baco_program_registers(hwmgr, turn_off_plls_tbl, + ARRAY_SIZE(turn_off_plls_tbl)); + } + baco_program_registers(hwmgr, clk_req_b_tbl, ARRAY_SIZE(clk_req_b_tbl)); + if (baco_program_registers(hwmgr, enter_baco_tbl, + ARRAY_SIZE(enter_baco_tbl))) + return 0; + + } else if (state == BACO_STATE_OUT) { + /* HW requires at least 20ms between regulator off and on */ + msleep(20); + /* Execute Hardware BACO exit sequence */ + if (baco_program_registers(hwmgr, exit_baco_tbl, + ARRAY_SIZE(exit_baco_tbl))) { + if (baco_program_registers(hwmgr, clean_baco_tbl, + ARRAY_SIZE(clean_baco_tbl))) + return 0; + } + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.h new file mode 100644 index 000000000000..87a5fa0a157a --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/polaris_baco.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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 __POLARIS_BACO_H__ +#define __POLARIS_BACO_H__ +#include "smu7_baco.h" + +extern int polaris_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c index 6bf48934fdc4..31a32a79cfc2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/pp_psm.c @@ -262,20 +262,22 @@ int psm_adjust_power_state_dynamic(struct pp_hwmgr *hwmgr, bool skip_display_set uint32_t index; long workload; - if (!skip_display_settings) - phm_display_configuration_changed(hwmgr); - - if (hwmgr->ps) - power_state_management(hwmgr, new_ps); - else - /* - * for vega12/vega20 which does not support power state manager - * DAL clock limits should also be honoured - */ - phm_apply_clock_adjust_rules(hwmgr); - - if (!skip_display_settings) - phm_notify_smc_display_config_after_ps_adjustment(hwmgr); + if (hwmgr->not_vf) { + if (!skip_display_settings) + phm_display_configuration_changed(hwmgr); + + if (hwmgr->ps) + power_state_management(hwmgr, new_ps); + else + /* + * for vega12/vega20 which does not support power state manager + * DAL clock limits should also be honoured + */ + phm_apply_clock_adjust_rules(hwmgr); + + if (!skip_display_settings) + phm_notify_smc_display_config_after_ps_adjustment(hwmgr); + } if (!phm_force_dpm_levels(hwmgr, hwmgr->request_dpm_level)) hwmgr->dpm_level = hwmgr->request_dpm_level; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c index 18e780f566fa..689072a312a7 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu10_hwmgr.c @@ -1026,12 +1026,15 @@ static int smu10_get_clock_by_type_with_latency(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; - clocks->data[i].latency_in_us = latency_required ? - smu10_get_mem_latency(hwmgr, - pclk_vol_table->entries[i].clk) : - 0; - clocks->num_levels++; + if (pclk_vol_table->entries[i].clk) { + clocks->data[clocks->num_levels].clocks_in_khz = + pclk_vol_table->entries[i].clk * 10; + clocks->data[clocks->num_levels].latency_in_us = latency_required ? + smu10_get_mem_latency(hwmgr, + pclk_vol_table->entries[i].clk) : + 0; + clocks->num_levels++; + } } return 0; @@ -1077,9 +1080,11 @@ static int smu10_get_clock_by_type_with_voltage(struct pp_hwmgr *hwmgr, clocks->num_levels = 0; for (i = 0; i < pclk_vol_table->count; i++) { - clocks->data[i].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; - clocks->data[i].voltage_in_mv = pclk_vol_table->entries[i].vol; - clocks->num_levels++; + if (pclk_vol_table->entries[i].clk) { + clocks->data[clocks->num_levels].clocks_in_khz = pclk_vol_table->entries[i].clk * 10; + clocks->data[clocks->num_levels].voltage_in_mv = pclk_vol_table->entries[i].vol; + clocks->num_levels++; + } } return 0; @@ -1151,12 +1156,11 @@ static int smu10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, struct smu10_hwmgr *data = hwmgr->backend; struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_ranges; Watermarks_t *table = &(data->water_marks_table); - int result = 0; smu_set_watermarks_for_clocks_ranges(table,wm_with_clock_ranges); smum_smc_table_manager(hwmgr, (uint8_t *)table, (uint16_t)SMU10_WMTABLE, false); data->water_marks_exist = true; - return result; + return 0; } static int smu10_smus_notify_pwe(struct pp_hwmgr *hwmgr) @@ -1311,6 +1315,12 @@ static int smu10_set_power_profile_mode(struct pp_hwmgr *hwmgr, long *input, uin return 0; } +static int smu10_asic_reset(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mode) +{ + return smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_DeviceDriverReset, + mode); +} static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .backend_init = smu10_hwmgr_backend_init, @@ -1355,6 +1365,7 @@ static const struct pp_hwmgr_func smu10_hwmgr_funcs = { .set_hard_min_fclk_by_freq = smu10_set_hard_min_fclk_by_freq, .get_power_profile_mode = smu10_get_power_profile_mode, .set_power_profile_mode = smu10_set_power_profile_mode, + .asic_reset = smu10_asic_reset, }; int smu10_init_function_pointers(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.c new file mode 100644 index 000000000000..044cda005aed --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.c @@ -0,0 +1,91 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "smu7_baco.h" +#include "tonga_baco.h" +#include "fiji_baco.h" +#include "polaris_baco.h" +#include "ci_baco.h" + +#include "bif/bif_5_0_d.h" +#include "bif/bif_5_0_sh_mask.h" + +#include "smu/smu_7_1_2_d.h" +#include "smu/smu_7_1_2_sh_mask.h" + +int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); + uint32_t reg; + + *cap = false; + if (!phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_BACO)) + return 0; + + reg = RREG32(mmCC_BIF_BX_FUSESTRAP0); + + if (reg & CC_BIF_BX_FUSESTRAP0__STRAP_BIF_PX_CAPABLE_MASK) + *cap = true; + + return 0; +} + +int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); + uint32_t reg; + + reg = RREG32(mmBACO_CNTL); + + if (reg & BACO_CNTL__BACO_MODE_MASK) + /* gfx has already entered BACO state */ + *state = BACO_STATE_IN; + else + *state = BACO_STATE_OUT; + return 0; +} + +int smu7_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) +{ + struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); + + switch (adev->asic_type) { + case CHIP_TOPAZ: + case CHIP_TONGA: + return tonga_baco_set_state(hwmgr, state); + case CHIP_FIJI: + return fiji_baco_set_state(hwmgr, state); + case CHIP_POLARIS10: + case CHIP_POLARIS11: + case CHIP_POLARIS12: + case CHIP_VEGAM: + return polaris_baco_set_state(hwmgr, state); +#ifdef CONFIG_DRM_AMDGPU_CIK + case CHIP_BONAIRE: + case CHIP_HAWAII: + return ci_baco_set_state(hwmgr, state); +#endif + default: + return -EINVAL; + } +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.h new file mode 100644 index 000000000000..be0d98abb536 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_baco.h @@ -0,0 +1,32 @@ +/* + * Copyright 2019 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 __SMU7_BACO_H__ +#define __SMU7_BACO_H__ +#include "hwmgr.h" +#include "common_baco.h" + +extern int smu7_baco_get_capability(struct pp_hwmgr *hwmgr, bool *cap); +extern int smu7_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state); +extern int smu7_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 487aeee1cf8a..bf04cfefb283 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -48,6 +48,7 @@ #include "smu7_clockpowergating.h" #include "processpptables.h" #include "pp_thermal.h" +#include "smu7_baco.h" #include "ivsrcid/ivsrcid_vislands30.h" @@ -719,7 +720,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) data->dpm_table.vddc_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; data->dpm_table.vddc_table.dpm_levels[i].param1 = std_voltage_table->entries[i].Leakage; /* param1 is for corresponding std voltage */ - data->dpm_table.vddc_table.dpm_levels[i].enabled = 1; + data->dpm_table.vddc_table.dpm_levels[i].enabled = true; } data->dpm_table.vddc_table.count = allowed_vdd_sclk_table->count; @@ -729,7 +730,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) /* Initialize Vddci DPM table based on allow Mclk values */ for (i = 0; i < allowed_vdd_mclk_table->count; i++) { data->dpm_table.vddci_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; - data->dpm_table.vddci_table.dpm_levels[i].enabled = 1; + data->dpm_table.vddci_table.dpm_levels[i].enabled = true; } data->dpm_table.vddci_table.count = allowed_vdd_mclk_table->count; } @@ -743,7 +744,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr) */ for (i = 0; i < allowed_vdd_mclk_table->count; i++) { data->dpm_table.mvdd_table.dpm_levels[i].value = allowed_vdd_mclk_table->entries[i].v; - data->dpm_table.mvdd_table.dpm_levels[i].enabled = 1; + data->dpm_table.mvdd_table.dpm_levels[i].enabled = true; } data->dpm_table.mvdd_table.count = allowed_vdd_mclk_table->count; } @@ -1994,7 +1995,6 @@ static int smu7_sort_lookup_table(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_voltage_lookup_table *lookup_table) { uint32_t table_size, i, j; - struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record; table_size = lookup_table->count; PP_ASSERT_WITH_CODE(0 != lookup_table->count, @@ -2005,9 +2005,8 @@ static int smu7_sort_lookup_table(struct pp_hwmgr *hwmgr, for (j = i + 1; j > 0; j--) { if (lookup_table->entries[j].us_vdd < lookup_table->entries[j - 1].us_vdd) { - tmp_voltage_lookup_record = lookup_table->entries[j - 1]; - lookup_table->entries[j - 1] = lookup_table->entries[j]; - lookup_table->entries[j] = tmp_voltage_lookup_record; + swap(lookup_table->entries[j - 1], + lookup_table->entries[j]); } } } @@ -2956,9 +2955,10 @@ static int smu7_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, if (hwmgr->display_config->num_display == 0) disable_mclk_switching = false; else - disable_mclk_switching = ((1 < hwmgr->display_config->num_display) || - disable_mclk_switching_for_frame_lock || - smu7_vblank_too_short(hwmgr, hwmgr->display_config->min_vblank_time)); + disable_mclk_switching = ((1 < hwmgr->display_config->num_display) && + !hwmgr->display_config->multi_monitor_in_sync) || + disable_mclk_switching_for_frame_lock || + smu7_vblank_too_short(hwmgr, hwmgr->display_config->min_vblank_time); sclk = smu7_ps->performance_levels[0].engine_clock; mclk = smu7_ps->performance_levels[0].memory_clock; @@ -3477,18 +3477,31 @@ static int smu7_get_pp_table_entry(struct pp_hwmgr *hwmgr, static int smu7_get_gpu_power(struct pp_hwmgr *hwmgr, u32 *query) { + struct amdgpu_device *adev = hwmgr->adev; int i; u32 tmp = 0; if (!query) return -EINVAL; - smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetCurrPkgPwr, 0); - tmp = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); - *query = tmp; + /* + * PPSMC_MSG_GetCurrPkgPwr is not supported on: + * - Hawaii + * - Bonaire + * - Fiji + * - Tonga + */ + if ((adev->asic_type != CHIP_HAWAII) && + (adev->asic_type != CHIP_BONAIRE) && + (adev->asic_type != CHIP_FIJI) && + (adev->asic_type != CHIP_TONGA)) { + smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_GetCurrPkgPwr, 0); + tmp = cgs_read_register(hwmgr->device, mmSMC_MSG_ARG_0); + *query = tmp; - if (tmp != 0) - return 0; + if (tmp != 0) + return 0; + } smum_send_msg_to_smc(hwmgr, PPSMC_MSG_PmStatusLogStart); cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, @@ -3969,6 +3982,13 @@ static int smu7_set_power_state_tasks(struct pp_hwmgr *hwmgr, const void *input) "Failed to populate and upload SCLK MCLK DPM levels!", result = tmp_result); + /* + * If a custom pp table is loaded, set DPMTABLE_OD_UPDATE_VDDC flag. + * That effectively disables AVFS feature. + */ + if (hwmgr->hardcode_pp_table != NULL) + data->need_update_smu7_dpm_table |= DPMTABLE_OD_UPDATE_VDDC; + tmp_result = smu7_update_avfs(hwmgr); PP_ASSERT_WITH_CODE((0 == tmp_result), "Failed to update avfs voltages!", @@ -4068,6 +4088,11 @@ static int smu7_program_display_gap(struct pp_hwmgr *hwmgr) data->frame_time_x2 = frame_time_in_us * 2 / 100; + if (data->frame_time_x2 < 280) { + pr_debug("%s: enforce minimal VBITimeout: %d -> 280\n", __func__, data->frame_time_x2); + data->frame_time_x2 = 280; + } + display_gap2 = pre_vbi_time_in_us * (ref_clock / 100); cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, ixCG_DISPLAY_GAP_CNTL2, display_gap2); @@ -4213,7 +4238,6 @@ static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); - uint32_t vbios_version; uint32_t tmp; /* Read MC indirect register offset 0x9F bits [3:0] to see @@ -4222,7 +4246,6 @@ static int smu7_check_mc_firmware(struct pp_hwmgr *hwmgr) */ smu7_get_mc_microcode_version(hwmgr); - vbios_version = hwmgr->microcode_version_info.MC & 0xf; data->need_long_memory_training = false; @@ -4920,7 +4943,7 @@ static int smu7_get_power_profile_mode(struct pp_hwmgr *hwmgr, char *buf) title[0], title[1], title[2], title[3], title[4], title[5], title[6], title[7]); - len = sizeof(smu7_profiling) / sizeof(struct profile_mode_setting); + len = ARRAY_SIZE(smu7_profiling); for (i = 0; i < len; i++) { if (i == hwmgr->power_profile_mode) { @@ -5052,13 +5075,11 @@ static int smu7_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw PHM_PerformanceLevel *level) { const struct smu7_power_state *ps; - struct smu7_hwmgr *data; uint32_t i; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = hwmgr->backend; ps = cast_const_phw_smu7_power_state(state); i = index > ps->performance_level_count - 1 ? @@ -5139,6 +5160,9 @@ static const struct pp_hwmgr_func smu7_hwmgr_funcs = { .get_power_profile_mode = smu7_get_power_profile_mode, .set_power_profile_mode = smu7_set_power_profile_mode, .get_performance_level = smu7_get_performance_level, + .get_asic_baco_capability = smu7_baco_get_capability, + .get_asic_baco_state = smu7_baco_get_state, + .set_asic_baco_state = smu7_baco_set_state, .power_off_asic = smu7_power_off_asic, }; @@ -5161,13 +5185,11 @@ uint8_t smu7_get_sleep_divider_id_from_clock(uint32_t clock, int smu7_init_function_pointers(struct pp_hwmgr *hwmgr) { - int ret = 0; - hwmgr->hwmgr_func = &smu7_hwmgr_funcs; if (hwmgr->pp_table_version == PP_TABLE_V0) hwmgr->pptable_func = &pptable_funcs; else if (hwmgr->pp_table_version == PP_TABLE_V1) hwmgr->pptable_func = &pptable_v1_0_funcs; - return ret; + return 0; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.c new file mode 100644 index 000000000000..ea743bea8e29 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.c @@ -0,0 +1,231 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "tonga_baco.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 "dce/dce_10_0_d.h" +#include "dce/dce_10_0_sh_mask.h" + +#include "smu/smu_7_1_2_d.h" +#include "smu/smu_7_1_2_sh_mask.h" + + +static const struct baco_cmd_entry gpio_tbl[] = +{ + { CMD_WRITE, mmGPIOPAD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PU_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_MASK, 0, 0, 0, 0xff77ffff }, + { CMD_WRITE, mmDC_GPIO_DVODATA_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmDC_GPIO_DVODATA_MASK, 0, 0, 0, 0xffffffff }, + { CMD_WRITE, mmDC_GPIO_GENERIC_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_GENERIC_MASK, 0, 0, 0, 0x03333333 }, + { CMD_WRITE, mmDC_GPIO_SYNCA_EN, 0, 0, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmDC_GPIO_SYNCA_MASK, 0, 0, 0, 0x00001111 } +}; + +static const struct baco_cmd_entry enable_fb_req_rej_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0300024 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x1, 0x0, 0, 0x1 }, + { CMD_WRITE, mmBIF_FB_EN, 0, 0, 0, 0x0 } +}; + +static const struct baco_cmd_entry use_bclk_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN_MASK, CG_SPLL_FUNC_CNTL__SPLL_BYPASS_EN__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_BYPASS_CHG__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_STATUS }, + { CMD_WAITFOR, mmGCK_SMC_IND_DATA, CG_SPLL_STATUS__SPLL_CHG_STATUS_MASK, 0, 0xffffffff, 0x2 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG_MASK, CG_SPLL_FUNC_CNTL_2__SPLL_CTLREQ_CHG__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x4000000, 0x1a, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x2 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL_MASK, MPLL_CNTL_MODE__MPLL_SW_DIR_CONTROL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__MPLL_MCLK_SEL_MASK, MPLL_CNTL_MODE__MPLL_MCLK_SEL__SHIFT, 0, 0x0 } +}; + +static const struct baco_cmd_entry turn_off_plls_tbl[] = +{ + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_SPLL_FUNC_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_RESET_MASK, CG_SPLL_FUNC_CNTL__SPLL_RESET__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_SPLL_FUNC_CNTL__SPLL_PWRON_MASK, CG_SPLL_FUNC_CNTL__SPLL_PWRON__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, 0xC0500170 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x2000000, 0x19, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, 0x8000000, 0x1b, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMPLL_CNTL_MODE, MPLL_CNTL_MODE__GLOBAL_MPLL_RESET_MASK, MPLL_CNTL_MODE__GLOBAL_MPLL_RESET__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmMPLL_CONTROL, 0, 0, 0, 0x00000006 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY0_D0, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY0_D1, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY1_D0, 0, 0, 0, 0x00007740 }, + { CMD_WRITE, mmMC_IO_RXCNTL_DPHY1_D1, 0, 0, 0, 0x00007740 }, + { CMD_READMODIFYWRITE, mmMCLK_PWRMGT_CNTL, MCLK_PWRMGT_CNTL__MRDCK0_PDNB_MASK, MCLK_PWRMGT_CNTL__MRDCK0_PDNB__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMCLK_PWRMGT_CNTL, MCLK_PWRMGT_CNTL__MRDCK1_PDNB_MASK, MCLK_PWRMGT_CNTL__MRDCK1_PDNB__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_CNTL_2, MC_SEQ_CNTL_2__DRST_PU_MASK, MC_SEQ_CNTL_2__DRST_PU__SHIFT, 0, 0x0 }, + { CMD_READMODIFYWRITE, mmMC_SEQ_CNTL_2, MC_SEQ_CNTL_2__DRST_PD_MASK, MC_SEQ_CNTL_2__DRST_PD__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL_2 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN_MASK, CG_CLKPIN_CNTL_2__FORCE_BIF_REFCLK_EN__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMPLL_BYPASSCLK_SEL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL_MASK, MPLL_BYPASSCLK_SEL__MPLL_CLKOUT_SEL__SHIFT, 0, 0x4 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixMISC_CLK_CTRL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL_MASK, MISC_CLK_CTRL__DEEP_SLEEP_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, MISC_CLK_CTRL__ZCLK_SEL_MASK, MISC_CLK_CTRL__ZCLK_SEL__SHIFT, 0, 0x1 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixCG_CLKPIN_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, CG_CLKPIN_CNTL__BCLK_AS_XCLK_MASK, CG_CLKPIN_CNTL__BCLK_AS_XCLK__SHIFT, 0, 0x0 }, + { CMD_WRITE, mmGCK_SMC_IND_INDEX, 0, 0, 0, ixTHM_CLK_CNTL }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__CMON_CLK_SEL_MASK, THM_CLK_CNTL__CMON_CLK_SEL__SHIFT, 0, 0x1 }, + { CMD_READMODIFYWRITE, mmGCK_SMC_IND_DATA, THM_CLK_CNTL__TMON_CLK_SEL_MASK, THM_CLK_CNTL__TMON_CLK_SEL__SHIFT, 0, 0x1 } +}; + +static const struct baco_cmd_entry enter_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, 0, 5, 0x40000 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, 0, 5, 0x02 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, 0, 5, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, 0, 5, 0x08 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x40 } +}; + +#define BACO_CNTL__PWRGOOD_MASK BACO_CNTL__PWRGOOD_GPIO_MASK+BACO_CNTL__PWRGOOD_MEM_MASK+BACO_CNTL__PWRGOOD_DVO_MASK + +static const struct baco_cmd_entry exit_baco_tbl[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_BF_MASK, 0, 0xffffffff, 0x200 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_MASK, 0, 5, 0x1c00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__RCU_BIF_CONFIG_DONE_MASK, 0, 5, 0x100 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x00 } +}; + +static const struct baco_cmd_entry clean_baco_tbl[] = +{ + { CMD_WRITE, mmBIOS_SCRATCH_6, 0, 0, 0, 0 }, + { CMD_WRITE, mmBIOS_SCRATCH_7, 0, 0, 0, 0 } +}; + +static const struct baco_cmd_entry gpio_tbl_iceland[] = +{ + { CMD_WRITE, mmGPIOPAD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PD_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_PU_EN, 0, 0, 0, 0x0 }, + { CMD_WRITE, mmGPIOPAD_MASK, 0, 0, 0, 0xff77ffff } +}; + +static const struct baco_cmd_entry exit_baco_tbl_iceland[] = +{ + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BCLK_OFF_MASK, BACO_CNTL__BACO_BCLK_OFF__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_POWER_OFF_MASK, BACO_CNTL__BACO_POWER_OFF__SHIFT, 0, 0x00 }, + { CMD_DELAY_MS, 0, 0, 0, 20, 0 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_BF_MASK, 0, 0xffffffff, 0x200 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ISO_DIS_MASK, BACO_CNTL__BACO_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__PWRGOOD_MASK, 0, 5, 0x1c00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_ANA_ISO_DIS_MASK, BACO_CNTL__BACO_ANA_ISO_DIS__SHIFT, 0, 0x01 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_BIF_SCLK_SWITCH_MASK, BACO_CNTL__BACO_BIF_SCLK_SWITCH__SHIFT, 0, 0x00 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_RESET_EN_MASK, BACO_CNTL__BACO_RESET_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__RCU_BIF_CONFIG_DONE_MASK, 0, 5, 0x100 }, + { CMD_READMODIFYWRITE, mmBACO_CNTL, BACO_CNTL__BACO_EN_MASK, BACO_CNTL__BACO_EN__SHIFT, 0, 0x00 }, + { CMD_WAITFOR, mmBACO_CNTL, BACO_CNTL__BACO_MODE_MASK, 0, 0xffffffff, 0x00 } +}; + +static const struct baco_cmd_entry clean_baco_tbl_iceland[] = +{ + { CMD_WRITE, mmBIOS_SCRATCH_7, 0, 0, 0, 0 } +}; + +int tonga_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) +{ + enum BACO_STATE cur_state; + + smu7_baco_get_state(hwmgr, &cur_state); + + if (cur_state == state) + /* aisc already in the target state */ + return 0; + + if (state == BACO_STATE_IN) { + if (hwmgr->chip_id == CHIP_TOPAZ) + baco_program_registers(hwmgr, gpio_tbl_iceland, ARRAY_SIZE(gpio_tbl_iceland)); + else + baco_program_registers(hwmgr, gpio_tbl, ARRAY_SIZE(gpio_tbl)); + baco_program_registers(hwmgr, enable_fb_req_rej_tbl, + ARRAY_SIZE(enable_fb_req_rej_tbl)); + baco_program_registers(hwmgr, use_bclk_tbl, ARRAY_SIZE(use_bclk_tbl)); + baco_program_registers(hwmgr, turn_off_plls_tbl, + ARRAY_SIZE(turn_off_plls_tbl)); + if (baco_program_registers(hwmgr, enter_baco_tbl, + ARRAY_SIZE(enter_baco_tbl))) + return 0; + + } else if (state == BACO_STATE_OUT) { + /* HW requires at least 20ms between regulator off and on */ + msleep(20); + /* Execute Hardware BACO exit sequence */ + if (hwmgr->chip_id == CHIP_TOPAZ) { + if (baco_program_registers(hwmgr, exit_baco_tbl_iceland, + ARRAY_SIZE(exit_baco_tbl_iceland))) { + if (baco_program_registers(hwmgr, clean_baco_tbl_iceland, + ARRAY_SIZE(clean_baco_tbl_iceland))) + return 0; + } + } else { + if (baco_program_registers(hwmgr, exit_baco_tbl, + ARRAY_SIZE(exit_baco_tbl))) { + if (baco_program_registers(hwmgr, clean_baco_tbl, + ARRAY_SIZE(clean_baco_tbl))) + return 0; + } + } + } + + return -EINVAL; +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.h b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.h new file mode 100644 index 000000000000..5dc16cc8a295 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/tonga_baco.h @@ -0,0 +1,29 @@ +/* + * Copyright 2019 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_BACO_H__ +#define __TONGA_BACO_H__ +#include "smu7_baco.h" + +extern int tonga_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 3be8eb21fd6e..92a65e3daff4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -712,7 +712,6 @@ static int vega10_sort_lookup_table(struct pp_hwmgr *hwmgr, struct phm_ppt_v1_voltage_lookup_table *lookup_table) { uint32_t table_size, i, j; - struct phm_ppt_v1_voltage_lookup_record tmp_voltage_lookup_record; PP_ASSERT_WITH_CODE(lookup_table && lookup_table->count, "Lookup table is empty", return -EINVAL); @@ -724,9 +723,8 @@ static int vega10_sort_lookup_table(struct pp_hwmgr *hwmgr, for (j = i + 1; j > 0; j--) { if (lookup_table->entries[j].us_vdd < lookup_table->entries[j - 1].us_vdd) { - tmp_voltage_lookup_record = lookup_table->entries[j - 1]; - lookup_table->entries[j - 1] = lookup_table->entries[j]; - lookup_table->entries[j] = tmp_voltage_lookup_record; + swap(lookup_table->entries[j - 1], + lookup_table->entries[j]); } } } @@ -914,6 +912,9 @@ static int vega10_hwmgr_backend_init(struct pp_hwmgr *hwmgr) hwmgr->platform_descriptor.clockStep.memoryClock = 500; data->total_active_cus = adev->gfx.cu_info.number; + if (!hwmgr->not_vf) + return result; + /* Setup default Overdrive Fan control settings */ data->odn_fan_table.target_fan_speed = hwmgr->thermal_controller.advanceFanControlParameters.usMaxFanRPM; @@ -981,6 +982,9 @@ static int vega10_setup_dpm_led_config(struct pp_hwmgr *hwmgr) static int vega10_setup_asic_task(struct pp_hwmgr *hwmgr) { + if (!hwmgr->not_vf) + return 0; + PP_ASSERT_WITH_CODE(!vega10_init_sclk_threshold(hwmgr), "Failed to init sclk threshold!", return -EINVAL); @@ -2505,6 +2509,9 @@ static int vega10_init_smc_table(struct pp_hwmgr *hwmgr) "Failed to setup default DPM tables!", return result); + if (!hwmgr->not_vf) + return 0; + /* initialize ODN table */ if (hwmgr->od_enabled) { if (odn_table->max_vddc) { @@ -2828,6 +2835,8 @@ static int vega10_stop_dpm(struct pp_hwmgr *hwmgr, uint32_t bitmap) struct vega10_hwmgr *data = hwmgr->backend; uint32_t i, feature_mask = 0; + if (!hwmgr->not_vf) + return 0; if(data->smu_features[GNLD_LED_DISPLAY].supported == true){ PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, @@ -2934,61 +2943,73 @@ static int vega10_enable_dpm_tasks(struct pp_hwmgr *hwmgr) struct vega10_hwmgr *data = hwmgr->backend; int tmp_result, result = 0; - vega10_enable_disable_PCC_limit_feature(hwmgr, true); + if (hwmgr->not_vf) { + vega10_enable_disable_PCC_limit_feature(hwmgr, true); - smum_send_msg_to_smc_with_parameter(hwmgr, - PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); - - tmp_result = vega10_construct_voltage_tables(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to construct voltage tables!", - result = tmp_result); + smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_ConfigureTelemetry, data->config_telemetry); - tmp_result = vega10_init_smc_table(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to initialize SMC table!", - result = tmp_result); + tmp_result = vega10_construct_voltage_tables(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to construct voltage tables!", + result = tmp_result); + } - if (PP_CAP(PHM_PlatformCaps_ThermalController)) { - tmp_result = vega10_enable_thermal_protection(hwmgr); + if (hwmgr->not_vf || hwmgr->pp_one_vf) { + tmp_result = vega10_init_smc_table(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable thermal protection!", - result = tmp_result); + "Failed to initialize SMC table!", + result = tmp_result); } - tmp_result = vega10_enable_vrhot_feature(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable VR hot feature!", - result = tmp_result); + if (hwmgr->not_vf) { + if (PP_CAP(PHM_PlatformCaps_ThermalController)) { + tmp_result = vega10_enable_thermal_protection(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable thermal protection!", + result = tmp_result); + } - tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable deep sleep master switch!", - result = tmp_result); + tmp_result = vega10_enable_vrhot_feature(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable VR hot feature!", + result = tmp_result); - tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to start DPM!", result = tmp_result); + tmp_result = vega10_enable_deep_sleep_master_switch(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable deep sleep master switch!", + result = tmp_result); + } - /* enable didt, do not abort if failed didt */ - tmp_result = vega10_enable_didt_config(hwmgr); - PP_ASSERT(!tmp_result, - "Failed to enable didt config!"); + if (hwmgr->not_vf) { + tmp_result = vega10_start_dpm(hwmgr, SMC_DPM_FEATURES); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to start DPM!", result = tmp_result); + } + + if (hwmgr->not_vf) { + /* enable didt, do not abort if failed didt */ + tmp_result = vega10_enable_didt_config(hwmgr); + PP_ASSERT(!tmp_result, + "Failed to enable didt config!"); + } tmp_result = vega10_enable_power_containment(hwmgr); PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable power containment!", - result = tmp_result); + "Failed to enable power containment!", + result = tmp_result); - tmp_result = vega10_power_control_set_level(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to power control set level!", - result = tmp_result); + if (hwmgr->not_vf) { + tmp_result = vega10_power_control_set_level(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to power control set level!", + result = tmp_result); - tmp_result = vega10_enable_ulv(hwmgr); - PP_ASSERT_WITH_CODE(!tmp_result, - "Failed to enable ULV!", - result = tmp_result); + tmp_result = vega10_enable_ulv(hwmgr); + PP_ASSERT_WITH_CODE(!tmp_result, + "Failed to enable ULV!", + result = tmp_result); + } return result; } @@ -3082,11 +3103,22 @@ static int vega10_get_pp_table_entry_callback_func(struct pp_hwmgr *hwmgr, performance_level->soc_clock = socclk_dep_table->entries [state_entry->ucSocClockIndexHigh].ulClk; if (gfxclk_dep_table->ucRevId == 0) { - performance_level->gfx_clock = gfxclk_dep_table->entries - [state_entry->ucGfxClockIndexHigh].ulClk; + /* under vega10 pp one vf mode, the gfx clk dpm need be lower + * to level-4 due to the limited 110w-power + */ + if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0)) + performance_level->gfx_clock = + gfxclk_dep_table->entries[4].ulClk; + else + performance_level->gfx_clock = gfxclk_dep_table->entries + [state_entry->ucGfxClockIndexHigh].ulClk; } else if (gfxclk_dep_table->ucRevId == 1) { patom_record_V2 = (ATOM_Vega10_GFXCLK_Dependency_Record_V2 *)gfxclk_dep_table->entries; - performance_level->gfx_clock = patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk; + if (hwmgr->pp_one_vf && (state_entry->ucGfxClockIndexHigh > 0)) + performance_level->gfx_clock = patom_record_V2[4].ulClk; + else + performance_level->gfx_clock = + patom_record_V2[state_entry->ucGfxClockIndexHigh].ulClk; } performance_level->mem_clock = mclk_dep_table->entries @@ -3220,7 +3252,8 @@ static int vega10_apply_state_adjust_rules(struct pp_hwmgr *hwmgr, if (hwmgr->display_config->num_display == 0) disable_mclk_switching = false; else - disable_mclk_switching = (hwmgr->display_config->num_display > 1) || + disable_mclk_switching = ((1 < hwmgr->display_config->num_display) && + !hwmgr->display_config->multi_monitor_in_sync) || disable_mclk_switching_for_frame_lock || disable_mclk_switching_for_vr || force_mclk_high; @@ -3496,6 +3529,7 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinGfxclkByIndex, data->smc_state_table.gfx_boot_level); + data->dpm_table.gfx_table.dpm_state.soft_min_level = data->smc_state_table.gfx_boot_level; } @@ -3504,7 +3538,8 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) if (!data->registry_data.mclk_dpm_key_disabled) { if (data->smc_state_table.mem_boot_level != data->dpm_table.mem_table.dpm_state.soft_min_level) { - if (data->smc_state_table.mem_boot_level == NUM_UCLK_DPM_LEVELS - 1) { + if ((data->smc_state_table.mem_boot_level == NUM_UCLK_DPM_LEVELS - 1) + && hwmgr->not_vf) { socclk_idx = vega10_get_soc_index_for_max_uclk(hwmgr); smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetSoftMinSocclkByIndex, @@ -3519,6 +3554,9 @@ static int vega10_upload_dpm_bootup_level(struct pp_hwmgr *hwmgr) } } + if (!hwmgr->not_vf) + return 0; + if (!data->registry_data.socclk_dpm_key_disabled) { if (data->smc_state_table.soc_boot_level != data->dpm_table.soc_table.dpm_state.soft_min_level) { @@ -3561,6 +3599,9 @@ static int vega10_upload_dpm_max_level(struct pp_hwmgr *hwmgr) } } + if (!hwmgr->not_vf) + return 0; + if (!data->registry_data.socclk_dpm_key_disabled) { if (data->smc_state_table.soc_max_level != data->dpm_table.soc_table.dpm_state.soft_max_level) { @@ -3690,6 +3731,13 @@ static int vega10_set_power_state_tasks(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(!result, "Failed to upload PPtable!", return result); + /* + * If a custom pp table is loaded, set DPMTABLE_OD_UPDATE_VDDC flag. + * That effectively disables AVFS feature. + */ + if(hwmgr->hardcode_pp_table != NULL) + data->need_update_dpm_table |= DPMTABLE_OD_UPDATE_VDDC; + vega10_update_avfs(hwmgr); /* @@ -4048,15 +4096,25 @@ static int vega10_get_profiling_clk_mask(struct pp_hwmgr *hwmgr, enum amd_dpm_fo } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { *mclk_mask = 0; } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; + /* under vega10 pp one vf mode, the gfx clk dpm need be lower + * to level-4 due to the limited power + */ + if (hwmgr->pp_one_vf) + *sclk_mask = 4; + else + *sclk_mask = table_info->vdd_dep_on_sclk->count - 1; *soc_mask = table_info->vdd_dep_on_socclk->count - 1; *mclk_mask = table_info->vdd_dep_on_mclk->count - 1; } + return 0; } static void vega10_set_fan_control_mode(struct pp_hwmgr *hwmgr, uint32_t mode) { + if (!hwmgr->not_vf) + return; + switch (mode) { case AMD_FAN_CTRL_NONE: vega10_fan_ctrl_set_fan_speed_percent(hwmgr, 100); @@ -4170,6 +4228,9 @@ static int vega10_dpm_force_dpm_level(struct pp_hwmgr *hwmgr, break; } + if (!hwmgr->not_vf) + return ret; + if (!ret) { if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK && hwmgr->dpm_level != AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) vega10_set_fan_control_mode(hwmgr, AMD_FAN_CTRL_NONE); @@ -4354,14 +4415,13 @@ static int vega10_set_watermarks_for_clocks_ranges(struct pp_hwmgr *hwmgr, struct vega10_hwmgr *data = hwmgr->backend; struct dm_pp_wm_sets_with_clock_ranges_soc15 *wm_with_clock_ranges = clock_range; Watermarks_t *table = &(data->smc_state_table.water_marks_table); - int result = 0; if (!data->registry_data.disable_water_mark) { smu_set_watermarks_for_clocks_ranges(table, wm_with_clock_ranges); data->water_marks_bitmap = WaterMarksExist; } - return result; + return 0; } static int vega10_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf) @@ -4474,7 +4534,7 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, struct vega10_pcie_table *pcie_table = &(data->dpm_table.pcie_table); struct vega10_odn_clock_voltage_dependency_table *podn_vdd_dep = NULL; - int i, now, size = 0; + int i, now, size = 0, count = 0; switch (type) { case PP_SCLK: @@ -4484,7 +4544,12 @@ static int vega10_print_clock_levels(struct pp_hwmgr *hwmgr, smum_send_msg_to_smc(hwmgr, PPSMC_MSG_GetCurrentGfxclkIndex); now = smum_get_argument(hwmgr); - for (i = 0; i < sclk_table->count; i++) + if (hwmgr->pp_one_vf && + (hwmgr->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK)) + count = 5; + else + count = sclk_table->count; + for (i = 0; i < count; i++) size += sprintf(buf + size, "%d: %uMhz %s\n", i, sclk_table->dpm_levels[i].value / 100, (i == now) ? "*" : ""); @@ -4695,6 +4760,9 @@ static int vega10_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; + if (!hwmgr->not_vf) + return 0; + if (PP_CAP(PHM_PlatformCaps_ThermalController)) vega10_disable_thermal_protection(hwmgr); @@ -5097,9 +5165,7 @@ static void vega10_odn_update_soc_table(struct pp_hwmgr *hwmgr, if (type == PP_OD_EDIT_SCLK_VDDC_TABLE) { podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_sclk; - for (i = 0; i < podn_vdd_dep->count - 1; i++) - od_vddc_lookup_table->entries[i].us_vdd = podn_vdd_dep->entries[i].vddc; - if (od_vddc_lookup_table->entries[i].us_vdd < podn_vdd_dep->entries[i].vddc) + for (i = 0; i < podn_vdd_dep->count; i++) od_vddc_lookup_table->entries[i].us_vdd = podn_vdd_dep->entries[i].vddc; } else if (type == PP_OD_EDIT_MCLK_VDDC_TABLE) { podn_vdd_dep = &data->odn_dpm_table.vdd_dep_on_mclk; @@ -5219,18 +5285,40 @@ static int vega10_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, return 0; } +static int vega10_set_mp1_state(struct pp_hwmgr *hwmgr, + enum pp_mp1_state mp1_state) +{ + uint16_t msg; + int ret; + + switch (mp1_state) { + case PP_MP1_STATE_UNLOAD: + msg = PPSMC_MSG_PrepareMp1ForUnload; + break; + case PP_MP1_STATE_SHUTDOWN: + case PP_MP1_STATE_RESET: + case PP_MP1_STATE_NONE: + default: + return 0; + } + + PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr, msg)) == 0, + "[PrepareMp1] Failed!", + return ret); + + return 0; +} + static int vega10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_hw_power_state *state, PHM_PerformanceLevelDesignation designation, uint32_t index, PHM_PerformanceLevel *level) { const struct vega10_power_state *ps; - struct vega10_hwmgr *data; uint32_t i; if (level == NULL || hwmgr == NULL || state == NULL) return -EINVAL; - data = hwmgr->backend; ps = cast_const_phw_vega10_power_state(state); i = index > ps->performance_level_count - 1 ? @@ -5242,6 +5330,59 @@ static int vega10_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_ return 0; } +static int vega10_disable_power_features_for_compute_performance(struct pp_hwmgr *hwmgr, bool disable) +{ + struct vega10_hwmgr *data = hwmgr->backend; + uint32_t feature_mask = 0; + + if (disable) { + feature_mask |= data->smu_features[GNLD_ULV].enabled ? + data->smu_features[GNLD_ULV].smu_feature_bitmap : 0; + feature_mask |= data->smu_features[GNLD_DS_GFXCLK].enabled ? + data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap : 0; + feature_mask |= data->smu_features[GNLD_DS_SOCCLK].enabled ? + data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap : 0; + feature_mask |= data->smu_features[GNLD_DS_LCLK].enabled ? + data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap : 0; + feature_mask |= data->smu_features[GNLD_DS_DCEFCLK].enabled ? + data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap : 0; + } else { + feature_mask |= (!data->smu_features[GNLD_ULV].enabled) ? + data->smu_features[GNLD_ULV].smu_feature_bitmap : 0; + feature_mask |= (!data->smu_features[GNLD_DS_GFXCLK].enabled) ? + data->smu_features[GNLD_DS_GFXCLK].smu_feature_bitmap : 0; + feature_mask |= (!data->smu_features[GNLD_DS_SOCCLK].enabled) ? + data->smu_features[GNLD_DS_SOCCLK].smu_feature_bitmap : 0; + feature_mask |= (!data->smu_features[GNLD_DS_LCLK].enabled) ? + data->smu_features[GNLD_DS_LCLK].smu_feature_bitmap : 0; + feature_mask |= (!data->smu_features[GNLD_DS_DCEFCLK].enabled) ? + data->smu_features[GNLD_DS_DCEFCLK].smu_feature_bitmap : 0; + } + + if (feature_mask) + PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, + !disable, feature_mask), + "enable/disable power features for compute performance Failed!", + return -EINVAL); + + if (disable) { + data->smu_features[GNLD_ULV].enabled = false; + data->smu_features[GNLD_DS_GFXCLK].enabled = false; + data->smu_features[GNLD_DS_SOCCLK].enabled = false; + data->smu_features[GNLD_DS_LCLK].enabled = false; + data->smu_features[GNLD_DS_DCEFCLK].enabled = false; + } else { + data->smu_features[GNLD_ULV].enabled = true; + data->smu_features[GNLD_DS_GFXCLK].enabled = true; + data->smu_features[GNLD_DS_SOCCLK].enabled = true; + data->smu_features[GNLD_DS_LCLK].enabled = true; + data->smu_features[GNLD_DS_DCEFCLK].enabled = true; + } + + return 0; + +} + static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .backend_init = vega10_hwmgr_backend_init, .backend_fini = vega10_hwmgr_backend_fini, @@ -5308,6 +5449,9 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .enable_mgpu_fan_boost = vega10_enable_mgpu_fan_boost, .get_ppfeature_status = vega10_get_ppfeature_status, .set_ppfeature_status = vega10_set_ppfeature_status, + .set_mp1_state = vega10_set_mp1_state, + .disable_power_features_for_compute_performance = + vega10_disable_power_features_for_compute_performance, }; int vega10_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c index 6f26cb241ecc..0a677d4bc87b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_powertune.c @@ -1343,6 +1343,9 @@ int vega10_enable_power_containment(struct pp_hwmgr *hwmgr) hwmgr->default_power_limit = hwmgr->power_limit = (uint32_t)(tdp_table->usMaximumPowerDeliveryLimit); + if (!hwmgr->not_vf) + return 0; + if (PP_CAP(PHM_PlatformCaps_PowerContainment)) { if (data->smu_features[GNLD_PPT].supported) PP_ASSERT_WITH_CODE(!vega10_enable_smc_features(hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index efb6d3762feb..aca61d1ff3c2 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -499,8 +499,6 @@ static int vega12_get_number_of_dpm_level(struct pp_hwmgr *hwmgr, static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, PPCLK_e clkID, uint32_t index, uint32_t *clock) { - int result = 0; - /* *SMU expects the Clock ID to be in the top 16 bits. *Lower 16 bits specify the level @@ -512,7 +510,7 @@ static int vega12_get_dpm_frequency_by_index(struct pp_hwmgr *hwmgr, *clock = smum_get_argument(hwmgr); - return result; + return 0; } static int vega12_setup_single_dpm_table(struct pp_hwmgr *hwmgr, @@ -2639,6 +2637,30 @@ static int vega12_get_performance_level(struct pp_hwmgr *hwmgr, const struct pp_ return 0; } +static int vega12_set_mp1_state(struct pp_hwmgr *hwmgr, + enum pp_mp1_state mp1_state) +{ + uint16_t msg; + int ret; + + switch (mp1_state) { + case PP_MP1_STATE_UNLOAD: + msg = PPSMC_MSG_PrepareMp1ForUnload; + break; + case PP_MP1_STATE_SHUTDOWN: + case PP_MP1_STATE_RESET: + case PP_MP1_STATE_NONE: + default: + return 0; + } + + PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr, msg)) == 0, + "[PrepareMp1] Failed!", + return ret); + + return 0; +} + static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .backend_init = vega12_hwmgr_backend_init, .backend_fini = vega12_hwmgr_backend_fini, @@ -2695,7 +2717,7 @@ static const struct pp_hwmgr_func vega12_hwmgr_funcs = { .set_asic_baco_state = vega12_baco_set_state, .get_ppfeature_status = vega12_get_ppfeature_status, .set_ppfeature_status = vega12_set_ppfeature_status, - + .set_mp1_state = vega12_set_mp1_state, }; int vega12_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c index df6ff9252401..9b5e72bdceca 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_baco.c @@ -29,7 +29,7 @@ #include "vega20_baco.h" #include "vega20_smumgr.h" - +#include "amdgpu_ras.h" static const struct soc15_baco_cmd_entry clean_baco_tbl[] = { @@ -74,6 +74,7 @@ int vega20_baco_get_state(struct pp_hwmgr *hwmgr, enum BACO_STATE *state) int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) { struct amdgpu_device *adev = (struct amdgpu_device *)(hwmgr->adev); + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); enum BACO_STATE cur_state; uint32_t data; @@ -84,13 +85,19 @@ int vega20_baco_set_state(struct pp_hwmgr *hwmgr, enum BACO_STATE state) return 0; if (state == BACO_STATE_IN) { - data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); - data |= 0x80000000; - WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); - - - if(smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnterBaco, 0)) - return -EINVAL; + if (!ras || !ras->supported) { + data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); + data |= 0x80000000; + WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); + + if(smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnterBaco, 0)) + return -EINVAL; + } else { + if(smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_EnterBaco, 1)) + return -EINVAL; + } } else if (state == BACO_STATE_OUT) { if (smum_send_msg_to_smc(hwmgr, PPSMC_MSG_ExitBaco)) diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index f27c6fbb192e..3b3ec5666051 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -183,6 +183,9 @@ static int vega20_set_features_platform_caps(struct pp_hwmgr *hwmgr) PHM_PlatformCaps_TablelessHardwareInterface); phm_cap_set(hwmgr->platform_descriptor.platformCaps, + PHM_PlatformCaps_BACO); + + phm_cap_set(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_EnableSMU7ThermalManagement); if (adev->pg_flags & AMD_PG_SUPPORT_UVD) @@ -490,8 +493,8 @@ static int vega20_setup_asic_task(struct pp_hwmgr *hwmgr) "Failed to init sclk threshold!", return ret); - if (adev->in_baco_reset) { - adev->in_baco_reset = 0; + if (adev->in_gpu_reset && + (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) { ret = vega20_baco_apply_vdci_flush_workaround(hwmgr); if (ret) @@ -869,7 +872,7 @@ static int vega20_override_pcie_parameters(struct pp_hwmgr *hwmgr) "[OverridePcieParameters] Attempt to override pcie params failed!", return ret); - data->pcie_parameters_override = 1; + data->pcie_parameters_override = true; data->pcie_gen_level1 = pcie_gen; data->pcie_width_level1 = pcie_width; @@ -2101,7 +2104,11 @@ static int vega20_get_gpu_power(struct pp_hwmgr *hwmgr, if (ret) return ret; - *query = metrics_table.CurrSocketPower << 8; + /* For the 40.46 release, they changed the value name */ + if (hwmgr->smu_version == 0x282e00) + *query = metrics_table.AverageSocketPower << 8; + else + *query = metrics_table.CurrSocketPower << 8; return ret; } @@ -2349,12 +2356,16 @@ static int vega20_force_dpm_highest(struct pp_hwmgr *hwmgr) data->dpm_table.soc_table.dpm_state.soft_max_level = data->dpm_table.soc_table.dpm_levels[soft_level].value; - ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF); + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to highest!", return ret); - ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF); + ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", return ret); @@ -2387,12 +2398,16 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr) data->dpm_table.soc_table.dpm_state.soft_max_level = data->dpm_table.soc_table.dpm_levels[soft_level].value; - ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF); + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload boot level to highest!", return ret); - ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF); + ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload dpm max level to highest!", return ret); @@ -2403,14 +2418,54 @@ static int vega20_force_dpm_lowest(struct pp_hwmgr *hwmgr) static int vega20_unforce_dpm_levels(struct pp_hwmgr *hwmgr) { + struct vega20_hwmgr *data = + (struct vega20_hwmgr *)(hwmgr->backend); + uint32_t soft_min_level, soft_max_level; int ret = 0; - ret = vega20_upload_dpm_min_level(hwmgr, 0xFFFFFFFF); + /* gfxclk soft min/max settings */ + soft_min_level = + vega20_find_lowest_dpm_level(&(data->dpm_table.gfx_table)); + soft_max_level = + vega20_find_highest_dpm_level(&(data->dpm_table.gfx_table)); + + data->dpm_table.gfx_table.dpm_state.soft_min_level = + data->dpm_table.gfx_table.dpm_levels[soft_min_level].value; + data->dpm_table.gfx_table.dpm_state.soft_max_level = + data->dpm_table.gfx_table.dpm_levels[soft_max_level].value; + + /* uclk soft min/max settings */ + soft_min_level = + vega20_find_lowest_dpm_level(&(data->dpm_table.mem_table)); + soft_max_level = + vega20_find_highest_dpm_level(&(data->dpm_table.mem_table)); + + data->dpm_table.mem_table.dpm_state.soft_min_level = + data->dpm_table.mem_table.dpm_levels[soft_min_level].value; + data->dpm_table.mem_table.dpm_state.soft_max_level = + data->dpm_table.mem_table.dpm_levels[soft_max_level].value; + + /* socclk soft min/max settings */ + soft_min_level = + vega20_find_lowest_dpm_level(&(data->dpm_table.soc_table)); + soft_max_level = + vega20_find_highest_dpm_level(&(data->dpm_table.soc_table)); + + data->dpm_table.soc_table.dpm_state.soft_min_level = + data->dpm_table.soc_table.dpm_levels[soft_min_level].value; + data->dpm_table.soc_table.dpm_state.soft_max_level = + data->dpm_table.soc_table.dpm_levels[soft_max_level].value; + + ret = vega20_upload_dpm_min_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload DPM Bootup Levels!", return ret); - ret = vega20_upload_dpm_max_level(hwmgr, 0xFFFFFFFF); + ret = vega20_upload_dpm_max_level(hwmgr, FEATURE_DPM_GFXCLK_MASK | + FEATURE_DPM_UCLK_MASK | + FEATURE_DPM_SOCCLK_MASK); PP_ASSERT_WITH_CODE(!ret, "Failed to upload DPM Max Levels!", return ret); @@ -3063,6 +3118,34 @@ static int vega20_odn_edit_dpm_table(struct pp_hwmgr *hwmgr, return 0; } +static int vega20_set_mp1_state(struct pp_hwmgr *hwmgr, + enum pp_mp1_state mp1_state) +{ + uint16_t msg; + int ret; + + switch (mp1_state) { + case PP_MP1_STATE_SHUTDOWN: + msg = PPSMC_MSG_PrepareMp1ForShutdown; + break; + case PP_MP1_STATE_UNLOAD: + msg = PPSMC_MSG_PrepareMp1ForUnload; + break; + case PP_MP1_STATE_RESET: + msg = PPSMC_MSG_PrepareMp1ForReset; + break; + case PP_MP1_STATE_NONE: + default: + return 0; + } + + PP_ASSERT_WITH_CODE((ret = smum_send_msg_to_smc(hwmgr, msg)) == 0, + "[PrepareMp1] Failed!", + return ret); + + return 0; +} + static int vega20_get_ppfeature_status(struct pp_hwmgr *hwmgr, char *buf) { static const char *ppfeature_name[] = { @@ -4057,6 +4140,56 @@ static int vega20_get_thermal_temperature_range(struct pp_hwmgr *hwmgr, return 0; } +static int vega20_smu_i2c_bus_access(struct pp_hwmgr *hwmgr, bool acquire) +{ + int res; + + /* I2C bus access can happen very early, when SMU not loaded yet */ + if (!vega20_is_smc_ram_running(hwmgr)) + return 0; + + res = smum_send_msg_to_smc_with_parameter(hwmgr, + (acquire ? + PPSMC_MSG_RequestI2CBus : + PPSMC_MSG_ReleaseI2CBus), + 0); + + PP_ASSERT_WITH_CODE(!res, "[SmuI2CAccessBus] Failed to access bus!", return res); + return res; +} + +static int vega20_set_df_cstate(struct pp_hwmgr *hwmgr, + enum pp_df_cstate state) +{ + int ret; + + /* PPSMC_MSG_DFCstateControl is supported with 40.50 and later fws */ + if (hwmgr->smu_version < 0x283200) { + pr_err("Df cstate control is supported with 40.50 and later SMC fw!\n"); + return -EINVAL; + } + + ret = smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DFCstateControl, state); + if (ret) + pr_err("SetDfCstate failed!\n"); + + return ret; +} + +static int vega20_set_xgmi_pstate(struct pp_hwmgr *hwmgr, + uint32_t pstate) +{ + int ret; + + ret = smum_send_msg_to_smc_with_parameter(hwmgr, + PPSMC_MSG_SetXgmiMode, + pstate ? XGMI_MODE_PSTATE_D0 : XGMI_MODE_PSTATE_D3); + if (ret) + pr_err("SetXgmiPstate failed!\n"); + + return ret; +} + static const struct pp_hwmgr_func vega20_hwmgr_funcs = { /* init/fini related */ .backend_init = vega20_hwmgr_backend_init, @@ -4123,6 +4256,10 @@ static const struct pp_hwmgr_func vega20_hwmgr_funcs = { .get_asic_baco_capability = vega20_baco_get_capability, .get_asic_baco_state = vega20_baco_get_state, .set_asic_baco_state = vega20_baco_set_state, + .set_mp1_state = vega20_set_mp1_state, + .smu_i2c_bus_access = vega20_smu_i2c_bus_access, + .set_df_cstate = vega20_set_df_cstate, + .set_xgmi_pstate = vega20_set_xgmi_pstate, }; int vega20_hwmgr_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h index a0f52c86d8c7..97b6714e83e6 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h @@ -26,6 +26,7 @@ #include "kgd_pp_interface.h" #include "dm_pp_interface.h" #include "dm_pp_smu.h" +#include "smu_types.h" #define SMU_THERMAL_MINIMUM_ALERT_TEMP 0 #define SMU_THERMAL_MAXIMUM_ALERT_TEMP 255 @@ -150,124 +151,6 @@ struct smu_power_state { struct smu_hw_power_state hardware; }; -enum smu_message_type -{ - SMU_MSG_TestMessage = 0, - SMU_MSG_GetSmuVersion, - SMU_MSG_GetDriverIfVersion, - SMU_MSG_SetAllowedFeaturesMaskLow, - SMU_MSG_SetAllowedFeaturesMaskHigh, - SMU_MSG_EnableAllSmuFeatures, - SMU_MSG_DisableAllSmuFeatures, - SMU_MSG_EnableSmuFeaturesLow, - SMU_MSG_EnableSmuFeaturesHigh, - SMU_MSG_DisableSmuFeaturesLow, - SMU_MSG_DisableSmuFeaturesHigh, - SMU_MSG_GetEnabledSmuFeaturesLow, - SMU_MSG_GetEnabledSmuFeaturesHigh, - SMU_MSG_SetWorkloadMask, - SMU_MSG_SetPptLimit, - SMU_MSG_SetDriverDramAddrHigh, - SMU_MSG_SetDriverDramAddrLow, - SMU_MSG_SetToolsDramAddrHigh, - SMU_MSG_SetToolsDramAddrLow, - SMU_MSG_TransferTableSmu2Dram, - SMU_MSG_TransferTableDram2Smu, - SMU_MSG_UseDefaultPPTable, - SMU_MSG_UseBackupPPTable, - SMU_MSG_RunBtc, - SMU_MSG_RequestI2CBus, - SMU_MSG_ReleaseI2CBus, - SMU_MSG_SetFloorSocVoltage, - SMU_MSG_SoftReset, - SMU_MSG_StartBacoMonitor, - SMU_MSG_CancelBacoMonitor, - SMU_MSG_EnterBaco, - SMU_MSG_SetSoftMinByFreq, - SMU_MSG_SetSoftMaxByFreq, - SMU_MSG_SetHardMinByFreq, - SMU_MSG_SetHardMaxByFreq, - SMU_MSG_GetMinDpmFreq, - SMU_MSG_GetMaxDpmFreq, - SMU_MSG_GetDpmFreqByIndex, - SMU_MSG_GetDpmClockFreq, - SMU_MSG_GetSsVoltageByDpm, - SMU_MSG_SetMemoryChannelConfig, - SMU_MSG_SetGeminiMode, - SMU_MSG_SetGeminiApertureHigh, - SMU_MSG_SetGeminiApertureLow, - SMU_MSG_SetMinLinkDpmByIndex, - SMU_MSG_OverridePcieParameters, - SMU_MSG_OverDriveSetPercentage, - SMU_MSG_SetMinDeepSleepDcefclk, - SMU_MSG_ReenableAcDcInterrupt, - SMU_MSG_NotifyPowerSource, - SMU_MSG_SetUclkFastSwitch, - SMU_MSG_SetUclkDownHyst, - SMU_MSG_GfxDeviceDriverReset, - SMU_MSG_GetCurrentRpm, - SMU_MSG_SetVideoFps, - SMU_MSG_SetTjMax, - SMU_MSG_SetFanTemperatureTarget, - SMU_MSG_PrepareMp1ForUnload, - SMU_MSG_DramLogSetDramAddrHigh, - SMU_MSG_DramLogSetDramAddrLow, - SMU_MSG_DramLogSetDramSize, - SMU_MSG_SetFanMaxRpm, - SMU_MSG_SetFanMinPwm, - SMU_MSG_ConfigureGfxDidt, - SMU_MSG_NumOfDisplays, - SMU_MSG_RemoveMargins, - SMU_MSG_ReadSerialNumTop32, - SMU_MSG_ReadSerialNumBottom32, - SMU_MSG_SetSystemVirtualDramAddrHigh, - SMU_MSG_SetSystemVirtualDramAddrLow, - SMU_MSG_WaflTest, - SMU_MSG_SetFclkGfxClkRatio, - SMU_MSG_AllowGfxOff, - SMU_MSG_DisallowGfxOff, - SMU_MSG_GetPptLimit, - SMU_MSG_GetDcModeMaxDpmFreq, - SMU_MSG_GetDebugData, - SMU_MSG_SetXgmiMode, - SMU_MSG_RunAfllBtc, - SMU_MSG_ExitBaco, - SMU_MSG_PrepareMp1ForReset, - SMU_MSG_PrepareMp1ForShutdown, - SMU_MSG_SetMGpuFanBoostLimitRpm, - SMU_MSG_GetAVFSVoltageByDpm, - SMU_MSG_PowerUpVcn, - SMU_MSG_PowerDownVcn, - SMU_MSG_PowerUpJpeg, - SMU_MSG_PowerDownJpeg, - SMU_MSG_BacoAudioD3PME, - SMU_MSG_ArmD3, - SMU_MSG_MAX_COUNT, -}; - -enum smu_clk_type -{ - SMU_GFXCLK, - SMU_VCLK, - SMU_DCLK, - SMU_ECLK, - SMU_SOCCLK, - SMU_UCLK, - SMU_DCEFCLK, - SMU_DISPCLK, - SMU_PIXCLK, - SMU_PHYCLK, - SMU_FCLK, - SMU_SCLK, - SMU_MCLK, - SMU_PCIE, - SMU_OD_SCLK, - SMU_OD_MCLK, - SMU_OD_VDDC_CURVE, - SMU_OD_RANGE, - SMU_CLK_COUNT, -}; - enum smu_power_src_type { SMU_POWER_SOURCE_AC, @@ -275,63 +158,6 @@ enum smu_power_src_type SMU_POWER_SOURCE_COUNT, }; -enum smu_feature_mask -{ - SMU_FEATURE_DPM_PREFETCHER_BIT, - SMU_FEATURE_DPM_GFXCLK_BIT, - SMU_FEATURE_DPM_UCLK_BIT, - SMU_FEATURE_DPM_SOCCLK_BIT, - SMU_FEATURE_DPM_UVD_BIT, - SMU_FEATURE_DPM_VCE_BIT, - SMU_FEATURE_ULV_BIT, - SMU_FEATURE_DPM_MP0CLK_BIT, - SMU_FEATURE_DPM_LINK_BIT, - SMU_FEATURE_DPM_DCEFCLK_BIT, - SMU_FEATURE_DS_GFXCLK_BIT, - SMU_FEATURE_DS_SOCCLK_BIT, - SMU_FEATURE_DS_LCLK_BIT, - SMU_FEATURE_PPT_BIT, - SMU_FEATURE_TDC_BIT, - SMU_FEATURE_THERMAL_BIT, - SMU_FEATURE_GFX_PER_CU_CG_BIT, - SMU_FEATURE_RM_BIT, - SMU_FEATURE_DS_DCEFCLK_BIT, - SMU_FEATURE_ACDC_BIT, - SMU_FEATURE_VR0HOT_BIT, - SMU_FEATURE_VR1HOT_BIT, - SMU_FEATURE_FW_CTF_BIT, - SMU_FEATURE_LED_DISPLAY_BIT, - SMU_FEATURE_FAN_CONTROL_BIT, - SMU_FEATURE_GFX_EDC_BIT, - SMU_FEATURE_GFXOFF_BIT, - SMU_FEATURE_CG_BIT, - SMU_FEATURE_DPM_FCLK_BIT, - SMU_FEATURE_DS_FCLK_BIT, - SMU_FEATURE_DS_MP1CLK_BIT, - SMU_FEATURE_DS_MP0CLK_BIT, - SMU_FEATURE_XGMI_BIT, - SMU_FEATURE_DPM_GFX_PACE_BIT, - SMU_FEATURE_MEM_VDDCI_SCALING_BIT, - SMU_FEATURE_MEM_MVDD_SCALING_BIT, - SMU_FEATURE_DS_UCLK_BIT, - SMU_FEATURE_GFX_ULV_BIT, - SMU_FEATURE_FW_DSTATE_BIT, - SMU_FEATURE_BACO_BIT, - SMU_FEATURE_VCN_PG_BIT, - SMU_FEATURE_JPEG_PG_BIT, - SMU_FEATURE_USB_PG_BIT, - SMU_FEATURE_RSMU_SMN_CG_BIT, - SMU_FEATURE_APCC_PLUS_BIT, - SMU_FEATURE_GTHR_BIT, - SMU_FEATURE_GFX_DCS_BIT, - SMU_FEATURE_GFX_SS_BIT, - SMU_FEATURE_OUT_OF_BAND_MONITOR_BIT, - SMU_FEATURE_TEMP_DEPENDENT_VMIN_BIT, - SMU_FEATURE_MMHUB_PG_BIT, - SMU_FEATURE_ATHUB_PG_BIT, - SMU_FEATURE_COUNT, -}; - enum smu_memory_pool_size { SMU_MEMORY_POOL_SIZE_ZERO = 0, @@ -396,12 +222,17 @@ struct smu_bios_boot_up_values uint16_t vdd_gfx; uint8_t cooling_id; uint32_t pp_table_id; + uint32_t format_revision; + uint32_t content_revision; + uint32_t fclk; }; enum smu_table_id { SMU_TABLE_PPTABLE = 0, SMU_TABLE_WATERMARKS, + SMU_TABLE_CUSTOM_DPM, + SMU_TABLE_DPMCLOCKS, SMU_TABLE_AVFS, SMU_TABLE_AVFS_PSM_DEBUG, SMU_TABLE_AVFS_FUSE_OVERRIDE, @@ -422,17 +253,27 @@ struct smu_table_context void *hardcode_pptable; unsigned long metrics_time; void *metrics_table; + void *clocks_table; + void *watermarks_table; void *max_sustainable_clocks; struct smu_bios_boot_up_values boot_values; void *driver_pptable; struct smu_table *tables; - uint32_t table_count; + /* + * The driver table is just a staging buffer for + * uploading/downloading content from the SMU. + * + * And the table_id for SMU_MSG_TransferTableSmu2Dram/ + * SMU_MSG_TransferTableDram2Smu instructs SMU + * which content driver is interested. + */ + struct smu_table driver_table; struct smu_table memory_pool; uint8_t thermal_controller_type; - uint16_t TDPODLimit; void *overdrive_table; + void *boot_overdrive_table; }; struct smu_dpm_context { @@ -452,6 +293,7 @@ struct smu_power_gate { bool uvd_gated; bool vce_gated; bool vcn_gated; + bool jpeg_gated; }; struct smu_power_context { @@ -490,6 +332,13 @@ struct mclock_latency_table { struct mclk_latency_entries entries[MAX_REGULAR_DPM_NUM]; }; +enum smu_reset_mode +{ + SMU_RESET_MODE_0, + SMU_RESET_MODE_1, + SMU_RESET_MODE_2, +}; + enum smu_baco_state { SMU_BACO_STATE_ENTER = 0, @@ -509,9 +358,10 @@ struct smu_context struct amdgpu_device *adev; struct amdgpu_irq_src *irq_source; - const struct smu_funcs *funcs; const struct pptable_funcs *ppt_funcs; struct mutex mutex; + struct mutex sensor_lock; + struct mutex metrics_lock; uint64_t pool_size; struct smu_table_context smu_table; @@ -540,6 +390,8 @@ struct smu_context #define WATERMARKS_EXIST (1 << 0) #define WATERMARKS_LOADED (1 << 1) uint32_t watermarks_bitmap; + uint32_t hard_min_uclk_req_from_dal; + bool disable_uclk_switch; uint32_t workload_mask; uint32_t workload_prority[WORKLOAD_POLICY_MAX]; @@ -547,11 +399,15 @@ struct smu_context uint32_t power_profile_mode; uint32_t default_power_profile_mode; bool pm_enabled; + bool is_apu; uint32_t smc_if_version; + bool uploading_custom_pp_table; }; +struct i2c_adapter; + struct pptable_funcs { int (*alloc_dpm_context)(struct smu_context *smu); int (*store_powerplay_table)(struct smu_context *smu); @@ -563,7 +419,7 @@ struct pptable_funcs { int (*get_smu_table_index)(struct smu_context *smu, uint32_t index); int (*get_smu_power_index)(struct smu_context *smu, uint32_t index); int (*get_workload_type)(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile); - int (*run_afll_btc)(struct smu_context *smu); + int (*run_btc)(struct smu_context *smu); int (*get_allowed_feature_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num); enum amd_pm_state_type (*get_current_power_state)(struct smu_context *smu); int (*set_default_dpm_table)(struct smu_context *smu); @@ -593,12 +449,13 @@ struct pptable_funcs { int (*set_power_profile_mode)(struct smu_context *smu, long *input, uint32_t size); int (*dpm_set_uvd_enable)(struct smu_context *smu, bool enable); int (*dpm_set_vce_enable)(struct smu_context *smu, bool enable); + int (*dpm_set_jpeg_enable)(struct smu_context *smu, bool enable); int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size); int (*pre_display_config_changed)(struct smu_context *smu); int (*display_config_changed)(struct smu_context *smu); int (*apply_clocks_adjust_rules)(struct smu_context *smu); - int (*notify_smc_dispaly_config)(struct smu_context *smu); + int (*notify_smc_display_config)(struct smu_context *smu); int (*force_dpm_limit_value)(struct smu_context *smu, bool highest); int (*unforce_dpm_levels)(struct smu_context *smu); int (*get_profiling_clk_mask)(struct smu_context *smu, @@ -607,8 +464,6 @@ struct pptable_funcs { uint32_t *mclk_mask, uint32_t *soc_mask); int (*set_cpu_power_state)(struct smu_context *smu); - int (*set_ppfeature_status)(struct smu_context *smu, uint64_t ppfeatures); - int (*get_ppfeature_status)(struct smu_context *smu, char *buf); bool (*is_dpm_running)(struct smu_context *smu); int (*tables_init)(struct smu_context *smu, struct smu_table *tables); int (*set_thermal_fan_table)(struct smu_context *smu); @@ -623,46 +478,53 @@ struct pptable_funcs { int (*get_uclk_dpm_states)(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states); int (*set_default_od_settings)(struct smu_context *smu, bool initialize); int (*set_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level); -}; - -struct smu_funcs -{ + int (*display_disable_memory_clock_switch)(struct smu_context *smu, bool disable_memory_clock_switch); + void (*dump_pptable)(struct smu_context *smu); + int (*get_power_limit)(struct smu_context *smu, uint32_t *limit, bool asic_default); + int (*get_dpm_clk_limited)(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t dpm_level, uint32_t *freq); + int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state); + int (*update_pcie_parameters)(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap); + int (*i2c_eeprom_init)(struct i2c_adapter *control); + void (*i2c_eeprom_fini)(struct i2c_adapter *control); + int (*get_dpm_clock_table)(struct smu_context *smu, struct dpm_clocks *clock_table); int (*init_microcode)(struct smu_context *smu); + int (*load_microcode)(struct smu_context *smu); int (*init_smc_tables)(struct smu_context *smu); int (*fini_smc_tables)(struct smu_context *smu); int (*init_power)(struct smu_context *smu); int (*fini_power)(struct smu_context *smu); - int (*load_microcode)(struct smu_context *smu); int (*check_fw_status)(struct smu_context *smu); int (*setup_pptable)(struct smu_context *smu); int (*get_vbios_bootup_values)(struct smu_context *smu); int (*get_clk_info_from_vbios)(struct smu_context *smu); int (*check_pptable)(struct smu_context *smu); int (*parse_pptable)(struct smu_context *smu); - int (*populate_smc_pptable)(struct smu_context *smu); + int (*populate_smc_tables)(struct smu_context *smu); int (*check_fw_version)(struct smu_context *smu); + int (*powergate_sdma)(struct smu_context *smu, bool gate); + int (*powergate_vcn)(struct smu_context *smu, bool gate); + int (*powergate_jpeg)(struct smu_context *smu, bool gate); + int (*set_gfx_cgpg)(struct smu_context *smu, bool enable); int (*write_pptable)(struct smu_context *smu); int (*set_min_dcef_deep_sleep)(struct smu_context *smu); + int (*set_driver_table_location)(struct smu_context *smu); int (*set_tool_table_location)(struct smu_context *smu); int (*notify_memory_pool_location)(struct smu_context *smu); - int (*write_watermarks_table)(struct smu_context *smu); int (*set_last_dcef_min_deep_sleep_clk)(struct smu_context *smu); int (*system_features_control)(struct smu_context *smu, bool en); - int (*send_smc_msg)(struct smu_context *smu, uint16_t msg); - int (*send_smc_msg_with_param)(struct smu_context *smu, uint16_t msg, uint32_t param); + int (*send_smc_msg_with_param)(struct smu_context *smu, + enum smu_message_type msg, uint32_t param); int (*read_smc_arg)(struct smu_context *smu, uint32_t *arg); int (*init_display_count)(struct smu_context *smu, uint32_t count); int (*set_allowed_mask)(struct smu_context *smu); int (*get_enabled_mask)(struct smu_context *smu, uint32_t *feature_mask, uint32_t num); - int (*update_feature_enable_state)(struct smu_context *smu, uint32_t feature_id, bool enabled); int (*notify_display_change)(struct smu_context *smu); - int (*get_power_limit)(struct smu_context *smu, uint32_t *limit, bool def); int (*set_power_limit)(struct smu_context *smu, uint32_t n); int (*get_current_clk_freq)(struct smu_context *smu, enum smu_clk_type clk_id, uint32_t *value); int (*init_max_sustainable_clocks)(struct smu_context *smu); int (*start_thermal_control)(struct smu_context *smu); - int (*read_sensor)(struct smu_context *smu, enum amd_pp_sensors sensor, - void *data, uint32_t *size); + int (*stop_thermal_control)(struct smu_context *smu); int (*set_deep_sleep_dcefclk)(struct smu_context *smu, uint32_t clk); int (*set_active_display_count)(struct smu_context *smu, uint32_t count); int (*store_cc6_data)(struct smu_context *smu, uint32_t separation_time, @@ -684,8 +546,6 @@ struct smu_funcs int (*get_current_shallow_sleep_clocks)(struct smu_context *smu, struct smu_clock_info *clocks); int (*notify_smu_enable_pwe)(struct smu_context *smu); - int (*set_watermarks_for_clock_ranges)(struct smu_context *smu, - struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges); int (*conv_power_profile_to_pplib_workload)(int power_profile); uint32_t (*get_fan_control_mode)(struct smu_context *smu); int (*set_fan_control_mode)(struct smu_context *smu, uint32_t mode); @@ -699,229 +559,94 @@ struct smu_funcs bool (*baco_is_support)(struct smu_context *smu); enum smu_baco_state (*baco_get_state)(struct smu_context *smu); int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state); - int (*baco_reset)(struct smu_context *smu); - -}; - -#define smu_init_microcode(smu) \ - ((smu)->funcs->init_microcode ? (smu)->funcs->init_microcode((smu)) : 0) -#define smu_init_smc_tables(smu) \ - ((smu)->funcs->init_smc_tables ? (smu)->funcs->init_smc_tables((smu)) : 0) -#define smu_fini_smc_tables(smu) \ - ((smu)->funcs->fini_smc_tables ? (smu)->funcs->fini_smc_tables((smu)) : 0) -#define smu_init_power(smu) \ - ((smu)->funcs->init_power ? (smu)->funcs->init_power((smu)) : 0) -#define smu_fini_power(smu) \ - ((smu)->funcs->fini_power ? (smu)->funcs->fini_power((smu)) : 0) -#define smu_load_microcode(smu) \ - ((smu)->funcs->load_microcode ? (smu)->funcs->load_microcode((smu)) : 0) -#define smu_check_fw_status(smu) \ - ((smu)->funcs->check_fw_status ? (smu)->funcs->check_fw_status((smu)) : 0) -#define smu_setup_pptable(smu) \ - ((smu)->funcs->setup_pptable ? (smu)->funcs->setup_pptable((smu)) : 0) -#define smu_get_vbios_bootup_values(smu) \ - ((smu)->funcs->get_vbios_bootup_values ? (smu)->funcs->get_vbios_bootup_values((smu)) : 0) -#define smu_get_clk_info_from_vbios(smu) \ - ((smu)->funcs->get_clk_info_from_vbios ? (smu)->funcs->get_clk_info_from_vbios((smu)) : 0) -#define smu_check_pptable(smu) \ - ((smu)->funcs->check_pptable ? (smu)->funcs->check_pptable((smu)) : 0) -#define smu_parse_pptable(smu) \ - ((smu)->funcs->parse_pptable ? (smu)->funcs->parse_pptable((smu)) : 0) -#define smu_populate_smc_pptable(smu) \ - ((smu)->funcs->populate_smc_pptable ? (smu)->funcs->populate_smc_pptable((smu)) : 0) -#define smu_check_fw_version(smu) \ - ((smu)->funcs->check_fw_version ? (smu)->funcs->check_fw_version((smu)) : 0) -#define smu_write_pptable(smu) \ - ((smu)->funcs->write_pptable ? (smu)->funcs->write_pptable((smu)) : 0) -#define smu_set_min_dcef_deep_sleep(smu) \ - ((smu)->funcs->set_min_dcef_deep_sleep ? (smu)->funcs->set_min_dcef_deep_sleep((smu)) : 0) -#define smu_set_tool_table_location(smu) \ - ((smu)->funcs->set_tool_table_location ? (smu)->funcs->set_tool_table_location((smu)) : 0) -#define smu_notify_memory_pool_location(smu) \ - ((smu)->funcs->notify_memory_pool_location ? (smu)->funcs->notify_memory_pool_location((smu)) : 0) -#define smu_gfx_off_control(smu, enable) \ - ((smu)->funcs->gfx_off_control ? (smu)->funcs->gfx_off_control((smu), (enable)) : 0) - -#define smu_write_watermarks_table(smu) \ - ((smu)->funcs->write_watermarks_table ? (smu)->funcs->write_watermarks_table((smu)) : 0) -#define smu_set_last_dcef_min_deep_sleep_clk(smu) \ - ((smu)->funcs->set_last_dcef_min_deep_sleep_clk ? (smu)->funcs->set_last_dcef_min_deep_sleep_clk((smu)) : 0) -#define smu_system_features_control(smu, en) \ - ((smu)->funcs->system_features_control ? (smu)->funcs->system_features_control((smu), (en)) : 0) -#define smu_init_max_sustainable_clocks(smu) \ - ((smu)->funcs->init_max_sustainable_clocks ? (smu)->funcs->init_max_sustainable_clocks((smu)) : 0) -#define smu_set_default_od_settings(smu, initialize) \ - ((smu)->ppt_funcs->set_default_od_settings ? (smu)->ppt_funcs->set_default_od_settings((smu), (initialize)) : 0) -#define smu_set_fan_speed_rpm(smu, speed) \ - ((smu)->funcs->set_fan_speed_rpm ? (smu)->funcs->set_fan_speed_rpm((smu), (speed)) : 0) -#define smu_send_smc_msg(smu, msg) \ - ((smu)->funcs->send_smc_msg? (smu)->funcs->send_smc_msg((smu), (msg)) : 0) -#define smu_send_smc_msg_with_param(smu, msg, param) \ - ((smu)->funcs->send_smc_msg_with_param? (smu)->funcs->send_smc_msg_with_param((smu), (msg), (param)) : 0) -#define smu_read_smc_arg(smu, arg) \ - ((smu)->funcs->read_smc_arg? (smu)->funcs->read_smc_arg((smu), (arg)) : 0) -#define smu_alloc_dpm_context(smu) \ - ((smu)->ppt_funcs->alloc_dpm_context ? (smu)->ppt_funcs->alloc_dpm_context((smu)) : 0) -#define smu_init_display_count(smu, count) \ - ((smu)->funcs->init_display_count ? (smu)->funcs->init_display_count((smu), (count)) : 0) -#define smu_feature_set_allowed_mask(smu) \ - ((smu)->funcs->set_allowed_mask? (smu)->funcs->set_allowed_mask((smu)) : 0) -#define smu_feature_get_enabled_mask(smu, mask, num) \ - ((smu)->funcs->get_enabled_mask? (smu)->funcs->get_enabled_mask((smu), (mask), (num)) : 0) -#define smu_is_dpm_running(smu) \ - ((smu)->ppt_funcs->is_dpm_running ? (smu)->ppt_funcs->is_dpm_running((smu)) : 0) -#define smu_feature_update_enable_state(smu, feature_id, enabled) \ - ((smu)->funcs->update_feature_enable_state? (smu)->funcs->update_feature_enable_state((smu), (feature_id), (enabled)) : 0) -#define smu_notify_display_change(smu) \ - ((smu)->funcs->notify_display_change? (smu)->funcs->notify_display_change((smu)) : 0) -#define smu_store_powerplay_table(smu) \ - ((smu)->ppt_funcs->store_powerplay_table ? (smu)->ppt_funcs->store_powerplay_table((smu)) : 0) -#define smu_check_powerplay_table(smu) \ - ((smu)->ppt_funcs->check_powerplay_table ? (smu)->ppt_funcs->check_powerplay_table((smu)) : 0) -#define smu_append_powerplay_table(smu) \ - ((smu)->ppt_funcs->append_powerplay_table ? (smu)->ppt_funcs->append_powerplay_table((smu)) : 0) -#define smu_set_default_dpm_table(smu) \ - ((smu)->ppt_funcs->set_default_dpm_table ? (smu)->ppt_funcs->set_default_dpm_table((smu)) : 0) -#define smu_populate_umd_state_clk(smu) \ - ((smu)->ppt_funcs->populate_umd_state_clk ? (smu)->ppt_funcs->populate_umd_state_clk((smu)) : 0) -#define smu_set_default_od8_settings(smu) \ - ((smu)->ppt_funcs->set_default_od8_settings ? (smu)->ppt_funcs->set_default_od8_settings((smu)) : 0) -#define smu_get_power_limit(smu, limit, def) \ - ((smu)->funcs->get_power_limit ? (smu)->funcs->get_power_limit((smu), (limit), (def)) : 0) -#define smu_set_power_limit(smu, limit) \ - ((smu)->funcs->set_power_limit ? (smu)->funcs->set_power_limit((smu), (limit)) : 0) -#define smu_get_current_clk_freq(smu, clk_id, value) \ - ((smu)->funcs->get_current_clk_freq? (smu)->funcs->get_current_clk_freq((smu), (clk_id), (value)) : 0) -#define smu_print_clk_levels(smu, clk_type, buf) \ - ((smu)->ppt_funcs->print_clk_levels ? (smu)->ppt_funcs->print_clk_levels((smu), (clk_type), (buf)) : 0) -#define smu_force_clk_levels(smu, clk_type, level) \ - ((smu)->ppt_funcs->force_clk_levels ? (smu)->ppt_funcs->force_clk_levels((smu), (clk_type), (level)) : 0) -#define smu_get_od_percentage(smu, type) \ - ((smu)->ppt_funcs->get_od_percentage ? (smu)->ppt_funcs->get_od_percentage((smu), (type)) : 0) -#define smu_set_od_percentage(smu, type, value) \ - ((smu)->ppt_funcs->set_od_percentage ? (smu)->ppt_funcs->set_od_percentage((smu), (type), (value)) : 0) -#define smu_od_edit_dpm_table(smu, type, input, size) \ - ((smu)->ppt_funcs->od_edit_dpm_table ? (smu)->ppt_funcs->od_edit_dpm_table((smu), (type), (input), (size)) : 0) -#define smu_tables_init(smu, tab) \ - ((smu)->ppt_funcs->tables_init ? (smu)->ppt_funcs->tables_init((smu), (tab)) : 0) -#define smu_set_thermal_fan_table(smu) \ - ((smu)->ppt_funcs->set_thermal_fan_table ? (smu)->ppt_funcs->set_thermal_fan_table((smu)) : 0) -#define smu_start_thermal_control(smu) \ - ((smu)->funcs->start_thermal_control? (smu)->funcs->start_thermal_control((smu)) : 0) -#define smu_read_sensor(smu, sensor, data, size) \ - ((smu)->funcs->read_sensor? (smu)->funcs->read_sensor((smu), (sensor), (data), (size)) : 0) -#define smu_asic_read_sensor(smu, sensor, data, size) \ - ((smu)->ppt_funcs->read_sensor? (smu)->ppt_funcs->read_sensor((smu), (sensor), (data), (size)) : 0) -#define smu_get_power_profile_mode(smu, buf) \ - ((smu)->ppt_funcs->get_power_profile_mode ? (smu)->ppt_funcs->get_power_profile_mode((smu), buf) : 0) -#define smu_set_power_profile_mode(smu, param, param_size) \ - ((smu)->ppt_funcs->set_power_profile_mode ? (smu)->ppt_funcs->set_power_profile_mode((smu), (param), (param_size)) : 0) -#define smu_pre_display_config_changed(smu) \ - ((smu)->ppt_funcs->pre_display_config_changed ? (smu)->ppt_funcs->pre_display_config_changed((smu)) : 0) -#define smu_display_config_changed(smu) \ - ((smu)->ppt_funcs->display_config_changed ? (smu)->ppt_funcs->display_config_changed((smu)) : 0) -#define smu_apply_clocks_adjust_rules(smu) \ - ((smu)->ppt_funcs->apply_clocks_adjust_rules ? (smu)->ppt_funcs->apply_clocks_adjust_rules((smu)) : 0) -#define smu_notify_smc_dispaly_config(smu) \ - ((smu)->ppt_funcs->notify_smc_dispaly_config ? (smu)->ppt_funcs->notify_smc_dispaly_config((smu)) : 0) -#define smu_force_dpm_limit_value(smu, highest) \ - ((smu)->ppt_funcs->force_dpm_limit_value ? (smu)->ppt_funcs->force_dpm_limit_value((smu), (highest)) : 0) -#define smu_unforce_dpm_levels(smu) \ - ((smu)->ppt_funcs->unforce_dpm_levels ? (smu)->ppt_funcs->unforce_dpm_levels((smu)) : 0) -#define smu_get_profiling_clk_mask(smu, level, sclk_mask, mclk_mask, soc_mask) \ - ((smu)->ppt_funcs->get_profiling_clk_mask ? (smu)->ppt_funcs->get_profiling_clk_mask((smu), (level), (sclk_mask), (mclk_mask), (soc_mask)) : 0) -#define smu_set_cpu_power_state(smu) \ - ((smu)->ppt_funcs->set_cpu_power_state ? (smu)->ppt_funcs->set_cpu_power_state((smu)) : 0) -#define smu_get_fan_control_mode(smu) \ - ((smu)->funcs->get_fan_control_mode ? (smu)->funcs->get_fan_control_mode((smu)) : 0) -#define smu_set_fan_control_mode(smu, value) \ - ((smu)->funcs->set_fan_control_mode ? (smu)->funcs->set_fan_control_mode((smu), (value)) : 0) -#define smu_get_fan_speed_percent(smu, speed) \ - ((smu)->ppt_funcs->get_fan_speed_percent ? (smu)->ppt_funcs->get_fan_speed_percent((smu), (speed)) : 0) -#define smu_set_fan_speed_percent(smu, speed) \ - ((smu)->funcs->set_fan_speed_percent ? (smu)->funcs->set_fan_speed_percent((smu), (speed)) : 0) -#define smu_get_fan_speed_rpm(smu, speed) \ - ((smu)->ppt_funcs->get_fan_speed_rpm ? (smu)->ppt_funcs->get_fan_speed_rpm((smu), (speed)) : 0) - -#define smu_msg_get_index(smu, msg) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_msg_index? (smu)->ppt_funcs->get_smu_msg_index((smu), (msg)) : -EINVAL) : -EINVAL) -#define smu_clk_get_index(smu, msg) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_clk_index? (smu)->ppt_funcs->get_smu_clk_index((smu), (msg)) : -EINVAL) : -EINVAL) -#define smu_feature_get_index(smu, msg) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_feature_index? (smu)->ppt_funcs->get_smu_feature_index((smu), (msg)) : -EINVAL) : -EINVAL) -#define smu_table_get_index(smu, tab) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_table_index? (smu)->ppt_funcs->get_smu_table_index((smu), (tab)) : -EINVAL) : -EINVAL) -#define smu_power_get_index(smu, src) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_power_index? (smu)->ppt_funcs->get_smu_power_index((smu), (src)) : -EINVAL) : -EINVAL) -#define smu_workload_get_type(smu, profile) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_workload_type? (smu)->ppt_funcs->get_workload_type((smu), (profile)) : -EINVAL) : -EINVAL) -#define smu_run_afll_btc(smu) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->run_afll_btc? (smu)->ppt_funcs->run_afll_btc((smu)) : 0) : 0) -#define smu_get_allowed_feature_mask(smu, feature_mask, num) \ - ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_allowed_feature_mask? (smu)->ppt_funcs->get_allowed_feature_mask((smu), (feature_mask), (num)) : 0) : 0) -#define smu_set_deep_sleep_dcefclk(smu, clk) \ - ((smu)->funcs->set_deep_sleep_dcefclk ? (smu)->funcs->set_deep_sleep_dcefclk((smu), (clk)) : 0) -#define smu_set_active_display_count(smu, count) \ - ((smu)->funcs->set_active_display_count ? (smu)->funcs->set_active_display_count((smu), (count)) : 0) -#define smu_store_cc6_data(smu, st, cc6_dis, pst_dis, pst_sw_dis) \ - ((smu)->funcs->store_cc6_data ? (smu)->funcs->store_cc6_data((smu), (st), (cc6_dis), (pst_dis), (pst_sw_dis)) : 0) -#define smu_get_clock_by_type(smu, type, clocks) \ - ((smu)->funcs->get_clock_by_type ? (smu)->funcs->get_clock_by_type((smu), (type), (clocks)) : 0) -#define smu_get_max_high_clocks(smu, clocks) \ - ((smu)->funcs->get_max_high_clocks ? (smu)->funcs->get_max_high_clocks((smu), (clocks)) : 0) -#define smu_get_clock_by_type_with_latency(smu, clk_type, clocks) \ - ((smu)->ppt_funcs->get_clock_by_type_with_latency ? (smu)->ppt_funcs->get_clock_by_type_with_latency((smu), (clk_type), (clocks)) : 0) -#define smu_get_clock_by_type_with_voltage(smu, type, clocks) \ - ((smu)->ppt_funcs->get_clock_by_type_with_voltage ? (smu)->ppt_funcs->get_clock_by_type_with_voltage((smu), (type), (clocks)) : 0) -#define smu_display_clock_voltage_request(smu, clock_req) \ - ((smu)->funcs->display_clock_voltage_request ? (smu)->funcs->display_clock_voltage_request((smu), (clock_req)) : 0) -#define smu_get_dal_power_level(smu, clocks) \ - ((smu)->funcs->get_dal_power_level ? (smu)->funcs->get_dal_power_level((smu), (clocks)) : 0) -#define smu_get_perf_level(smu, designation, level) \ - ((smu)->funcs->get_perf_level ? (smu)->funcs->get_perf_level((smu), (designation), (level)) : 0) -#define smu_get_current_shallow_sleep_clocks(smu, clocks) \ - ((smu)->funcs->get_current_shallow_sleep_clocks ? (smu)->funcs->get_current_shallow_sleep_clocks((smu), (clocks)) : 0) -#define smu_notify_smu_enable_pwe(smu) \ - ((smu)->funcs->notify_smu_enable_pwe ? (smu)->funcs->notify_smu_enable_pwe((smu)) : 0) -#define smu_set_watermarks_for_clock_ranges(smu, clock_ranges) \ - ((smu)->funcs->set_watermarks_for_clock_ranges ? (smu)->funcs->set_watermarks_for_clock_ranges((smu), (clock_ranges)) : 0) -#define smu_dpm_set_uvd_enable(smu, enable) \ - ((smu)->ppt_funcs->dpm_set_uvd_enable ? (smu)->ppt_funcs->dpm_set_uvd_enable((smu), (enable)) : 0) -#define smu_dpm_set_vce_enable(smu, enable) \ - ((smu)->ppt_funcs->dpm_set_vce_enable ? (smu)->ppt_funcs->dpm_set_vce_enable((smu), (enable)) : 0) -#define smu_set_xgmi_pstate(smu, pstate) \ - ((smu)->funcs->set_xgmi_pstate ? (smu)->funcs->set_xgmi_pstate((smu), (pstate)) : 0) -#define smu_set_ppfeature_status(smu, ppfeatures) \ - ((smu)->ppt_funcs->set_ppfeature_status ? (smu)->ppt_funcs->set_ppfeature_status((smu), (ppfeatures)) : -EINVAL) -#define smu_get_ppfeature_status(smu, buf) \ - ((smu)->ppt_funcs->get_ppfeature_status ? (smu)->ppt_funcs->get_ppfeature_status((smu), (buf)) : -EINVAL) -#define smu_set_watermarks_table(smu, tab, clock_ranges) \ - ((smu)->ppt_funcs->set_watermarks_table ? (smu)->ppt_funcs->set_watermarks_table((smu), (tab), (clock_ranges)) : 0) -#define smu_get_current_clk_freq_by_table(smu, clk_type, value) \ - ((smu)->ppt_funcs->get_current_clk_freq_by_table ? (smu)->ppt_funcs->get_current_clk_freq_by_table((smu), (clk_type), (value)) : 0) -#define smu_thermal_temperature_range_update(smu, range, rw) \ - ((smu)->ppt_funcs->thermal_temperature_range_update? (smu)->ppt_funcs->thermal_temperature_range_update((smu), (range), (rw)) : 0) -#define smu_get_thermal_temperature_range(smu, range) \ - ((smu)->ppt_funcs->get_thermal_temperature_range? (smu)->ppt_funcs->get_thermal_temperature_range((smu), (range)) : 0) -#define smu_register_irq_handler(smu) \ - ((smu)->funcs->register_irq_handler ? (smu)->funcs->register_irq_handler(smu) : 0) -#define smu_set_azalia_d3_pme(smu) \ - ((smu)->funcs->set_azalia_d3_pme ? (smu)->funcs->set_azalia_d3_pme((smu)) : 0) -#define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \ - ((smu)->ppt_funcs->get_uclk_dpm_states ? (smu)->ppt_funcs->get_uclk_dpm_states((smu), (clocks_in_khz), (num_states)) : 0) -#define smu_get_max_sustainable_clocks_by_dc(smu, max_clocks) \ - ((smu)->funcs->get_max_sustainable_clocks_by_dc ? (smu)->funcs->get_max_sustainable_clocks_by_dc((smu), (max_clocks)) : 0) -#define smu_get_uclk_dpm_states(smu, clocks_in_khz, num_states) \ - ((smu)->ppt_funcs->get_uclk_dpm_states ? (smu)->ppt_funcs->get_uclk_dpm_states((smu), (clocks_in_khz), (num_states)) : 0) -#define smu_baco_is_support(smu) \ - ((smu)->funcs->baco_is_support? (smu)->funcs->baco_is_support((smu)) : false) -#define smu_baco_get_state(smu, state) \ - ((smu)->funcs->baco_get_state? (smu)->funcs->baco_get_state((smu), (state)) : 0) -#define smu_baco_reset(smu) \ - ((smu)->funcs->baco_reset? (smu)->funcs->baco_reset((smu)) : 0) -#define smu_asic_set_performance_level(smu, level) \ - ((smu)->ppt_funcs->set_performance_level? (smu)->ppt_funcs->set_performance_level((smu), (level)) : -EINVAL); + int (*baco_enter)(struct smu_context *smu); + int (*baco_exit)(struct smu_context *smu); + int (*mode2_reset)(struct smu_context *smu); + int (*get_dpm_ultimate_freq)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *min, uint32_t *max); + int (*set_soft_freq_limited_range)(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); + int (*override_pcie_parameters)(struct smu_context *smu); + uint32_t (*get_pptable_power_limit)(struct smu_context *smu); + int (*disable_umc_cdr_12gbps_workaround)(struct smu_context *smu); +}; + +int smu_load_microcode(struct smu_context *smu); + +int smu_check_fw_status(struct smu_context *smu); +int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled); + +#define smu_i2c_eeprom_init(smu, control) \ + ((smu)->ppt_funcs->i2c_eeprom_init ? (smu)->ppt_funcs->i2c_eeprom_init((control)) : -EINVAL) +#define smu_i2c_eeprom_fini(smu, control) \ + ((smu)->ppt_funcs->i2c_eeprom_fini ? (smu)->ppt_funcs->i2c_eeprom_fini((control)) : -EINVAL) + +int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed); + +int smu_get_power_limit(struct smu_context *smu, + uint32_t *limit, + bool def, + bool lock_needed); + +int smu_set_power_limit(struct smu_context *smu, uint32_t limit); +int smu_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf); +int smu_get_od_percentage(struct smu_context *smu, enum smu_clk_type type); +int smu_set_od_percentage(struct smu_context *smu, enum smu_clk_type type, uint32_t value); + +int smu_od_edit_dpm_table(struct smu_context *smu, + enum PP_OD_DPM_TABLE_COMMAND type, + long *input, uint32_t size); + +int smu_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size); +int smu_get_power_profile_mode(struct smu_context *smu, char *buf); + +int smu_set_power_profile_mode(struct smu_context *smu, + long *param, + uint32_t param_size, + bool lock_needed); +int smu_get_fan_control_mode(struct smu_context *smu); +int smu_set_fan_control_mode(struct smu_context *smu, int value); +int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed); +int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed); +int smu_get_fan_speed_rpm(struct smu_context *smu, uint32_t *speed); + +int smu_set_deep_sleep_dcefclk(struct smu_context *smu, int clk); +int smu_set_active_display_count(struct smu_context *smu, uint32_t count); + +int smu_get_clock_by_type(struct smu_context *smu, + enum amd_pp_clock_type type, + struct amd_pp_clocks *clocks); + +int smu_get_max_high_clocks(struct smu_context *smu, + struct amd_pp_simple_clock_info *clocks); + +int smu_get_clock_by_type_with_latency(struct smu_context *smu, + enum smu_clk_type clk_type, + struct pp_clock_levels_with_latency *clocks); + +int smu_get_clock_by_type_with_voltage(struct smu_context *smu, + enum amd_pp_clock_type type, + struct pp_clock_levels_with_voltage *clocks); + +int smu_display_clock_voltage_request(struct smu_context *smu, + struct pp_display_clock_request *clock_req); +int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disable_memory_clock_switch); +int smu_notify_smu_enable_pwe(struct smu_context *smu); + +int smu_set_xgmi_pstate(struct smu_context *smu, + uint32_t pstate); + +int smu_set_azalia_d3_pme(struct smu_context *smu); + +bool smu_baco_is_support(struct smu_context *smu); + +int smu_baco_get_state(struct smu_context *smu, enum smu_baco_state *state); + +int smu_baco_enter(struct smu_context *smu); +int smu_baco_exit(struct smu_context *smu); + +int smu_mode2_reset(struct smu_context *smu); extern int smu_get_atom_data_table(struct smu_context *smu, uint32_t table, uint16_t *size, uint8_t *frev, uint8_t *crev, @@ -930,6 +655,8 @@ extern int smu_get_atom_data_table(struct smu_context *smu, uint32_t table, extern const struct amd_ip_funcs smu_ip_funcs; extern const struct amdgpu_ip_block_version smu_v11_0_ip_block; +extern const struct amdgpu_ip_block_version smu_v12_0_ip_block; + extern int smu_feature_init_dpm(struct smu_context *smu); extern int smu_feature_is_enabled(struct smu_context *smu, @@ -945,6 +672,7 @@ int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int void *table_data, bool drv2smu); bool is_support_sw_smu(struct amdgpu_device *adev); +bool is_support_sw_smu_xgmi(struct amdgpu_device *adev); int smu_reset(struct smu_context *smu); int smu_common_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size); @@ -952,6 +680,10 @@ int smu_sys_get_pp_table(struct smu_context *smu, void **table); int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size); int smu_get_power_num_states(struct smu_context *smu, struct pp_states_info *state_info); enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu); +int smu_write_watermarks_table(struct smu_context *smu); +int smu_set_watermarks_for_clock_ranges( + struct smu_context *smu, + struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges); /* smu to display interface */ extern int smu_display_configuration_change(struct smu_context *smu, const @@ -962,21 +694,51 @@ extern int smu_get_current_clocks(struct smu_context *smu, extern int smu_dpm_set_power_gate(struct smu_context *smu,uint32_t block_type, bool gate); extern int smu_handle_task(struct smu_context *smu, enum amd_dpm_forced_level level, - enum amd_pp_task task_id); + enum amd_pp_task task_id, + bool lock_needed); +int smu_switch_power_profile(struct smu_context *smu, + enum PP_SMC_POWER_PROFILE type, + bool en); int smu_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t *smu_version); int smu_get_dpm_freq_by_index(struct smu_context *smu, enum smu_clk_type clk_type, uint16_t level, uint32_t *value); int smu_get_dpm_level_count(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *value); int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t *min, uint32_t *max); + uint32_t *min, uint32_t *max, bool lock_needed); int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); int smu_set_hard_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t min, uint32_t max); +int smu_get_dpm_level_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min_value, uint32_t *max_value); enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu); int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level); int smu_set_display_count(struct smu_context *smu, uint32_t count); bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type); +const char *smu_get_message_name(struct smu_context *smu, enum smu_message_type type); +const char *smu_get_feature_name(struct smu_context *smu, enum smu_feature_mask feature); +size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf); +int smu_sys_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask); +int smu_force_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t mask, + bool lock_needed); +int smu_set_mp1_state(struct smu_context *smu, + enum pp_mp1_state mp1_state); +int smu_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state); + +int smu_get_max_sustainable_clocks_by_dc(struct smu_context *smu, + struct pp_smu_nv_clock_table *max_clocks); + +int smu_get_uclk_dpm_states(struct smu_context *smu, + unsigned int *clock_values_in_khz, + unsigned int *num_states); + +int smu_get_dpm_clock_table(struct smu_context *smu, + struct dpm_clocks *clock_table); + +uint32_t smu_get_pptable_power_limit(struct smu_context *smu); #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h new file mode 100644 index 000000000000..e3291259b249 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h @@ -0,0 +1,119 @@ +/* + * Copyright 2019 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 ARCTURUS_PP_SMC_H +#define ARCTURUS_PP_SMC_H + +#pragma pack(push, 1) + +// SMU Response Codes: +#define PPSMC_Result_OK 0x1 +#define PPSMC_Result_Failed 0xFF +#define PPSMC_Result_UnknownCmd 0xFE +#define PPSMC_Result_CmdRejectedPrereq 0xFD +#define PPSMC_Result_CmdRejectedBusy 0xFC + +// Message Definitions: +// BASIC +#define PPSMC_MSG_TestMessage 0x1 +#define PPSMC_MSG_GetSmuVersion 0x2 +#define PPSMC_MSG_GetDriverIfVersion 0x3 +#define PPSMC_MSG_SetAllowedFeaturesMaskLow 0x4 +#define PPSMC_MSG_SetAllowedFeaturesMaskHigh 0x5 +#define PPSMC_MSG_EnableAllSmuFeatures 0x6 +#define PPSMC_MSG_DisableAllSmuFeatures 0x7 +#define PPSMC_MSG_EnableSmuFeaturesLow 0x8 +#define PPSMC_MSG_EnableSmuFeaturesHigh 0x9 +#define PPSMC_MSG_DisableSmuFeaturesLow 0xA +#define PPSMC_MSG_DisableSmuFeaturesHigh 0xB +#define PPSMC_MSG_GetEnabledSmuFeaturesLow 0xC +#define PPSMC_MSG_GetEnabledSmuFeaturesHigh 0xD +#define PPSMC_MSG_SetDriverDramAddrHigh 0xE +#define PPSMC_MSG_SetDriverDramAddrLow 0xF +#define PPSMC_MSG_SetToolsDramAddrHigh 0x10 +#define PPSMC_MSG_SetToolsDramAddrLow 0x11 +#define PPSMC_MSG_TransferTableSmu2Dram 0x12 +#define PPSMC_MSG_TransferTableDram2Smu 0x13 +#define PPSMC_MSG_UseDefaultPPTable 0x14 +#define PPSMC_MSG_UseBackupPPTable 0x15 +#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x16 +#define PPSMC_MSG_SetSystemVirtualDramAddrLow 0x17 + +//BACO/BAMACO/BOMACO +#define PPSMC_MSG_EnterBaco 0x18 +#define PPSMC_MSG_ExitBaco 0x19 +#define PPSMC_MSG_ArmD3 0x1A + +//DPM +#define PPSMC_MSG_SetSoftMinByFreq 0x1B +#define PPSMC_MSG_SetSoftMaxByFreq 0x1C +#define PPSMC_MSG_SetHardMinByFreq 0x1D +#define PPSMC_MSG_SetHardMaxByFreq 0x1E +#define PPSMC_MSG_GetMinDpmFreq 0x1F +#define PPSMC_MSG_GetMaxDpmFreq 0x20 +#define PPSMC_MSG_GetDpmFreqByIndex 0x21 + +#define PPSMC_MSG_SetWorkloadMask 0x22 +#define PPSMC_MSG_SetDfSwitchType 0x23 +#define PPSMC_MSG_GetVoltageByDpm 0x24 +#define PPSMC_MSG_GetVoltageByDpmOverdrive 0x25 + +#define PPSMC_MSG_SetPptLimit 0x26 +#define PPSMC_MSG_GetPptLimit 0x27 + +//Power Gating +#define PPSMC_MSG_PowerUpVcn0 0x28 +#define PPSMC_MSG_PowerDownVcn0 0x29 +#define PPSMC_MSG_PowerUpVcn1 0x2A +#define PPSMC_MSG_PowerDownVcn1 0x2B + +//Resets and reload +#define PPSMC_MSG_PrepareMp1ForUnload 0x2C +#define PPSMC_MSG_PrepareMp1ForReset 0x2D +#define PPSMC_MSG_PrepareMp1ForShutdown 0x2E +#define PPSMC_MSG_SoftReset 0x2F + +//BTC +#define PPSMC_MSG_RunAfllBtc 0x30 +#define PPSMC_MSG_RunDcBtc 0x31 + +//Debug +#define PPSMC_MSG_DramLogSetDramAddrHigh 0x33 +#define PPSMC_MSG_DramLogSetDramAddrLow 0x34 +#define PPSMC_MSG_DramLogSetDramSize 0x35 +#define PPSMC_MSG_GetDebugData 0x36 + +//WAFL and XGMI +#define PPSMC_MSG_WaflTest 0x37 +#define PPSMC_MSG_SetXgmiMode 0x38 + +//Others +#define PPSMC_MSG_SetMemoryChannelEnable 0x39 + +#define PPSMC_Message_Count 0x3A + +typedef uint32_t PPSMC_Result; +typedef uint32_t PPSMC_Msg; +#pragma pack(pop) + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index c5989cb38b1b..2ffb666b97e6 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -189,6 +189,14 @@ struct phm_vce_clock_voltage_dependency_table { struct phm_vce_clock_voltage_dependency_record entries[1]; }; + +enum SMU_ASIC_RESET_MODE +{ + SMU_ASIC_RESET_MODE_0, + SMU_ASIC_RESET_MODE_1, + SMU_ASIC_RESET_MODE_2, +}; + struct pp_smumgr_func { char *name; int (*smu_init)(struct pp_hwmgr *hwmgr); @@ -344,6 +352,13 @@ struct pp_hwmgr_func { int (*set_asic_baco_state)(struct pp_hwmgr *hwmgr, enum BACO_STATE state); int (*get_ppfeature_status)(struct pp_hwmgr *hwmgr, char *buf); int (*set_ppfeature_status)(struct pp_hwmgr *hwmgr, uint64_t ppfeature_masks); + int (*set_mp1_state)(struct pp_hwmgr *hwmgr, enum pp_mp1_state mp1_state); + int (*asic_reset)(struct pp_hwmgr *hwmgr, enum SMU_ASIC_RESET_MODE mode); + int (*smu_i2c_bus_access)(struct pp_hwmgr *hwmgr, bool aquire); + int (*set_df_cstate)(struct pp_hwmgr *hwmgr, enum pp_df_cstate state); + int (*set_xgmi_pstate)(struct pp_hwmgr *hwmgr, uint32_t pstate); + int (*disable_power_features_for_compute_performance)(struct pp_hwmgr *hwmgr, + bool disable); }; struct pp_table_func { @@ -726,6 +741,7 @@ struct pp_hwmgr { uint32_t smu_version; bool not_vf; bool pm_en; + bool pp_one_vf; struct mutex smu_lock; uint32_t pp_table_version; diff --git a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h index 90879e4092a3..df4677da736c 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/rv_ppsmc.h @@ -59,7 +59,7 @@ #define PPSMC_MSG_SetDriverDramAddrLow 0x1B #define PPSMC_MSG_TransferTableSmu2Dram 0x1C #define PPSMC_MSG_TransferTableDram2Smu 0x1D -#define PPSMC_MSG_ControlGfxRM 0x1E +#define PPSMC_MSG_DeviceDriverReset 0x1E #define PPSMC_MSG_SetGfxclkOverdriveByFreqVid 0x1F #define PPSMC_MSG_SetHardMinDcefclkByFreq 0x20 #define PPSMC_MSG_SetHardMinSocclkByFreq 0x21 diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h index 755d51f9c6a9..fdc6b7a57bc9 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if.h @@ -27,7 +27,9 @@ // *** IMPORTANT *** // SMU TEAM: Always increment the interface version if // any structure is changed in this file -#define SMU11_DRIVER_IF_VERSION 0x13 +// Be aware of that the version should be updated in +// smu_v11_0.h, rename is also needed. +// #define SMU11_DRIVER_IF_VERSION 0x13 #define PPTABLE_V20_SMU_VERSION 3 diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h new file mode 100644 index 000000000000..ce5b5011c122 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h @@ -0,0 +1,912 @@ +/* + * Copyright 2019 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 SMU11_DRIVER_IF_ARCTURUS_H +#define SMU11_DRIVER_IF_ARCTURUS_H + +// *** IMPORTANT *** +// SMU TEAM: Always increment the interface version if +// any structure is changed in this file +//#define SMU11_DRIVER_IF_VERSION 0x09 + +#define PPTABLE_ARCTURUS_SMU_VERSION 4 + +#define NUM_GFXCLK_DPM_LEVELS 16 +#define NUM_VCLK_DPM_LEVELS 8 +#define NUM_DCLK_DPM_LEVELS 8 +#define NUM_MP0CLK_DPM_LEVELS 2 +#define NUM_SOCCLK_DPM_LEVELS 8 +#define NUM_UCLK_DPM_LEVELS 4 +#define NUM_FCLK_DPM_LEVELS 8 +#define NUM_XGMI_LEVELS 2 +#define NUM_XGMI_PSTATE_LEVELS 4 + +#define MAX_GFXCLK_DPM_LEVEL (NUM_GFXCLK_DPM_LEVELS - 1) +#define MAX_VCLK_DPM_LEVEL (NUM_VCLK_DPM_LEVELS - 1) +#define MAX_DCLK_DPM_LEVEL (NUM_DCLK_DPM_LEVELS - 1) +#define MAX_MP0CLK_DPM_LEVEL (NUM_MP0CLK_DPM_LEVELS - 1) +#define MAX_SOCCLK_DPM_LEVEL (NUM_SOCCLK_DPM_LEVELS - 1) +#define MAX_UCLK_DPM_LEVEL (NUM_UCLK_DPM_LEVELS - 1) +#define MAX_FCLK_DPM_LEVEL (NUM_FCLK_DPM_LEVELS - 1) +#define MAX_XGMI_LEVEL (NUM_XGMI_LEVELS - 1) +#define MAX_XGMI_PSTATE_LEVEL (NUM_XGMI_PSTATE_LEVELS - 1) + +// Feature Control Defines +// DPM +#define FEATURE_DPM_PREFETCHER_BIT 0 +#define FEATURE_DPM_GFXCLK_BIT 1 +#define FEATURE_DPM_UCLK_BIT 2 +#define FEATURE_DPM_SOCCLK_BIT 3 +#define FEATURE_DPM_FCLK_BIT 4 +#define FEATURE_DPM_MP0CLK_BIT 5 +#define FEATURE_DPM_XGMI_BIT 6 +// Idle +#define FEATURE_DS_GFXCLK_BIT 7 +#define FEATURE_DS_SOCCLK_BIT 8 +#define FEATURE_DS_LCLK_BIT 9 +#define FEATURE_DS_FCLK_BIT 10 +#define FEATURE_DS_UCLK_BIT 11 +#define FEATURE_GFX_ULV_BIT 12 +#define FEATURE_DPM_VCN_BIT 13 +#define FEATURE_RSMU_SMN_CG_BIT 14 +#define FEATURE_WAFL_CG_BIT 15 +// Throttler/Response +#define FEATURE_PPT_BIT 16 +#define FEATURE_TDC_BIT 17 +#define FEATURE_APCC_PLUS_BIT 18 +#define FEATURE_VR0HOT_BIT 19 +#define FEATURE_VR1HOT_BIT 20 +#define FEATURE_FW_CTF_BIT 21 +#define FEATURE_FAN_CONTROL_BIT 22 +#define FEATURE_THERMAL_BIT 23 +// Other +#define FEATURE_OUT_OF_BAND_MONITOR_BIT 24 +#define FEATURE_TEMP_DEPENDENT_VMIN_BIT 25 + +#define FEATURE_SPARE_26_BIT 26 +#define FEATURE_SPARE_27_BIT 27 +#define FEATURE_SPARE_28_BIT 28 +#define FEATURE_SPARE_29_BIT 29 +#define FEATURE_SPARE_30_BIT 30 +#define FEATURE_SPARE_31_BIT 31 +#define FEATURE_SPARE_32_BIT 32 +#define FEATURE_SPARE_33_BIT 33 +#define FEATURE_SPARE_34_BIT 34 +#define FEATURE_SPARE_35_BIT 35 +#define FEATURE_SPARE_36_BIT 36 +#define FEATURE_SPARE_37_BIT 37 +#define FEATURE_SPARE_38_BIT 38 +#define FEATURE_SPARE_39_BIT 39 +#define FEATURE_SPARE_40_BIT 40 +#define FEATURE_SPARE_41_BIT 41 +#define FEATURE_SPARE_42_BIT 42 +#define FEATURE_SPARE_43_BIT 43 +#define FEATURE_SPARE_44_BIT 44 +#define FEATURE_SPARE_45_BIT 45 +#define FEATURE_SPARE_46_BIT 46 +#define FEATURE_SPARE_47_BIT 47 +#define FEATURE_SPARE_48_BIT 48 +#define FEATURE_SPARE_49_BIT 49 +#define FEATURE_SPARE_50_BIT 50 +#define FEATURE_SPARE_51_BIT 51 +#define FEATURE_SPARE_52_BIT 52 +#define FEATURE_SPARE_53_BIT 53 +#define FEATURE_SPARE_54_BIT 54 +#define FEATURE_SPARE_55_BIT 55 +#define FEATURE_SPARE_56_BIT 56 +#define FEATURE_SPARE_57_BIT 57 +#define FEATURE_SPARE_58_BIT 58 +#define FEATURE_SPARE_59_BIT 59 +#define FEATURE_SPARE_60_BIT 60 +#define FEATURE_SPARE_61_BIT 61 +#define FEATURE_SPARE_62_BIT 62 +#define FEATURE_SPARE_63_BIT 63 + +#define NUM_FEATURES 64 + + +#define FEATURE_DPM_PREFETCHER_MASK (1 << FEATURE_DPM_PREFETCHER_BIT ) +#define FEATURE_DPM_GFXCLK_MASK (1 << FEATURE_DPM_GFXCLK_BIT ) +#define FEATURE_DPM_UCLK_MASK (1 << FEATURE_DPM_UCLK_BIT ) +#define FEATURE_DPM_SOCCLK_MASK (1 << FEATURE_DPM_SOCCLK_BIT ) +#define FEATURE_DPM_FCLK_MASK (1 << FEATURE_DPM_FCLK_BIT ) +#define FEATURE_DPM_MP0CLK_MASK (1 << FEATURE_DPM_MP0CLK_BIT ) +#define FEATURE_DPM_XGMI_MASK (1 << FEATURE_DPM_XGMI_BIT ) + +#define FEATURE_DS_GFXCLK_MASK (1 << FEATURE_DS_GFXCLK_BIT ) +#define FEATURE_DS_SOCCLK_MASK (1 << FEATURE_DS_SOCCLK_BIT ) +#define FEATURE_DS_LCLK_MASK (1 << FEATURE_DS_LCLK_BIT ) +#define FEATURE_DS_FCLK_MASK (1 << FEATURE_DS_FCLK_BIT ) +#define FEATURE_DS_UCLK_MASK (1 << FEATURE_DS_UCLK_BIT ) +#define FEATURE_GFX_ULV_MASK (1 << FEATURE_GFX_ULV_BIT ) +#define FEATURE_DPM_VCN_MASK (1 << FEATURE_DPM_VCN_BIT ) +#define FEATURE_RSMU_SMN_CG_MASK (1 << FEATURE_RSMU_SMN_CG_BIT ) +#define FEATURE_WAFL_CG_MASK (1 << FEATURE_WAFL_CG_BIT ) + +#define FEATURE_PPT_MASK (1 << FEATURE_PPT_BIT ) +#define FEATURE_TDC_MASK (1 << FEATURE_TDC_BIT ) +#define FEATURE_APCC_PLUS_MASK (1 << FEATURE_APCC_PLUS_BIT ) +#define FEATURE_VR0HOT_MASK (1 << FEATURE_VR0HOT_BIT ) +#define FEATURE_VR1HOT_MASK (1 << FEATURE_VR1HOT_BIT ) +#define FEATURE_FW_CTF_MASK (1 << FEATURE_FW_CTF_BIT ) +#define FEATURE_FAN_CONTROL_MASK (1 << FEATURE_FAN_CONTROL_BIT ) +#define FEATURE_THERMAL_MASK (1 << FEATURE_THERMAL_BIT ) + +#define FEATURE_OUT_OF_BAND_MONITOR_MASK (1 << FEATURE_OUT_OF_BAND_MONITOR_BIT ) +#define FEATURE_TEMP_DEPENDENT_VMIN_MASK (1 << FEATURE_TEMP_DEPENDENT_VMIN_BIT ) + + +//FIXME need updating +// Debug Overrides Bitmask +#define DPM_OVERRIDE_DISABLE_UCLK_PID 0x00000001 +#define DPM_OVERRIDE_DISABLE_VOLT_LINK_VCN_FCLK 0x00000002 + +// I2C Config Bit Defines +#define I2C_CONTROLLER_ENABLED 1 +#define I2C_CONTROLLER_DISABLED 0 + +// VR Mapping Bit Defines +#define VR_MAPPING_VR_SELECT_MASK 0x01 +#define VR_MAPPING_VR_SELECT_SHIFT 0x00 + +#define VR_MAPPING_PLANE_SELECT_MASK 0x02 +#define VR_MAPPING_PLANE_SELECT_SHIFT 0x01 + +// PSI Bit Defines +#define PSI_SEL_VR0_PLANE0_PSI0 0x01 +#define PSI_SEL_VR0_PLANE0_PSI1 0x02 +#define PSI_SEL_VR0_PLANE1_PSI0 0x04 +#define PSI_SEL_VR0_PLANE1_PSI1 0x08 +#define PSI_SEL_VR1_PLANE0_PSI0 0x10 +#define PSI_SEL_VR1_PLANE0_PSI1 0x20 +#define PSI_SEL_VR1_PLANE1_PSI0 0x40 +#define PSI_SEL_VR1_PLANE1_PSI1 0x80 + +// Throttler Control/Status Bits +#define THROTTLER_PADDING_BIT 0 +#define THROTTLER_TEMP_EDGE_BIT 1 +#define THROTTLER_TEMP_HOTSPOT_BIT 2 +#define THROTTLER_TEMP_MEM_BIT 3 +#define THROTTLER_TEMP_VR_GFX_BIT 4 +#define THROTTLER_TEMP_VR_MEM_BIT 5 +#define THROTTLER_TEMP_VR_SOC_BIT 6 +#define THROTTLER_TDC_GFX_BIT 7 +#define THROTTLER_TDC_SOC_BIT 8 +#define THROTTLER_PPT0_BIT 9 +#define THROTTLER_PPT1_BIT 10 +#define THROTTLER_PPT2_BIT 11 +#define THROTTLER_PPT3_BIT 12 +#define THROTTLER_PPM_BIT 13 +#define THROTTLER_FIT_BIT 14 +#define THROTTLER_APCC_BIT 15 + +// Table transfer status +#define TABLE_TRANSFER_OK 0x0 +#define TABLE_TRANSFER_FAILED 0xFF +#define TABLE_TRANSFER_PENDING 0xAB + +// Workload bits +#define WORKLOAD_PPLIB_DEFAULT_BIT 0 +#define WORKLOAD_PPLIB_POWER_SAVING_BIT 1 +#define WORKLOAD_PPLIB_VIDEO_BIT 2 +#define WORKLOAD_PPLIB_COMPUTE_BIT 3 +#define WORKLOAD_PPLIB_CUSTOM_BIT 4 +#define WORKLOAD_PPLIB_COUNT 5 + +//XGMI performance states +#define XGMI_STATE_D0 1 +#define XGMI_STATE_D3 0 + +#define NUM_I2C_CONTROLLERS 8 + +#define I2C_CONTROLLER_ENABLED 1 +#define I2C_CONTROLLER_DISABLED 0 + +#define MAX_SW_I2C_COMMANDS 8 + +typedef enum { + I2C_CONTROLLER_PORT_0 = 0, //CKSVII2C0 + I2C_CONTROLLER_PORT_1 = 1, //CKSVII2C1 + I2C_CONTROLLER_PORT_COUNT, +} I2cControllerPort_e; + +typedef enum { + I2C_CONTROLLER_NAME_VR_GFX = 0, + I2C_CONTROLLER_NAME_VR_SOC, + I2C_CONTROLLER_NAME_VR_MEM, + I2C_CONTROLLER_NAME_SPARE, + I2C_CONTROLLER_NAME_COUNT, +} I2cControllerName_e; + +typedef enum { + I2C_CONTROLLER_THROTTLER_TYPE_NONE = 0, + I2C_CONTROLLER_THROTTLER_VR_GFX, + I2C_CONTROLLER_THROTTLER_VR_SOC, + I2C_CONTROLLER_THROTTLER_VR_MEM, + I2C_CONTROLLER_THROTTLER_COUNT, +} I2cControllerThrottler_e; + +typedef enum { + I2C_CONTROLLER_PROTOCOL_VR_0, + I2C_CONTROLLER_PROTOCOL_VR_1, + I2C_CONTROLLER_PROTOCOL_TMP_0, + I2C_CONTROLLER_PROTOCOL_TMP_1, + I2C_CONTROLLER_PROTOCOL_SPARE_0, + I2C_CONTROLLER_PROTOCOL_SPARE_1, + I2C_CONTROLLER_PROTOCOL_COUNT, +} I2cControllerProtocol_e; + +typedef struct { + uint8_t Enabled; + uint8_t Speed; + uint8_t Padding[2]; + uint32_t SlaveAddress; + uint8_t ControllerPort; + uint8_t ControllerName; + uint8_t ThermalThrotter; + uint8_t I2cProtocol; +} I2cControllerConfig_t; + +typedef enum { + I2C_PORT_SVD_SCL = 0, + I2C_PORT_GPIO, +} I2cPort_e; + +typedef enum { + I2C_SPEED_FAST_50K = 0, //50 Kbits/s + I2C_SPEED_FAST_100K, //100 Kbits/s + I2C_SPEED_FAST_400K, //400 Kbits/s + I2C_SPEED_FAST_PLUS_1M, //1 Mbits/s (in fast mode) + I2C_SPEED_HIGH_1M, //1 Mbits/s (in high speed mode) + I2C_SPEED_HIGH_2M, //2.3 Mbits/s + I2C_SPEED_COUNT, +} I2cSpeed_e; + +typedef enum { + I2C_CMD_READ = 0, + I2C_CMD_WRITE, + I2C_CMD_COUNT, +} I2cCmdType_e; + +#define CMDCONFIG_STOP_BIT 0 +#define CMDCONFIG_RESTART_BIT 1 + +#define CMDCONFIG_STOP_MASK (1 << CMDCONFIG_STOP_BIT) +#define CMDCONFIG_RESTART_MASK (1 << CMDCONFIG_RESTART_BIT) + +typedef struct { + uint8_t RegisterAddr; ////only valid for write, ignored for read + uint8_t Cmd; //Read(0) or Write(1) + uint8_t Data; //Return data for read. Data to send for write + uint8_t CmdConfig; //Includes whether associated command should have a stop or restart command +} SwI2cCmd_t; //SW I2C Command Table + +typedef struct { + uint8_t I2CcontrollerPort; //CKSVII2C0(0) or //CKSVII2C1(1) + uint8_t I2CSpeed; //Slow(0) or Fast(1) + uint16_t SlaveAddress; + uint8_t NumCmds; //Number of commands + uint8_t Padding[3]; + + SwI2cCmd_t SwI2cCmds[MAX_SW_I2C_COMMANDS]; + + uint32_t MmHubPadding[8]; // SMU internal use + +} SwI2cRequest_t; // SW I2C Request Table + +//D3HOT sequences +typedef enum { + BACO_SEQUENCE, + MSR_SEQUENCE, + BAMACO_SEQUENCE, + ULPS_SEQUENCE, + D3HOT_SEQUENCE_COUNT, +}D3HOTSequence_e; + +//THis is aligned with RSMU PGFSM Register Mapping +typedef enum { + PG_DYNAMIC_MODE = 0, + PG_STATIC_MODE, +} PowerGatingMode_e; + +//This is aligned with RSMU PGFSM Register Mapping +typedef enum { + PG_POWER_DOWN = 0, + PG_POWER_UP, +} PowerGatingSettings_e; + +typedef struct { + uint32_t a; // store in IEEE float format in this variable + uint32_t b; // store in IEEE float format in this variable + uint32_t c; // store in IEEE float format in this variable +} QuadraticInt_t; + +typedef struct { + uint32_t m; // store in IEEE float format in this variable + uint32_t b; // store in IEEE float format in this variable +} LinearInt_t; + +typedef struct { + uint32_t a; // store in IEEE float format in this variable + uint32_t b; // store in IEEE float format in this variable + uint32_t c; // store in IEEE float format in this variable +} DroopInt_t; + +typedef enum { + GFXCLK_SOURCE_PLL = 0, + GFXCLK_SOURCE_AFLL, + GFXCLK_SOURCE_COUNT, +} GfxclkSrc_e; + +typedef enum { + PPCLK_GFXCLK, + PPCLK_VCLK, + PPCLK_DCLK, + PPCLK_SOCCLK, + PPCLK_UCLK, + PPCLK_FCLK, + PPCLK_COUNT, +} PPCLK_e; + +typedef enum { + POWER_SOURCE_AC, + POWER_SOURCE_DC, + POWER_SOURCE_COUNT, +} POWER_SOURCE_e; + +typedef enum { + TEMP_EDGE, + TEMP_HOTSPOT, + TEMP_MEM, + TEMP_VR_GFX, + TEMP_VR_SOC, + TEMP_VR_MEM, + TEMP_COUNT +} TEMP_TYPE_e; + +typedef enum { + PPT_THROTTLER_PPT0, + PPT_THROTTLER_PPT1, + PPT_THROTTLER_PPT2, + PPT_THROTTLER_PPT3, + PPT_THROTTLER_COUNT +} PPT_THROTTLER_e; + +typedef enum { + VOLTAGE_MODE_AVFS = 0, + VOLTAGE_MODE_AVFS_SS, + VOLTAGE_MODE_SS, + VOLTAGE_MODE_COUNT, +} VOLTAGE_MODE_e; + +typedef enum { + AVFS_VOLTAGE_GFX = 0, + AVFS_VOLTAGE_SOC, + AVFS_VOLTAGE_COUNT, +} AVFS_VOLTAGE_TYPE_e; + +typedef enum { + GPIO_INT_POLARITY_ACTIVE_LOW = 0, + GPIO_INT_POLARITY_ACTIVE_HIGH, +} GpioIntPolarity_e; + +typedef enum { + MEMORY_TYPE_GDDR6 = 0, + MEMORY_TYPE_HBM, +} MemoryType_e; + +typedef enum { + PWR_CONFIG_TDP = 0, + PWR_CONFIG_TGP, + PWR_CONFIG_TCP_ESTIMATED, + PWR_CONFIG_TCP_MEASURED, +} PwrConfig_e; + +typedef enum { + XGMI_LINK_RATE_2 = 2, // 2Gbps + XGMI_LINK_RATE_4 = 4, // 4Gbps + XGMI_LINK_RATE_8 = 8, // 8Gbps + XGMI_LINK_RATE_12 = 12, // 12Gbps + XGMI_LINK_RATE_16 = 16, // 16Gbps + XGMI_LINK_RATE_17 = 17, // 17Gbps + XGMI_LINK_RATE_18 = 18, // 18Gbps + XGMI_LINK_RATE_19 = 19, // 19Gbps + XGMI_LINK_RATE_20 = 20, // 20Gbps + XGMI_LINK_RATE_21 = 21, // 21Gbps + XGMI_LINK_RATE_22 = 22, // 22Gbps + XGMI_LINK_RATE_23 = 23, // 23Gbps + XGMI_LINK_RATE_24 = 24, // 24Gbps + XGMI_LINK_RATE_25 = 25, // 25Gbps + XGMI_LINK_RATE_COUNT +} XGMI_LINK_RATE_e; + +typedef enum { + XGMI_LINK_WIDTH_1 = 1, // x1 + XGMI_LINK_WIDTH_2 = 2, // x2 + XGMI_LINK_WIDTH_4 = 4, // x4 + XGMI_LINK_WIDTH_8 = 8, // x8 + XGMI_LINK_WIDTH_9 = 9, // x9 + XGMI_LINK_WIDTH_16 = 16, // x16 + XGMI_LINK_WIDTH_COUNT +} XGMI_LINK_WIDTH_e; + +typedef struct { + uint8_t VoltageMode; // 0 - AVFS only, 1- min(AVFS,SS), 2-SS only + uint8_t SnapToDiscrete; // 0 - Fine grained DPM, 1 - Discrete DPM + uint8_t NumDiscreteLevels; // Set to 2 (Fmin, Fmax) when using fine grained DPM, otherwise set to # discrete levels used + uint8_t padding; + LinearInt_t ConversionToAvfsClk; // Transfer function to AVFS Clock (GHz->GHz) + QuadraticInt_t SsCurve; // Slow-slow curve (GHz->V) + uint16_t SsFmin; // Fmin for SS curve. If SS curve is selected, will use V@SSFmin for F <= Fmin + uint16_t Padding16; +} DpmDescriptor_t; + +typedef struct { + uint32_t Version; + + // SECTION: Feature Enablement + uint32_t FeaturesToRun[2]; + + // SECTION: Infrastructure Limits + uint16_t SocketPowerLimitAc[PPT_THROTTLER_COUNT]; + uint16_t SocketPowerLimitAcTau[PPT_THROTTLER_COUNT]; + uint16_t TdcLimitSoc; // Amps + uint16_t TdcLimitSocTau; // Time constant of LPF in ms + uint16_t TdcLimitGfx; // Amps + uint16_t TdcLimitGfxTau; // Time constant of LPF in ms + + uint16_t TedgeLimit; // Celcius + uint16_t ThotspotLimit; // Celcius + uint16_t TmemLimit; // Celcius + uint16_t Tvr_gfxLimit; // Celcius + uint16_t Tvr_memLimit; // Celcius + uint16_t Tvr_socLimit; // Celcius + uint32_t FitLimit; // Failures in time (failures per million parts over the defined lifetime) + + uint16_t PpmPowerLimit; // Switch this this power limit when temperature is above PpmTempThreshold + uint16_t PpmTemperatureThreshold; + + // SECTION: Throttler settings + uint32_t ThrottlerControlMask; // See Throtter masks defines + + // SECTION: ULV Settings + uint16_t UlvVoltageOffsetGfx; // In mV(Q2) + uint16_t UlvPadding; // Padding + + uint8_t UlvGfxclkBypass; // 1 to turn off/bypass Gfxclk during ULV, 0 to leave Gfxclk on during ULV + uint8_t Padding234[3]; + + // SECTION: Voltage Control Parameters + uint16_t MinVoltageGfx; // In mV(Q2) Minimum Voltage ("Vmin") of VDD_GFX + uint16_t MinVoltageSoc; // In mV(Q2) Minimum Voltage ("Vmin") of VDD_SOC + uint16_t MaxVoltageGfx; // In mV(Q2) Maximum Voltage allowable of VDD_GFX + uint16_t MaxVoltageSoc; // In mV(Q2) Maximum Voltage allowable of VDD_SOC + + uint16_t LoadLineResistanceGfx; // In mOhms with 8 fractional bits + uint16_t LoadLineResistanceSoc; // In mOhms with 8 fractional bits + + //SECTION: DPM Config 1 + DpmDescriptor_t DpmDescriptor[PPCLK_COUNT]; + + uint16_t FreqTableGfx [NUM_GFXCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableVclk [NUM_VCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableDclk [NUM_DCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableSocclk [NUM_SOCCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableUclk [NUM_UCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableFclk [NUM_FCLK_DPM_LEVELS ]; // In MHz + + uint32_t Paddingclks[16]; + + // SECTION: DPM Config 2 + uint16_t Mp0clkFreq [NUM_MP0CLK_DPM_LEVELS]; // in MHz + uint16_t Mp0DpmVoltage [NUM_MP0CLK_DPM_LEVELS]; // mV(Q2) + + // GFXCLK DPM + uint16_t GfxclkFidle; // In MHz + uint16_t GfxclkSlewRate; // for PLL babystepping??? + uint8_t Padding567[4]; + uint16_t GfxclkDsMaxFreq; // In MHz + uint8_t GfxclkSource; // 0 = PLL, 1 = AFLL + uint8_t Padding456; + + // GFXCLK Thermal DPM (formerly 'Boost' Settings) + uint16_t EnableTdpm; + uint16_t TdpmHighHystTemperature; + uint16_t TdpmLowHystTemperature; + uint16_t GfxclkFreqHighTempLimit; // High limit on GFXCLK when temperature is high, for reliability. + + // SECTION: Fan Control + uint16_t FanStopTemp; //Celcius + uint16_t FanStartTemp; //Celcius + + uint16_t FanGainEdge; + uint16_t FanGainHotspot; + uint16_t FanGainVrGfx; + uint16_t FanGainVrSoc; + uint16_t FanGainVrMem; + uint16_t FanGainHbm; + uint16_t FanPwmMin; + uint16_t FanAcousticLimitRpm; + uint16_t FanThrottlingRpm; + uint16_t FanMaximumRpm; + uint16_t FanTargetTemperature; + uint16_t FanTargetGfxclk; + uint8_t FanZeroRpmEnable; + uint8_t FanTachEdgePerRev; + uint8_t FanTempInputSelect; + uint8_t padding8_Fan; + + // The following are AFC override parameters. Leave at 0 to use FW defaults. + int16_t FuzzyFan_ErrorSetDelta; + int16_t FuzzyFan_ErrorRateSetDelta; + int16_t FuzzyFan_PwmSetDelta; + uint16_t FuzzyFan_Reserved; + + + // SECTION: AVFS + // Overrides + uint8_t OverrideAvfsGb[AVFS_VOLTAGE_COUNT]; + uint8_t Padding8_Avfs[2]; + + QuadraticInt_t qAvfsGb[AVFS_VOLTAGE_COUNT]; // GHz->V Override of fused curve + DroopInt_t dBtcGbGfxPll; // GHz->V BtcGb + DroopInt_t dBtcGbGfxAfll; // GHz->V BtcGb + DroopInt_t dBtcGbSoc; // GHz->V BtcGb + LinearInt_t qAgingGb[AVFS_VOLTAGE_COUNT]; // GHz->V + + QuadraticInt_t qStaticVoltageOffset[AVFS_VOLTAGE_COUNT]; // GHz->V + + uint16_t DcTol[AVFS_VOLTAGE_COUNT]; // mV Q2 + + uint8_t DcBtcEnabled[AVFS_VOLTAGE_COUNT]; + uint8_t Padding8_GfxBtc[2]; + + uint16_t DcBtcMin[AVFS_VOLTAGE_COUNT]; // mV Q2 + uint16_t DcBtcMax[AVFS_VOLTAGE_COUNT]; // mV Q2 + + uint16_t DcBtcGb[AVFS_VOLTAGE_COUNT]; // mV Q2 + + // SECTION: XGMI + uint8_t XgmiDpmPstates[NUM_XGMI_LEVELS]; // 2 DPM states, high and low. 0-P0, 1-P1, 2-P2, 3-P3. + uint8_t XgmiDpmSpare[2]; + + // Temperature Dependent Vmin + uint16_t VDDGFX_TVmin; //Celcius + uint16_t VDDSOC_TVmin; //Celcius + uint16_t VDDGFX_Vmin_HiTemp; // mV Q2 + uint16_t VDDGFX_Vmin_LoTemp; // mV Q2 + uint16_t VDDSOC_Vmin_HiTemp; // mV Q2 + uint16_t VDDSOC_Vmin_LoTemp; // mV Q2 + + uint16_t VDDGFX_TVminHystersis; // Celcius + uint16_t VDDSOC_TVminHystersis; // Celcius + + + // SECTION: Advanced Options + uint32_t DebugOverrides; + QuadraticInt_t ReservedEquation0; + QuadraticInt_t ReservedEquation1; + QuadraticInt_t ReservedEquation2; + QuadraticInt_t ReservedEquation3; + + uint16_t MinVoltageUlvGfx; // In mV(Q2) Minimum Voltage ("Vmin") of VDD_GFX in ULV mode + uint16_t PaddingUlv; // Padding + + // Total Power configuration, use defines from PwrConfig_e + uint8_t TotalPowerConfig; //0-TDP, 1-TGP, 2-TCP Estimated, 3-TCP Measured + uint8_t TotalPowerSpare1; + uint16_t TotalPowerSpare2; + + // APCC Settings + uint16_t PccThresholdLow; + uint16_t PccThresholdHigh; + uint32_t PaddingAPCC[6]; //FIXME pending SPEC + + // OOB Settings + uint16_t BasePerformanceCardPower; + uint16_t MaxPerformanceCardPower; + uint16_t BasePerformanceFrequencyCap; //In Mhz + uint16_t MaxPerformanceFrequencyCap; //In Mhz + + // SECTION: Reserved + uint32_t Reserved[9]; + + // SECTION: BOARD PARAMETERS + + // SVI2 Board Parameters + uint16_t MaxVoltageStepGfx; // In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value. + uint16_t MaxVoltageStepSoc; // In mV(Q2) Max voltage step that SMU will request. Multiple steps are taken if voltage change exceeds this value. + + uint8_t VddGfxVrMapping; // Use VR_MAPPING* bitfields + uint8_t VddSocVrMapping; // Use VR_MAPPING* bitfields + uint8_t VddMemVrMapping; // Use VR_MAPPING* bitfields + uint8_t BoardVrMapping; // Use VR_MAPPING* bitfields + + uint8_t GfxUlvPhaseSheddingMask; // set this to 1 to set PSI0/1 to 1 in ULV mode + uint8_t ExternalSensorPresent; // External RDI connected to TMON (aka TEMP IN) + uint8_t Padding8_V[2]; + + // Telemetry Settings + uint16_t GfxMaxCurrent; // in Amps + int8_t GfxOffset; // in Amps + uint8_t Padding_TelemetryGfx; + + uint16_t SocMaxCurrent; // in Amps + int8_t SocOffset; // in Amps + uint8_t Padding_TelemetrySoc; + + uint16_t MemMaxCurrent; // in Amps + int8_t MemOffset; // in Amps + uint8_t Padding_TelemetryMem; + + uint16_t BoardMaxCurrent; // in Amps + int8_t BoardOffset; // in Amps + uint8_t Padding_TelemetryBoardInput; + + // GPIO Settings + uint8_t VR0HotGpio; // GPIO pin configured for VR0 HOT event + uint8_t VR0HotPolarity; // GPIO polarity for VR0 HOT event + uint8_t VR1HotGpio; // GPIO pin configured for VR1 HOT event + uint8_t VR1HotPolarity; // GPIO polarity for VR1 HOT event + + // GFXCLK PLL Spread Spectrum + uint8_t PllGfxclkSpreadEnabled; // on or off + uint8_t PllGfxclkSpreadPercent; // Q4.4 + uint16_t PllGfxclkSpreadFreq; // kHz + + // UCLK Spread Spectrum + uint8_t UclkSpreadEnabled; // on or off + uint8_t UclkSpreadPercent; // Q4.4 + uint16_t UclkSpreadFreq; // kHz + + // FCLK Spread Spectrum + uint8_t FclkSpreadEnabled; // on or off + uint8_t FclkSpreadPercent; // Q4.4 + uint16_t FclkSpreadFreq; // kHz + + // GFXCLK Fll Spread Spectrum + uint8_t FllGfxclkSpreadEnabled; // on or off + uint8_t FllGfxclkSpreadPercent; // Q4.4 + uint16_t FllGfxclkSpreadFreq; // kHz + + // I2C Controller Structure + I2cControllerConfig_t I2cControllers[NUM_I2C_CONTROLLERS]; + + // Memory section + uint32_t MemoryChannelEnabled; // For DRAM use only, Max 32 channels enabled bit mask. + + uint8_t DramBitWidth; // For DRAM use only. See Dram Bit width type defines + uint8_t PaddingMem[3]; + + // Total board power + uint16_t TotalBoardPower; //Only needed for TCP Estimated case, where TCP = TGP+Total Board Power + uint16_t BoardPadding; + + // SECTION: XGMI Training + uint8_t XgmiLinkSpeed [NUM_XGMI_PSTATE_LEVELS]; + uint8_t XgmiLinkWidth [NUM_XGMI_PSTATE_LEVELS]; + + uint16_t XgmiFclkFreq [NUM_XGMI_PSTATE_LEVELS]; + uint16_t XgmiSocVoltage [NUM_XGMI_PSTATE_LEVELS]; + + // GPIO pins for I2C communications with 2nd controller for Input Telemetry Sequence + uint8_t GpioI2cScl; // Serial Clock + uint8_t GpioI2cSda; // Serial Data + uint16_t GpioPadding; + + // Platform input telemetry voltage coefficient + uint32_t BoardVoltageCoeffA; // decode by /1000 + uint32_t BoardVoltageCoeffB; // decode by /1000 + + uint32_t BoardReserved[7]; + + // Padding for MMHUB - do not modify this + uint32_t MmHubPadding[8]; // SMU internal use + +} PPTable_t; + +typedef struct { + // Time constant parameters for clock averages in ms + uint16_t GfxclkAverageLpfTau; + uint16_t SocclkAverageLpfTau; + uint16_t UclkAverageLpfTau; + uint16_t GfxActivityLpfTau; + uint16_t UclkActivityLpfTau; + + uint16_t SocketPowerLpfTau; + + // Padding - ignore + uint32_t MmHubPadding[8]; // SMU internal use +} DriverSmuConfig_t; + +typedef struct { + uint16_t CurrClock[PPCLK_COUNT]; + uint16_t AverageGfxclkFrequency; + uint16_t AverageSocclkFrequency; + uint16_t AverageUclkFrequency ; + uint16_t AverageGfxActivity ; + uint16_t AverageUclkActivity ; + uint8_t CurrSocVoltageOffset ; + uint8_t CurrGfxVoltageOffset ; + uint8_t CurrMemVidOffset ; + uint8_t Padding8 ; + uint16_t AverageSocketPower ; + uint16_t TemperatureEdge ; + uint16_t TemperatureHotspot ; + uint16_t TemperatureHBM ; + uint16_t TemperatureVrGfx ; + uint16_t TemperatureVrSoc ; + uint16_t TemperatureVrMem ; + uint32_t ThrottlerStatus ; + + uint16_t CurrFanSpeed ; + uint16_t Padding16; + + uint32_t Padding[4]; + + // Padding - ignore + uint32_t MmHubPadding[8]; // SMU internal use +} SmuMetrics_t; + + +typedef struct { + uint16_t avgPsmCount[75]; + uint16_t minPsmCount[75]; + float avgPsmVoltage[75]; + float minPsmVoltage[75]; + + uint32_t MmHubPadding[8]; // SMU internal use +} AvfsDebugTable_t; + +typedef struct { + uint8_t AvfsVersion; + uint8_t Padding; + uint8_t AvfsEn[AVFS_VOLTAGE_COUNT]; + + uint8_t OverrideVFT[AVFS_VOLTAGE_COUNT]; + uint8_t OverrideAvfsGb[AVFS_VOLTAGE_COUNT]; + + uint8_t OverrideTemperatures[AVFS_VOLTAGE_COUNT]; + uint8_t OverrideVInversion[AVFS_VOLTAGE_COUNT]; + uint8_t OverrideP2V[AVFS_VOLTAGE_COUNT]; + uint8_t OverrideP2VCharzFreq[AVFS_VOLTAGE_COUNT]; + + int32_t VFT0_m1[AVFS_VOLTAGE_COUNT]; // Q8.24 + int32_t VFT0_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t VFT0_b[AVFS_VOLTAGE_COUNT]; // Q32 + + int32_t VFT1_m1[AVFS_VOLTAGE_COUNT]; // Q8.16 + int32_t VFT1_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t VFT1_b[AVFS_VOLTAGE_COUNT]; // Q32 + + int32_t VFT2_m1[AVFS_VOLTAGE_COUNT]; // Q8.16 + int32_t VFT2_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t VFT2_b[AVFS_VOLTAGE_COUNT]; // Q32 + + int32_t AvfsGb0_m1[AVFS_VOLTAGE_COUNT]; // Q8.24 + int32_t AvfsGb0_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t AvfsGb0_b[AVFS_VOLTAGE_COUNT]; // Q32 + + int32_t AcBtcGb_m1[AVFS_VOLTAGE_COUNT]; // Q8.24 + int32_t AcBtcGb_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t AcBtcGb_b[AVFS_VOLTAGE_COUNT]; // Q32 + + uint32_t AvfsTempCold[AVFS_VOLTAGE_COUNT]; + uint32_t AvfsTempMid[AVFS_VOLTAGE_COUNT]; + uint32_t AvfsTempHot[AVFS_VOLTAGE_COUNT]; + + uint32_t VInversion[AVFS_VOLTAGE_COUNT]; // in mV with 2 fractional bits + + + int32_t P2V_m1[AVFS_VOLTAGE_COUNT]; // Q8.24 + int32_t P2V_m2[AVFS_VOLTAGE_COUNT]; // Q12.12 + int32_t P2V_b[AVFS_VOLTAGE_COUNT]; // Q32 + + uint32_t P2VCharzFreq[AVFS_VOLTAGE_COUNT]; // in 10KHz units + + uint32_t EnabledAvfsModules[3]; + + uint32_t MmHubPadding[8]; // SMU internal use +} AvfsFuseOverride_t; + +typedef struct { + uint8_t Gfx_ActiveHystLimit; + uint8_t Gfx_IdleHystLimit; + uint8_t Gfx_FPS; + uint8_t Gfx_MinActiveFreqType; + uint8_t Gfx_BoosterFreqType; + uint8_t Gfx_MinFreqStep; // Minimum delta between current and target frequeny in order for FW to change clock. + uint8_t Gfx_UseRlcBusy; + uint8_t PaddingGfx[3]; + uint16_t Gfx_MinActiveFreq; // MHz + uint16_t Gfx_BoosterFreq; // MHz + uint16_t Gfx_PD_Data_time_constant; // Time constant of PD controller in ms + uint32_t Gfx_PD_Data_limit_a; // Q16 + uint32_t Gfx_PD_Data_limit_b; // Q16 + uint32_t Gfx_PD_Data_limit_c; // Q16 + uint32_t Gfx_PD_Data_error_coeff; // Q16 + uint32_t Gfx_PD_Data_error_rate_coeff; // Q16 + + uint8_t Mem_ActiveHystLimit; + uint8_t Mem_IdleHystLimit; + uint8_t Mem_FPS; + uint8_t Mem_MinActiveFreqType; + uint8_t Mem_BoosterFreqType; + uint8_t Mem_MinFreqStep; // Minimum delta between current and target frequeny in order for FW to change clock. + uint8_t Mem_UseRlcBusy; + uint8_t PaddingMem[3]; + uint16_t Mem_MinActiveFreq; // MHz + uint16_t Mem_BoosterFreq; // MHz + uint16_t Mem_PD_Data_time_constant; // Time constant of PD controller in ms + uint32_t Mem_PD_Data_limit_a; // Q16 + uint32_t Mem_PD_Data_limit_b; // Q16 + uint32_t Mem_PD_Data_limit_c; // Q16 + uint32_t Mem_PD_Data_error_coeff; // Q16 + uint32_t Mem_PD_Data_error_rate_coeff; // Q16 + + uint32_t Mem_UpThreshold_Limit; // Q16 + uint8_t Mem_UpHystLimit; + uint8_t Mem_DownHystLimit; + uint16_t Mem_Fps; + + uint32_t MmHubPadding[8]; // SMU internal use +} DpmActivityMonitorCoeffInt_t; + +// These defines are used with the following messages: +// SMC_MSG_TransferTableDram2Smu +// SMC_MSG_TransferTableSmu2Dram +#define TABLE_PPTABLE 0 +#define TABLE_AVFS 1 +#define TABLE_AVFS_PSM_DEBUG 2 +#define TABLE_AVFS_FUSE_OVERRIDE 3 +#define TABLE_PMSTATUSLOG 4 +#define TABLE_SMU_METRICS 5 +#define TABLE_DRIVER_SMU_CONFIG 6 +#define TABLE_OVERDRIVE 7 +#define TABLE_WAFL_XGMI_TOPOLOGY 8 +#define TABLE_I2C_COMMANDS 9 +#define TABLE_ACTIVITY_MONITOR_COEFF 10 +#define TABLE_COUNT 11 + +// These defines are used with the SMC_MSG_SetUclkFastSwitch message. +typedef enum { + DF_SWITCH_TYPE_FAST = 0, + DF_SWITCH_TYPE_SLOW, + DF_SWITCH_TYPE_COUNT, +} DF_SWITCH_TYPE_e; + +typedef enum { + DRAM_BIT_WIDTH_DISABLED = 0, + DRAM_BIT_WIDTH_X_8, + DRAM_BIT_WIDTH_X_16, + DRAM_BIT_WIDTH_X_32, + DRAM_BIT_WIDTH_X_64, // NOT USED. + DRAM_BIT_WIDTH_X_128, + DRAM_BIT_WIDTH_COUNT, +} DRAM_BIT_WIDTH_TYPE_e; + +#define REMOVE_FMAX_MARGIN_BIT 0x0 +#define REMOVE_DCTOL_MARGIN_BIT 0x1 +#define REMOVE_PLATFORM_MARGIN_BIT 0x2 + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h index adbbfebbb1e5..ac0120e384be 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_navi10.h @@ -26,7 +26,9 @@ // *** IMPORTANT *** // SMU TEAM: Always increment the interface version if // any structure is changed in this file -#define SMU11_DRIVER_IF_VERSION 0x33 +// Be aware of that the version should be updated in +// smu_v11_0.h, maybe rename is also needed. +// #define SMU11_DRIVER_IF_VERSION 0x33 #define PPTABLE_NV10_SMU_VERSION 8 @@ -504,10 +506,11 @@ typedef struct { uint32_t Status; uint16_t DieTemperature; - uint16_t MemoryTemperature; + uint16_t CurrentMemoryTemperature; - uint16_t SelectedCardPower; - uint16_t Reserved4; + uint16_t MemoryTemperature; + uint8_t MemoryHotspotPosition; + uint8_t Reserved4; uint32_t BoardLevelEnergyAccumulator; } OutOfBandMonitor_t; @@ -799,7 +802,12 @@ typedef struct { // Mvdd Svi2 Div Ratio Setting uint32_t MvddRatio; // This is used for MVDD Vid workaround. It has 16 fractional bits (Q16.16) - uint32_t BoardReserved[9]; + uint8_t RenesesLoadLineEnabled; + uint8_t GfxLoadlineResistance; + uint8_t SocLoadlineResistance; + uint8_t Padding8_Loadline; + + uint32_t BoardReserved[8]; // Padding for MMHUB - do not modify this uint32_t MmHubPadding[8]; // SMU internal use @@ -903,13 +911,22 @@ typedef struct { } Watermarks_t; typedef struct { + uint16_t avgPsmCount[28]; + uint16_t minPsmCount[28]; + float avgPsmVoltage[28]; + float minPsmVoltage[28]; + + uint32_t MmHubPadding[32]; // SMU internal use +} AvfsDebugTable_t_NV14; + +typedef struct { uint16_t avgPsmCount[36]; uint16_t minPsmCount[36]; float avgPsmVoltage[36]; float minPsmVoltage[36]; uint32_t MmHubPadding[8]; // SMU internal use -} AvfsDebugTable_t; +} AvfsDebugTable_t_NV10; typedef struct { uint8_t AvfsVersion; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu12_driver_if.h b/drivers/gpu/drm/amd/powerplay/inc/smu12_driver_if.h new file mode 100644 index 000000000000..2f85a34c0591 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu12_driver_if.h @@ -0,0 +1,222 @@ +/* + * Copyright 2019 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 SMU12_DRIVER_IF_H +#define SMU12_DRIVER_IF_H + +// *** IMPORTANT *** +// SMU TEAM: Always increment the interface version if +// any structure is changed in this file +#define SMU12_DRIVER_IF_VERSION 11 + +typedef struct { + int32_t value; + uint32_t numFractionalBits; +} FloatInIntFormat_t; + +typedef enum { + DSPCLK_DCFCLK = 0, + DSPCLK_DISPCLK, + DSPCLK_PIXCLK, + DSPCLK_PHYCLK, + DSPCLK_COUNT, +} DSPCLK_e; + +typedef struct { + uint16_t Freq; // in MHz + uint16_t Vid; // min voltage in SVI2 VID +} DisplayClockTable_t; + +typedef struct { + uint16_t MinClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MaxClock; // This is either DCFCLK or SOCCLK (in MHz) + uint16_t MinMclk; + uint16_t MaxMclk; + + uint8_t WmSetting; + uint8_t WmType; // Used for normal pstate change or memory retraining + uint8_t Padding[2]; +} WatermarkRowGeneric_t; + +#define NUM_WM_RANGES 4 +#define WM_PSTATE_CHG 0 +#define WM_RETRAINING 1 + +typedef enum { + WM_SOCCLK = 0, + WM_DCFCLK, + WM_COUNT, +} WM_CLOCK_e; + +typedef struct { + // Watermarks + WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES]; + + uint32_t MmHubPadding[7]; // SMU internal use +} Watermarks_t; + +typedef enum { + CUSTOM_DPM_SETTING_GFXCLK, + CUSTOM_DPM_SETTING_CCLK, + CUSTOM_DPM_SETTING_FCLK_CCX, + CUSTOM_DPM_SETTING_FCLK_GFX, + CUSTOM_DPM_SETTING_FCLK_STALLS, + CUSTOM_DPM_SETTING_LCLK, + CUSTOM_DPM_SETTING_COUNT, +} CUSTOM_DPM_SETTING_e; + +typedef struct { + uint8_t ActiveHystLimit; + uint8_t IdleHystLimit; + uint8_t FPS; + uint8_t MinActiveFreqType; + FloatInIntFormat_t MinActiveFreq; + FloatInIntFormat_t PD_Data_limit; + FloatInIntFormat_t PD_Data_time_constant; + FloatInIntFormat_t PD_Data_error_coeff; + FloatInIntFormat_t PD_Data_error_rate_coeff; +} DpmActivityMonitorCoeffExt_t; + +typedef struct { + DpmActivityMonitorCoeffExt_t DpmActivityMonitorCoeff[CUSTOM_DPM_SETTING_COUNT]; +} CustomDpmSettings_t; + + +#define NUM_DCFCLK_DPM_LEVELS 8 +#define NUM_SOCCLK_DPM_LEVELS 8 +#define NUM_FCLK_DPM_LEVELS 4 +#define NUM_MEMCLK_DPM_LEVELS 4 +#define NUM_VCN_DPM_LEVELS 8 + +typedef struct { + uint32_t Freq; // In MHz + uint32_t Vol; // Millivolts with 2 fractional bits +} DpmClock_t; + +typedef struct { + DpmClock_t DcfClocks[NUM_DCFCLK_DPM_LEVELS]; + DpmClock_t SocClocks[NUM_SOCCLK_DPM_LEVELS]; + DpmClock_t FClocks[NUM_FCLK_DPM_LEVELS]; + DpmClock_t MemClocks[NUM_MEMCLK_DPM_LEVELS]; + DpmClock_t VClocks[NUM_VCN_DPM_LEVELS]; + DpmClock_t DClocks[NUM_VCN_DPM_LEVELS]; + + uint8_t NumDcfClkDpmEnabled; + uint8_t NumSocClkDpmEnabled; + uint8_t NumFClkDpmEnabled; + uint8_t NumMemClkDpmEnabled; + uint8_t NumVClkDpmEnabled; + uint8_t NumDClkDpmEnabled; + uint8_t spare[2]; +} DpmClocks_t; + + +typedef enum { + CLOCK_SMNCLK = 0, + CLOCK_SOCCLK, + CLOCK_MP0CLK, + CLOCK_MP1CLK, + CLOCK_MP2CLK, + CLOCK_VCLK, + CLOCK_LCLK, + CLOCK_DCLK, + CLOCK_ACLK, + CLOCK_ISPCLK, + CLOCK_SHUBCLK, + CLOCK_DISPCLK, + CLOCK_DPPCLK, + CLOCK_DPREFCLK, + CLOCK_DCFCLK, + CLOCK_FCLK, + CLOCK_UMCCLK, + CLOCK_GFXCLK, + CLOCK_COUNT, +} CLOCK_IDs_e; + +// Throttler Status Bitmask +#define THROTTLER_STATUS_BIT_SPL 0 +#define THROTTLER_STATUS_BIT_FPPT 1 +#define THROTTLER_STATUS_BIT_SPPT 2 +#define THROTTLER_STATUS_BIT_SPPT_APU 3 +#define THROTTLER_STATUS_BIT_THM_CORE 4 +#define THROTTLER_STATUS_BIT_THM_GFX 5 +#define THROTTLER_STATUS_BIT_THM_SOC 6 +#define THROTTLER_STATUS_BIT_TDC_VDD 7 +#define THROTTLER_STATUS_BIT_TDC_SOC 8 + +typedef struct { + uint16_t ClockFrequency[CLOCK_COUNT]; //[MHz] + + uint16_t AverageGfxclkFrequency; //[MHz] + uint16_t AverageSocclkFrequency; //[MHz] + uint16_t AverageVclkFrequency; //[MHz] + uint16_t AverageFclkFrequency; //[MHz] + + uint16_t AverageGfxActivity; //[centi] + uint16_t AverageUvdActivity; //[centi] + + uint16_t Voltage[2]; //[mV] indices: VDDCR_VDD, VDDCR_SOC + uint16_t Current[2]; //[mA] indices: VDDCR_VDD, VDDCR_SOC + uint16_t Power[2]; //[mW] indices: VDDCR_VDD, VDDCR_SOC + + uint16_t FanPwm; //[milli] + uint16_t CurrentSocketPower; //[mW] + + uint16_t CoreFrequency[8]; //[MHz] + uint16_t CorePower[8]; //[mW] + uint16_t CoreTemperature[8]; //[centi-Celsius] + uint16_t L3Frequency[2]; //[MHz] + uint16_t L3Temperature[2]; //[centi-Celsius] + + uint16_t GfxTemperature; //[centi-Celsius] + uint16_t SocTemperature; //[centi-Celsius] + uint16_t ThrottlerStatus; + uint16_t spare; + + uint16_t StapmOriginalLimit; //[mW] + uint16_t StapmCurrentLimit; //[mW] + uint16_t ApuPower; //[mW] + uint16_t dGpuPower; //[mW] +} SmuMetrics_t; + + +// Workload bits +#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 0 +#define WORKLOAD_PPLIB_VIDEO_BIT 2 +#define WORKLOAD_PPLIB_VR_BIT 3 +#define WORKLOAD_PPLIB_COMPUTE_BIT 4 +#define WORKLOAD_PPLIB_CUSTOM_BIT 5 +#define WORKLOAD_PPLIB_COUNT 6 + +#define TABLE_BIOS_IF 0 // Called by BIOS +#define TABLE_WATERMARKS 1 // Called by Driver +#define TABLE_CUSTOM_DPM 2 // Called by Driver +#define TABLE_SPARE1 3 +#define TABLE_DPMCLOCKS 4 // Called by Driver +#define TABLE_MOMENTARY_PM 5 // Called by Tools +#define TABLE_MODERN_STDBY 6 // Called by Tools for Modern Standby Log +#define TABLE_SMU_METRICS 7 // Called by Driver +#define TABLE_COUNT 8 + + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_types.h b/drivers/gpu/drm/amd/powerplay/inc/smu_types.h new file mode 100644 index 000000000000..a5b4df146713 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_types.h @@ -0,0 +1,268 @@ +/* + * Copyright 2019 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 __SMU_TYPES_H__ +#define __SMU_TYPES_H__ + +#define SMU_MESSAGE_TYPES \ + __SMU_DUMMY_MAP(TestMessage), \ + __SMU_DUMMY_MAP(GetSmuVersion), \ + __SMU_DUMMY_MAP(GetDriverIfVersion), \ + __SMU_DUMMY_MAP(SetAllowedFeaturesMaskLow), \ + __SMU_DUMMY_MAP(SetAllowedFeaturesMaskHigh), \ + __SMU_DUMMY_MAP(EnableAllSmuFeatures), \ + __SMU_DUMMY_MAP(DisableAllSmuFeatures), \ + __SMU_DUMMY_MAP(EnableSmuFeaturesLow), \ + __SMU_DUMMY_MAP(EnableSmuFeaturesHigh), \ + __SMU_DUMMY_MAP(DisableSmuFeaturesLow), \ + __SMU_DUMMY_MAP(DisableSmuFeaturesHigh), \ + __SMU_DUMMY_MAP(GetEnabledSmuFeaturesLow), \ + __SMU_DUMMY_MAP(GetEnabledSmuFeaturesHigh), \ + __SMU_DUMMY_MAP(SetWorkloadMask), \ + __SMU_DUMMY_MAP(SetPptLimit), \ + __SMU_DUMMY_MAP(SetDriverDramAddrHigh), \ + __SMU_DUMMY_MAP(SetDriverDramAddrLow), \ + __SMU_DUMMY_MAP(SetToolsDramAddrHigh), \ + __SMU_DUMMY_MAP(SetToolsDramAddrLow), \ + __SMU_DUMMY_MAP(TransferTableSmu2Dram), \ + __SMU_DUMMY_MAP(TransferTableDram2Smu), \ + __SMU_DUMMY_MAP(UseDefaultPPTable), \ + __SMU_DUMMY_MAP(UseBackupPPTable), \ + __SMU_DUMMY_MAP(RunBtc), \ + __SMU_DUMMY_MAP(RequestI2CBus), \ + __SMU_DUMMY_MAP(ReleaseI2CBus), \ + __SMU_DUMMY_MAP(SetFloorSocVoltage), \ + __SMU_DUMMY_MAP(SoftReset), \ + __SMU_DUMMY_MAP(StartBacoMonitor), \ + __SMU_DUMMY_MAP(CancelBacoMonitor), \ + __SMU_DUMMY_MAP(EnterBaco), \ + __SMU_DUMMY_MAP(SetSoftMinByFreq), \ + __SMU_DUMMY_MAP(SetSoftMaxByFreq), \ + __SMU_DUMMY_MAP(SetHardMinByFreq), \ + __SMU_DUMMY_MAP(SetHardMaxByFreq), \ + __SMU_DUMMY_MAP(GetMinDpmFreq), \ + __SMU_DUMMY_MAP(GetMaxDpmFreq), \ + __SMU_DUMMY_MAP(GetDpmFreqByIndex), \ + __SMU_DUMMY_MAP(GetDpmClockFreq), \ + __SMU_DUMMY_MAP(GetSsVoltageByDpm), \ + __SMU_DUMMY_MAP(SetMemoryChannelConfig), \ + __SMU_DUMMY_MAP(SetGeminiMode), \ + __SMU_DUMMY_MAP(SetGeminiApertureHigh), \ + __SMU_DUMMY_MAP(SetGeminiApertureLow), \ + __SMU_DUMMY_MAP(SetMinLinkDpmByIndex), \ + __SMU_DUMMY_MAP(OverridePcieParameters), \ + __SMU_DUMMY_MAP(OverDriveSetPercentage), \ + __SMU_DUMMY_MAP(SetMinDeepSleepDcefclk), \ + __SMU_DUMMY_MAP(ReenableAcDcInterrupt), \ + __SMU_DUMMY_MAP(NotifyPowerSource), \ + __SMU_DUMMY_MAP(SetUclkFastSwitch), \ + __SMU_DUMMY_MAP(SetUclkDownHyst), \ + __SMU_DUMMY_MAP(GfxDeviceDriverReset), \ + __SMU_DUMMY_MAP(GetCurrentRpm), \ + __SMU_DUMMY_MAP(SetVideoFps), \ + __SMU_DUMMY_MAP(SetTjMax), \ + __SMU_DUMMY_MAP(SetFanTemperatureTarget), \ + __SMU_DUMMY_MAP(PrepareMp1ForUnload), \ + __SMU_DUMMY_MAP(DramLogSetDramAddrHigh), \ + __SMU_DUMMY_MAP(DramLogSetDramAddrLow), \ + __SMU_DUMMY_MAP(DramLogSetDramSize), \ + __SMU_DUMMY_MAP(SetFanMaxRpm), \ + __SMU_DUMMY_MAP(SetFanMinPwm), \ + __SMU_DUMMY_MAP(ConfigureGfxDidt), \ + __SMU_DUMMY_MAP(NumOfDisplays), \ + __SMU_DUMMY_MAP(RemoveMargins), \ + __SMU_DUMMY_MAP(ReadSerialNumTop32), \ + __SMU_DUMMY_MAP(ReadSerialNumBottom32), \ + __SMU_DUMMY_MAP(SetSystemVirtualDramAddrHigh), \ + __SMU_DUMMY_MAP(SetSystemVirtualDramAddrLow), \ + __SMU_DUMMY_MAP(WaflTest), \ + __SMU_DUMMY_MAP(SetFclkGfxClkRatio), \ + __SMU_DUMMY_MAP(AllowGfxOff), \ + __SMU_DUMMY_MAP(DisallowGfxOff), \ + __SMU_DUMMY_MAP(GetPptLimit), \ + __SMU_DUMMY_MAP(GetDcModeMaxDpmFreq), \ + __SMU_DUMMY_MAP(GetDebugData), \ + __SMU_DUMMY_MAP(SetXgmiMode), \ + __SMU_DUMMY_MAP(RunAfllBtc), \ + __SMU_DUMMY_MAP(ExitBaco), \ + __SMU_DUMMY_MAP(PrepareMp1ForReset), \ + __SMU_DUMMY_MAP(PrepareMp1ForShutdown), \ + __SMU_DUMMY_MAP(SetMGpuFanBoostLimitRpm), \ + __SMU_DUMMY_MAP(GetAVFSVoltageByDpm), \ + __SMU_DUMMY_MAP(PowerUpVcn), \ + __SMU_DUMMY_MAP(PowerDownVcn), \ + __SMU_DUMMY_MAP(PowerUpJpeg), \ + __SMU_DUMMY_MAP(PowerDownJpeg), \ + __SMU_DUMMY_MAP(BacoAudioD3PME), \ + __SMU_DUMMY_MAP(ArmD3), \ + __SMU_DUMMY_MAP(RunDcBtc), \ + __SMU_DUMMY_MAP(RunGfxDcBtc), \ + __SMU_DUMMY_MAP(RunSocDcBtc), \ + __SMU_DUMMY_MAP(SetMemoryChannelEnable), \ + __SMU_DUMMY_MAP(SetDfSwitchType), \ + __SMU_DUMMY_MAP(GetVoltageByDpm), \ + __SMU_DUMMY_MAP(GetVoltageByDpmOverdrive), \ + __SMU_DUMMY_MAP(PowerUpVcn0), \ + __SMU_DUMMY_MAP(PowerDownVcn0), \ + __SMU_DUMMY_MAP(PowerUpVcn1), \ + __SMU_DUMMY_MAP(PowerDownVcn1), \ + __SMU_DUMMY_MAP(PowerUpGfx), \ + __SMU_DUMMY_MAP(PowerDownIspByTile), \ + __SMU_DUMMY_MAP(PowerUpIspByTile), \ + __SMU_DUMMY_MAP(PowerDownSdma), \ + __SMU_DUMMY_MAP(PowerUpSdma), \ + __SMU_DUMMY_MAP(SetHardMinIspclkByFreq), \ + __SMU_DUMMY_MAP(SetHardMinVcn), \ + __SMU_DUMMY_MAP(Spare1), \ + __SMU_DUMMY_MAP(Spare2), \ + __SMU_DUMMY_MAP(SetAllowFclkSwitch), \ + __SMU_DUMMY_MAP(SetMinVideoGfxclkFreq), \ + __SMU_DUMMY_MAP(ActiveProcessNotify), \ + __SMU_DUMMY_MAP(SetCustomPolicy), \ + __SMU_DUMMY_MAP(QueryPowerLimit), \ + __SMU_DUMMY_MAP(SetGfxclkOverdriveByFreqVid), \ + __SMU_DUMMY_MAP(SetHardMinDcfclkByFreq), \ + __SMU_DUMMY_MAP(SetHardMinSocclkByFreq), \ + __SMU_DUMMY_MAP(ControlIgpuATS), \ + __SMU_DUMMY_MAP(SetMinVideoFclkFreq), \ + __SMU_DUMMY_MAP(SetMinDeepSleepDcfclk), \ + __SMU_DUMMY_MAP(ForcePowerDownGfx), \ + __SMU_DUMMY_MAP(SetPhyclkVoltageByFreq), \ + __SMU_DUMMY_MAP(SetDppclkVoltageByFreq), \ + __SMU_DUMMY_MAP(SetSoftMinVcn), \ + __SMU_DUMMY_MAP(EnablePostCode), \ + __SMU_DUMMY_MAP(GetGfxclkFrequency), \ + __SMU_DUMMY_MAP(GetFclkFrequency), \ + __SMU_DUMMY_MAP(GetMinGfxclkFrequency), \ + __SMU_DUMMY_MAP(GetMaxGfxclkFrequency), \ + __SMU_DUMMY_MAP(SetGfxCGPG), \ + __SMU_DUMMY_MAP(SetSoftMaxGfxClk), \ + __SMU_DUMMY_MAP(SetHardMinGfxClk), \ + __SMU_DUMMY_MAP(SetSoftMaxSocclkByFreq), \ + __SMU_DUMMY_MAP(SetSoftMaxFclkByFreq), \ + __SMU_DUMMY_MAP(SetSoftMaxVcn), \ + __SMU_DUMMY_MAP(PowerGateMmHub), \ + __SMU_DUMMY_MAP(UpdatePmeRestore), \ + __SMU_DUMMY_MAP(GpuChangeState), \ + __SMU_DUMMY_MAP(SetPowerLimitPercentage), \ + __SMU_DUMMY_MAP(ForceGfxContentSave), \ + __SMU_DUMMY_MAP(EnableTmdp48MHzRefclkPwrDown), \ + __SMU_DUMMY_MAP(PowerGateAtHub), \ + __SMU_DUMMY_MAP(SetSoftMinJpeg), \ + __SMU_DUMMY_MAP(SetHardMinFclkByFreq), \ + __SMU_DUMMY_MAP(DFCstateControl), \ + __SMU_DUMMY_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE), \ + __SMU_DUMMY_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE), \ + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(type) SMU_MSG_##type +enum smu_message_type { + SMU_MESSAGE_TYPES + SMU_MSG_MAX_COUNT, +}; + +enum smu_clk_type { + SMU_GFXCLK, + SMU_VCLK, + SMU_DCLK, + SMU_ECLK, + SMU_SOCCLK, + SMU_UCLK, + SMU_DCEFCLK, + SMU_DISPCLK, + SMU_PIXCLK, + SMU_PHYCLK, + SMU_FCLK, + SMU_SCLK, + SMU_MCLK, + SMU_PCIE, + SMU_OD_SCLK, + SMU_OD_MCLK, + SMU_OD_VDDC_CURVE, + SMU_OD_RANGE, + SMU_CLK_COUNT, +}; + +#define SMU_FEATURE_MASKS \ + __SMU_DUMMY_MAP(DPM_PREFETCHER), \ + __SMU_DUMMY_MAP(DPM_GFXCLK), \ + __SMU_DUMMY_MAP(DPM_UCLK), \ + __SMU_DUMMY_MAP(DPM_SOCCLK), \ + __SMU_DUMMY_MAP(DPM_UVD), \ + __SMU_DUMMY_MAP(DPM_VCE), \ + __SMU_DUMMY_MAP(ULV), \ + __SMU_DUMMY_MAP(DPM_MP0CLK), \ + __SMU_DUMMY_MAP(DPM_LINK), \ + __SMU_DUMMY_MAP(DPM_DCEFCLK), \ + __SMU_DUMMY_MAP(DS_GFXCLK), \ + __SMU_DUMMY_MAP(DS_SOCCLK), \ + __SMU_DUMMY_MAP(DS_LCLK), \ + __SMU_DUMMY_MAP(PPT), \ + __SMU_DUMMY_MAP(TDC), \ + __SMU_DUMMY_MAP(THERMAL), \ + __SMU_DUMMY_MAP(GFX_PER_CU_CG), \ + __SMU_DUMMY_MAP(RM), \ + __SMU_DUMMY_MAP(DS_DCEFCLK), \ + __SMU_DUMMY_MAP(ACDC), \ + __SMU_DUMMY_MAP(VR0HOT), \ + __SMU_DUMMY_MAP(VR1HOT), \ + __SMU_DUMMY_MAP(FW_CTF), \ + __SMU_DUMMY_MAP(LED_DISPLAY), \ + __SMU_DUMMY_MAP(FAN_CONTROL), \ + __SMU_DUMMY_MAP(GFX_EDC), \ + __SMU_DUMMY_MAP(GFXOFF), \ + __SMU_DUMMY_MAP(CG), \ + __SMU_DUMMY_MAP(DPM_FCLK), \ + __SMU_DUMMY_MAP(DS_FCLK), \ + __SMU_DUMMY_MAP(DS_MP1CLK), \ + __SMU_DUMMY_MAP(DS_MP0CLK), \ + __SMU_DUMMY_MAP(XGMI), \ + __SMU_DUMMY_MAP(DPM_GFX_PACE), \ + __SMU_DUMMY_MAP(MEM_VDDCI_SCALING), \ + __SMU_DUMMY_MAP(MEM_MVDD_SCALING), \ + __SMU_DUMMY_MAP(DS_UCLK), \ + __SMU_DUMMY_MAP(GFX_ULV), \ + __SMU_DUMMY_MAP(FW_DSTATE), \ + __SMU_DUMMY_MAP(BACO), \ + __SMU_DUMMY_MAP(VCN_PG), \ + __SMU_DUMMY_MAP(JPEG_PG), \ + __SMU_DUMMY_MAP(USB_PG), \ + __SMU_DUMMY_MAP(RSMU_SMN_CG), \ + __SMU_DUMMY_MAP(APCC_PLUS), \ + __SMU_DUMMY_MAP(GTHR), \ + __SMU_DUMMY_MAP(GFX_DCS), \ + __SMU_DUMMY_MAP(GFX_SS), \ + __SMU_DUMMY_MAP(OUT_OF_BAND_MONITOR), \ + __SMU_DUMMY_MAP(TEMP_DEPENDENT_VMIN), \ + __SMU_DUMMY_MAP(MMHUB_PG), \ + __SMU_DUMMY_MAP(ATHUB_PG), \ + __SMU_DUMMY_MAP(APCC_DFLL), \ + __SMU_DUMMY_MAP(WAFL_CG), + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(feature) SMU_FEATURE_##feature##_BIT +enum smu_feature_mask { + SMU_FEATURE_MASKS + SMU_FEATURE_COUNT, +}; + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h index 2fff4b16cb4e..d5314d12628a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h @@ -25,6 +25,12 @@ #include "amdgpu_smu.h" +#define SMU11_DRIVER_IF_VERSION_INV 0xFFFFFFFF +#define SMU11_DRIVER_IF_VERSION_VG20 0x13 +#define SMU11_DRIVER_IF_VERSION_ARCT 0x12 +#define SMU11_DRIVER_IF_VERSION_NV10 0x33 +#define SMU11_DRIVER_IF_VERSION_NV14 0x34 + /* MP Apertures */ #define MP0_Public 0x03800000 #define MP0_SRAM 0x03900000 @@ -42,20 +48,33 @@ #define SMU11_TOOL_SIZE 0x19000 +#define MAX_PCIE_CONF 2 + #define CLK_MAP(clk, index) \ - [SMU_##clk] = index + [SMU_##clk] = {1, (index)} #define FEA_MAP(fea) \ - [SMU_FEATURE_##fea##_BIT] = FEATURE_##fea##_BIT + [SMU_FEATURE_##fea##_BIT] = {1, FEATURE_##fea##_BIT} #define TAB_MAP(tab) \ - [SMU_TABLE_##tab] = TABLE_##tab + [SMU_TABLE_##tab] = {1, TABLE_##tab} #define PWR_MAP(tab) \ - [SMU_POWER_SOURCE_##tab] = POWER_SOURCE_##tab + [SMU_POWER_SOURCE_##tab] = {1, POWER_SOURCE_##tab} #define WORKLOAD_MAP(profile, workload) \ - [profile] = workload + [profile] = {1, (workload)} + +static const struct smu_temperature_range smu11_thermal_policy[] = +{ + {-273150, 99000, 99000, -273150, 99000, 99000, -273150, 99000, 99000}, + { 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000, 120000}, +}; + +struct smu_11_0_cmn2aisc_mapping { + int valid_mapping; + int map_to; +}; struct smu_11_0_max_sustainable_clocks { uint32_t display_clock; @@ -71,6 +90,11 @@ struct smu_11_0_dpm_table { uint32_t max; /* MHz */ }; +struct smu_11_0_pcie_table { + uint8_t pcie_gen[MAX_PCIE_CONF]; + uint8_t pcie_lane[MAX_PCIE_CONF]; +}; + struct smu_11_0_dpm_tables { struct smu_11_0_dpm_table soc_table; struct smu_11_0_dpm_table gfx_table; @@ -83,6 +107,7 @@ struct smu_11_0_dpm_tables { struct smu_11_0_dpm_table display_table; struct smu_11_0_dpm_table phy_table; struct smu_11_0_dpm_table fclk_table; + struct smu_11_0_pcie_table pcie_table; }; struct smu_11_0_dpm_context { @@ -113,6 +138,133 @@ enum smu_v11_0_baco_seq { BACO_SEQ_COUNT, }; -void smu_v11_0_set_smu_funcs(struct smu_context *smu); +int smu_v11_0_init_microcode(struct smu_context *smu); + +int smu_v11_0_load_microcode(struct smu_context *smu); + +int smu_v11_0_init_smc_tables(struct smu_context *smu); + +int smu_v11_0_fini_smc_tables(struct smu_context *smu); + +int smu_v11_0_init_power(struct smu_context *smu); + +int smu_v11_0_fini_power(struct smu_context *smu); + +int smu_v11_0_check_fw_status(struct smu_context *smu); + +int smu_v11_0_setup_pptable(struct smu_context *smu); + +int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu); + +int smu_v11_0_get_clk_info_from_vbios(struct smu_context *smu); + +int smu_v11_0_check_pptable(struct smu_context *smu); + +int smu_v11_0_parse_pptable(struct smu_context *smu); + +int smu_v11_0_populate_smc_pptable(struct smu_context *smu); + +int smu_v11_0_check_fw_version(struct smu_context *smu); + +int smu_v11_0_write_pptable(struct smu_context *smu); + +int smu_v11_0_set_min_dcef_deep_sleep(struct smu_context *smu); + +int smu_v11_0_set_driver_table_location(struct smu_context *smu); + +int smu_v11_0_set_tool_table_location(struct smu_context *smu); + +int smu_v11_0_notify_memory_pool_location(struct smu_context *smu); + +int smu_v11_0_system_features_control(struct smu_context *smu, + bool en); + +int +smu_v11_0_send_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param); + +int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg); + +int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count); + +int smu_v11_0_set_allowed_mask(struct smu_context *smu); + +int smu_v11_0_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num); + +int smu_v11_0_notify_display_change(struct smu_context *smu); + +int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n); + +int smu_v11_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_id, + uint32_t *value); + +int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu); + +int smu_v11_0_start_thermal_control(struct smu_context *smu); + +int smu_v11_0_stop_thermal_control(struct smu_context *smu); + +int smu_v11_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size); + +int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk); + +int +smu_v11_0_display_clock_voltage_request(struct smu_context *smu, + struct pp_display_clock_request + *clock_req); + +uint32_t +smu_v11_0_get_fan_control_mode(struct smu_context *smu); + +int +smu_v11_0_set_fan_control_mode(struct smu_context *smu, + uint32_t mode); + +int +smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed); + +int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, + uint32_t speed); + +int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, + uint32_t pstate); + +int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable); + +int smu_v11_0_register_irq_handler(struct smu_context *smu); + +int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu); + +int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, + struct pp_smu_nv_clock_table *max_clocks); + +bool smu_v11_0_baco_is_support(struct smu_context *smu); + +enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu); + +int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state); + +int smu_v11_0_baco_enter(struct smu_context *smu); +int smu_v11_0_baco_exit(struct smu_context *smu); + +int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max); + +int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t min, uint32_t max); + +int smu_v11_0_override_pcie_parameters(struct smu_context *smu); + +int smu_v11_0_set_default_od_settings(struct smu_context *smu, bool initialize, size_t overdrive_table_size); + +uint32_t smu_v11_0_get_max_power_limit(struct smu_context *smu); + +int smu_v11_0_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level); #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h index 373861ddccd0..406bfd187ce8 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_ppsmc.h @@ -120,7 +120,10 @@ #define PPSMC_MSG_GetVoltageByDpmOverdrive 0x45 #define PPSMC_MSG_BacoAudioD3PME 0x48 -#define PPSMC_Message_Count 0x49 +#define PPSMC_MSG_DALDisableDummyPstateChange 0x49 +#define PPSMC_MSG_DALEnableDummyPstateChange 0x4A + +#define PPSMC_Message_Count 0x4B typedef uint32_t PPSMC_Result; typedef uint32_t PPSMC_Msg; diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h index 86cdc3393eac..7a63cf8e85ed 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_pptable.h @@ -39,21 +39,39 @@ #define SMU_11_0_PP_OVERDRIVE_VERSION 0x0800 #define SMU_11_0_PP_POWERSAVINGCLOCK_VERSION 0x0100 +enum SMU_11_0_ODFEATURE_CAP { + SMU_11_0_ODCAP_GFXCLK_LIMITS = 0, + SMU_11_0_ODCAP_GFXCLK_CURVE, + SMU_11_0_ODCAP_UCLK_MAX, + SMU_11_0_ODCAP_POWER_LIMIT, + SMU_11_0_ODCAP_FAN_ACOUSTIC_LIMIT, + SMU_11_0_ODCAP_FAN_SPEED_MIN, + SMU_11_0_ODCAP_TEMPERATURE_FAN, + SMU_11_0_ODCAP_TEMPERATURE_SYSTEM, + SMU_11_0_ODCAP_MEMORY_TIMING_TUNE, + SMU_11_0_ODCAP_FAN_ZERO_RPM_CONTROL, + SMU_11_0_ODCAP_AUTO_UV_ENGINE, + SMU_11_0_ODCAP_AUTO_OC_ENGINE, + SMU_11_0_ODCAP_AUTO_OC_MEMORY, + SMU_11_0_ODCAP_FAN_CURVE, + SMU_11_0_ODCAP_COUNT, +}; + enum SMU_11_0_ODFEATURE_ID { - SMU_11_0_ODFEATURE_GFXCLK_LIMITS = 1 << 0, //GFXCLK Limit feature - SMU_11_0_ODFEATURE_GFXCLK_CURVE = 1 << 1, //GFXCLK Curve feature - SMU_11_0_ODFEATURE_UCLK_MAX = 1 << 2, //UCLK Limit feature - SMU_11_0_ODFEATURE_POWER_LIMIT = 1 << 3, //Power Limit feature - SMU_11_0_ODFEATURE_FAN_ACOUSTIC_LIMIT = 1 << 4, //Fan Acoustic RPM feature - SMU_11_0_ODFEATURE_FAN_SPEED_MIN = 1 << 5, //Minimum Fan Speed feature - SMU_11_0_ODFEATURE_TEMPERATURE_FAN = 1 << 6, //Fan Target Temperature Limit feature - SMU_11_0_ODFEATURE_TEMPERATURE_SYSTEM = 1 << 7, //Operating Temperature Limit feature - SMU_11_0_ODFEATURE_MEMORY_TIMING_TUNE = 1 << 8, //AC Timing Tuning feature - SMU_11_0_ODFEATURE_FAN_ZERO_RPM_CONTROL = 1 << 9, //Zero RPM feature - SMU_11_0_ODFEATURE_AUTO_UV_ENGINE = 1 << 10, //Auto Under Volt GFXCLK feature - SMU_11_0_ODFEATURE_AUTO_OC_ENGINE = 1 << 11, //Auto Over Clock GFXCLK feature - SMU_11_0_ODFEATURE_AUTO_OC_MEMORY = 1 << 12, //Auto Over Clock MCLK feature - SMU_11_0_ODFEATURE_FAN_CURVE = 1 << 13, //VICTOR TODO + SMU_11_0_ODFEATURE_GFXCLK_LIMITS = 1 << SMU_11_0_ODCAP_GFXCLK_LIMITS, //GFXCLK Limit feature + SMU_11_0_ODFEATURE_GFXCLK_CURVE = 1 << SMU_11_0_ODCAP_GFXCLK_CURVE, //GFXCLK Curve feature + SMU_11_0_ODFEATURE_UCLK_MAX = 1 << SMU_11_0_ODCAP_UCLK_MAX, //UCLK Limit feature + SMU_11_0_ODFEATURE_POWER_LIMIT = 1 << SMU_11_0_ODCAP_POWER_LIMIT, //Power Limit feature + SMU_11_0_ODFEATURE_FAN_ACOUSTIC_LIMIT = 1 << SMU_11_0_ODCAP_FAN_ACOUSTIC_LIMIT, //Fan Acoustic RPM feature + SMU_11_0_ODFEATURE_FAN_SPEED_MIN = 1 << SMU_11_0_ODCAP_FAN_SPEED_MIN, //Minimum Fan Speed feature + SMU_11_0_ODFEATURE_TEMPERATURE_FAN = 1 << SMU_11_0_ODCAP_TEMPERATURE_FAN, //Fan Target Temperature Limit feature + SMU_11_0_ODFEATURE_TEMPERATURE_SYSTEM = 1 << SMU_11_0_ODCAP_TEMPERATURE_SYSTEM, //Operating Temperature Limit feature + SMU_11_0_ODFEATURE_MEMORY_TIMING_TUNE = 1 << SMU_11_0_ODCAP_MEMORY_TIMING_TUNE, //AC Timing Tuning feature + SMU_11_0_ODFEATURE_FAN_ZERO_RPM_CONTROL = 1 << SMU_11_0_ODCAP_FAN_ZERO_RPM_CONTROL, //Zero RPM feature + SMU_11_0_ODFEATURE_AUTO_UV_ENGINE = 1 << SMU_11_0_ODCAP_AUTO_UV_ENGINE, //Auto Under Volt GFXCLK feature + SMU_11_0_ODFEATURE_AUTO_OC_ENGINE = 1 << SMU_11_0_ODCAP_AUTO_OC_ENGINE, //Auto Over Clock GFXCLK feature + SMU_11_0_ODFEATURE_AUTO_OC_MEMORY = 1 << SMU_11_0_ODCAP_AUTO_OC_MEMORY, //Auto Over Clock MCLK feature + SMU_11_0_ODFEATURE_FAN_CURVE = 1 << SMU_11_0_ODCAP_FAN_CURVE, //Fan Curve feature SMU_11_0_ODFEATURE_COUNT = 14, }; #define SMU_11_0_MAX_ODFEATURE 32 //Maximum Number of OD Features @@ -141,7 +159,9 @@ struct smu_11_0_powerplay_table struct smu_11_0_power_saving_clock_table power_saving_clock; struct smu_11_0_overdrive_table overdrive_table; +#ifndef SMU_11_0_PARTIAL_PPTABLE PPTable_t smc_pptable; //PPTable_t in smu11_driver_if.h +#endif } __attribute__((packed)); #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h new file mode 100644 index 000000000000..d79e54b5ebf6 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h @@ -0,0 +1,95 @@ +/* + * Copyright 2019 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 __SMU_V12_0_H__ +#define __SMU_V12_0_H__ + +#include "amdgpu_smu.h" + +/* MP Apertures */ +#define MP0_Public 0x03800000 +#define MP0_SRAM 0x03900000 +#define MP1_Public 0x03b00000 +#define MP1_SRAM 0x03c00004 + + +struct smu_12_0_cmn2aisc_mapping { + int valid_mapping; + int map_to; +}; + +int smu_v12_0_send_msg_without_waiting(struct smu_context *smu, + uint16_t msg); + +int smu_v12_0_read_arg(struct smu_context *smu, uint32_t *arg); + +int smu_v12_0_wait_for_response(struct smu_context *smu); + +int +smu_v12_0_send_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param); + +int smu_v12_0_check_fw_status(struct smu_context *smu); + +int smu_v12_0_check_fw_version(struct smu_context *smu); + +int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate); + +int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate); + +int smu_v12_0_powergate_jpeg(struct smu_context *smu, bool gate); + +int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable); + +int smu_v12_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size); + +uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu); + +int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable); + +int smu_v12_0_init_smc_tables(struct smu_context *smu); + +int smu_v12_0_fini_smc_tables(struct smu_context *smu); + +int smu_v12_0_populate_smc_tables(struct smu_context *smu); + +int smu_v12_0_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num); + +int smu_v12_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_id, + uint32_t *value); + +int smu_v12_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max); + +int smu_v12_0_mode2_reset(struct smu_context *smu); + +int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t min, uint32_t max); + +int smu_v12_0_set_driver_table_location(struct smu_context *smu); + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0_ppsmc.h new file mode 100644 index 000000000000..9ac9f3bd3664 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0_ppsmc.h @@ -0,0 +1,106 @@ +/* + * Copyright 2019 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 SMU_12_0_PPSMC_H +#define SMU_12_0_PPSMC_H + +// SMU Response Codes: +#define PPSMC_Result_OK 0x1 +#define PPSMC_Result_Failed 0xFF +#define PPSMC_Result_UnknownCmd 0xFE +#define PPSMC_Result_CmdRejectedPrereq 0xFD +#define PPSMC_Result_CmdRejectedBusy 0xFC + + +// Message Definitions: +#define PPSMC_MSG_TestMessage 0x1 +#define PPSMC_MSG_GetSmuVersion 0x2 +#define PPSMC_MSG_GetDriverIfVersion 0x3 +#define PPSMC_MSG_PowerUpGfx 0x6 +#define PPSMC_MSG_EnableGfxOff 0x7 +#define PPSMC_MSG_DisableGfxOff 0x8 +#define PPSMC_MSG_PowerDownIspByTile 0x9 // ISP is power gated by default +#define PPSMC_MSG_PowerUpIspByTile 0xA +#define PPSMC_MSG_PowerDownVcn 0xB // VCN is power gated by default +#define PPSMC_MSG_PowerUpVcn 0xC +#define PPSMC_MSG_PowerDownSdma 0xD // SDMA is power gated by default +#define PPSMC_MSG_PowerUpSdma 0xE +#define PPSMC_MSG_SetHardMinIspclkByFreq 0xF +#define PPSMC_MSG_SetHardMinVcn 0x10 // For wireless display +#define PPSMC_MSG_spare1 0x11 +#define PPSMC_MSG_spare2 0x12 +#define PPSMC_MSG_SetAllowFclkSwitch 0x13 +#define PPSMC_MSG_SetMinVideoGfxclkFreq 0x14 +#define PPSMC_MSG_ActiveProcessNotify 0x15 +#define PPSMC_MSG_SetCustomPolicy 0x16 +#define PPSMC_MSG_SetVideoFps 0x17 +#define PPSMC_MSG_SetDisplayCount 0x18 // Moved to VBIOS +#define PPSMC_MSG_QueryPowerLimit 0x19 //Driver to look up sustainable clocks for VQ +#define PPSMC_MSG_SetDriverDramAddrHigh 0x1A +#define PPSMC_MSG_SetDriverDramAddrLow 0x1B +#define PPSMC_MSG_TransferTableSmu2Dram 0x1C +#define PPSMC_MSG_TransferTableDram2Smu 0x1D +#define PPSMC_MSG_GfxDeviceDriverReset 0x1E +#define PPSMC_MSG_SetGfxclkOverdriveByFreqVid 0x1F +#define PPSMC_MSG_SetHardMinDcfclkByFreq 0x20 // Moved to VBIOS +#define PPSMC_MSG_SetHardMinSocclkByFreq 0x21 +#define PPSMC_MSG_ControlIgpuATS 0x22 +#define PPSMC_MSG_SetMinVideoFclkFreq 0x23 +#define PPSMC_MSG_SetMinDeepSleepDcfclk 0x24 // Moved to VBIOS +#define PPSMC_MSG_ForcePowerDownGfx 0x25 +#define PPSMC_MSG_SetPhyclkVoltageByFreq 0x26 // Moved to VBIOS +#define PPSMC_MSG_SetDppclkVoltageByFreq 0x27 // Moved to VBIOS and is SetDppclkFreq +#define PPSMC_MSG_SetSoftMinVcn 0x28 +#define PPSMC_MSG_EnablePostCode 0x29 +#define PPSMC_MSG_GetGfxclkFrequency 0x2A +#define PPSMC_MSG_GetFclkFrequency 0x2B +#define PPSMC_MSG_GetMinGfxclkFrequency 0x2C +#define PPSMC_MSG_GetMaxGfxclkFrequency 0x2D +#define PPSMC_MSG_SoftReset 0x2E // Not supported +#define PPSMC_MSG_SetGfxCGPG 0x2F +#define PPSMC_MSG_SetSoftMaxGfxClk 0x30 +#define PPSMC_MSG_SetHardMinGfxClk 0x31 +#define PPSMC_MSG_SetSoftMaxSocclkByFreq 0x32 +#define PPSMC_MSG_SetSoftMaxFclkByFreq 0x33 +#define PPSMC_MSG_SetSoftMaxVcn 0x34 +#define PPSMC_MSG_PowerGateMmHub 0x35 +#define PPSMC_MSG_UpdatePmeRestore 0x36 // Moved to VBIOS +#define PPSMC_MSG_GpuChangeState 0x37 +#define PPSMC_MSG_SetPowerLimitPercentage 0x38 +#define PPSMC_MSG_ForceGfxContentSave 0x39 +#define PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown 0x3A // Moved to VBIOS +#define PPSMC_MSG_PowerDownJpeg 0x3B +#define PPSMC_MSG_PowerUpJpeg 0x3C +#define PPSMC_MSG_PowerGateAtHub 0x3D +#define PPSMC_MSG_SetSoftMinJpeg 0x3E +#define PPSMC_MSG_SetHardMinFclkByFreq 0x3F +#define PPSMC_Message_Count 0x40 + + +//Argument for PPSMC_MSG_GpuChangeState +enum { + eGpuChangeState_D0Entry = 1, + eGpuChangeState_D3Entry, +}; + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h index a0883038f3c3..0c66f0fe1aaf 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/vega20_ppsmc.h @@ -120,7 +120,8 @@ #define PPSMC_MSG_SetMGpuFanBoostLimitRpm 0x5D #define PPSMC_MSG_GetAVFSVoltageByDpm 0x5F #define PPSMC_MSG_BacoWorkAroundFlushVDCI 0x60 -#define PPSMC_Message_Count 0x61 +#define PPSMC_MSG_DFCstateControl 0x63 +#define PPSMC_Message_Count 0x64 typedef uint32_t PPSMC_Result; typedef uint32_t PPSMC_Msg; diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c index b81c7e715dc9..0d73a49166af 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c @@ -26,6 +26,7 @@ #include <linux/pci.h> #include "amdgpu.h" #include "amdgpu_smu.h" +#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" #include "smu_v11_0.h" @@ -35,6 +36,7 @@ #include "navi10_ppt.h" #include "smu_v11_0_pptable.h" #include "smu_v11_0_ppsmc.h" +#include "nbio/nbio_7_4_sh_mask.h" #include "asic_reg/mp/mp_11_0_sh_mask.h" @@ -50,9 +52,9 @@ FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) #define MSG_MAP(msg, index) \ - [SMU_MSG_##msg] = index + [SMU_MSG_##msg] = {1, (index)} -static int navi10_message_map[SMU_MSG_MAX_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage, PPSMC_MSG_TestMessage), MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion), MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion), @@ -117,9 +119,13 @@ static int navi10_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg), MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME), MSG_MAP(ArmD3, PPSMC_MSG_ArmD3), + MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange), + MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange), + MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm), + MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive), }; -static int navi10_clk_map[SMU_CLK_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = { CLK_MAP(GFXCLK, PPCLK_GFXCLK), CLK_MAP(SCLK, PPCLK_GFXCLK), CLK_MAP(SOCCLK, PPCLK_SOCCLK), @@ -134,7 +140,7 @@ static int navi10_clk_map[SMU_CLK_COUNT] = { CLK_MAP(PHYCLK, PPCLK_PHYCLK), }; -static int navi10_feature_mask_map[SMU_FEATURE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(DPM_PREFETCHER), FEA_MAP(DPM_GFXCLK), FEA_MAP(DPM_GFX_PACE), @@ -177,9 +183,10 @@ static int navi10_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(TEMP_DEPENDENT_VMIN), FEA_MAP(MMHUB_PG), FEA_MAP(ATHUB_PG), + FEA_MAP(APCC_DFLL), }; -static int navi10_table_map[SMU_TABLE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PPTABLE), TAB_MAP(WATERMARKS), TAB_MAP(AVFS), @@ -194,96 +201,110 @@ static int navi10_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PACE), }; -static int navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { PWR_MAP(AC), PWR_MAP(DC), }; -static int navi10_workload_map[] = { +static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_PPLIB_DEFAULT_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_CUSTOM_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), }; static int navi10_get_smu_msg_index(struct smu_context *smc, uint32_t index) { - int val; - if (index > SMU_MSG_MAX_COUNT) + struct smu_11_0_cmn2aisc_mapping mapping; + + if (index >= SMU_MSG_MAX_COUNT) return -EINVAL; - val = navi10_message_map[index]; - if (val > PPSMC_Message_Count) + mapping = navi10_message_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int navi10_get_smu_clk_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_CLK_COUNT) return -EINVAL; - val = navi10_clk_map[index]; - if (val >= PPCLK_COUNT) + mapping = navi10_clk_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int navi10_get_smu_feature_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_FEATURE_COUNT) return -EINVAL; - val = navi10_feature_mask_map[index]; - if (val > 64) + mapping = navi10_feature_mask_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int navi10_get_smu_table_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_TABLE_COUNT) return -EINVAL; - val = navi10_table_map[index]; - if (val >= TABLE_COUNT) + mapping = navi10_table_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int navi10_get_pwr_src_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_POWER_SOURCE_COUNT) return -EINVAL; - val = navi10_pwr_src_map[index]; - if (val >= POWER_SOURCE_COUNT) + mapping = navi10_pwr_src_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int navi10_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (profile > PP_SMC_POWER_PROFILE_CUSTOM) return -EINVAL; - val = navi10_workload_map[profile]; + mapping = navi10_workload_map[profile]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } - return val; + return mapping.map_to; } static bool is_asic_secure(struct smu_context *smu) @@ -313,40 +334,52 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, memset(feature_mask, 0, sizeof(uint32_t) * num); *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) - | FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) - | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) - | FEATURE_MASK(FEATURE_DPM_LINK_BIT) - | FEATURE_MASK(FEATURE_GFX_ULV_BIT) | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) | FEATURE_MASK(FEATURE_PPT_BIT) | FEATURE_MASK(FEATURE_TDC_BIT) | FEATURE_MASK(FEATURE_GFX_EDC_BIT) + | FEATURE_MASK(FEATURE_APCC_PLUS_BIT) | FEATURE_MASK(FEATURE_VR0HOT_BIT) | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) | FEATURE_MASK(FEATURE_THERMAL_BIT) | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) - | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) - | FEATURE_MASK(FEATURE_DS_GFXCLK_BIT) + | FEATURE_MASK(FEATURE_DS_LCLK_BIT) | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) | FEATURE_MASK(FEATURE_BACO_BIT) | FEATURE_MASK(FEATURE_ACDC_BIT) | FEATURE_MASK(FEATURE_GFX_SS_BIT) | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) - | FEATURE_MASK(FEATURE_FW_CTF_BIT); + | FEATURE_MASK(FEATURE_FW_CTF_BIT) + | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT); + + if (adev->pm.pp_feature & PP_SOCCLK_DPM_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + + if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); + + if (adev->pm.pp_feature & PP_PCIE_DPM_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_LINK_BIT); + + if (adev->pm.pp_feature & PP_DCEFCLK_DPM_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT); if (adev->pm.pp_feature & PP_MCLK_DPM_MASK) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | FEATURE_MASK(FEATURE_MEM_VDDCI_SCALING_BIT) | FEATURE_MASK(FEATURE_MEM_MVDD_SCALING_BIT); - if (adev->pm.pp_feature & PP_GFXOFF_MASK) { + if (adev->pm.pp_feature & PP_ULV_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFX_ULV_BIT); + + if (adev->pm.pp_feature & PP_SCLK_DEEP_SLEEP_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DS_GFXCLK_BIT); + + if (adev->pm.pp_feature & PP_GFXOFF_MASK) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_GFXOFF_BIT); - /* TODO: remove it once fw fix the bug */ - *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_FW_DSTATE_BIT); - } if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); @@ -357,6 +390,9 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN) *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_VCN_PG_BIT); + if (smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_JPEG_PG_BIT); + /* disable DPM UCLK and DS SOCCLK on navi10 A0 secure board */ if (is_asic_secure(smu)) { /* only for navi10 A0 */ @@ -523,6 +559,10 @@ static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables) return -ENOMEM; smu_table->metrics_time = 0; + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + if (!smu_table->watermarks_table) + return -ENOMEM; + return 0; } @@ -532,17 +572,20 @@ static int navi10_get_metrics_table(struct smu_context *smu, struct smu_table_context *smu_table= &smu->smu_table; int ret = 0; - if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + HZ / 1000)) { + mutex_lock(&smu->metrics_lock); + if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) { ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)smu_table->metrics_table, false); if (ret) { pr_info("Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); return ret; } smu_table->metrics_time = jiffies; } memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + mutex_unlock(&smu->metrics_lock); return ret; } @@ -570,6 +613,7 @@ static int navi10_set_default_dpm_table(struct smu_context *smu) struct smu_table_context *table_context = &smu->smu_table; struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; PPTable_t *driver_ppt = NULL; + int i; driver_ppt = table_context->driver_pptable; @@ -600,6 +644,11 @@ static int navi10_set_default_dpm_table(struct smu_context *smu) dpm_context->dpm_tables.phy_table.min = driver_ppt->FreqTablePhyclk[0]; dpm_context->dpm_tables.phy_table.max = driver_ppt->FreqTablePhyclk[NUM_PHYCLK_DPM_LEVELS - 1]; + for (i = 0; i < MAX_PCIE_CONF; i++) { + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = driver_ppt->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = driver_ppt->PcieLaneCount[i]; + } + return 0; } @@ -629,6 +678,31 @@ static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable) return ret; } +static int navi10_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg(smu, SMU_MSG_PowerUpJpeg); + if (ret) + return ret; + } + power_gate->jpeg_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownJpeg); + if (ret) + return ret; + } + power_gate->jpeg_gated = true; + } + + return ret; +} + static int navi10_get_current_clk_freq_by_table(struct smu_context *smu, enum smu_clk_type clk_type, uint32_t *value) @@ -662,13 +736,39 @@ static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu return dpm_desc->SnapToDiscrete == 0 ? true : false; } +static inline bool navi10_od_feature_is_supported(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODFEATURE_CAP cap) +{ + return od_table->cap[cap]; +} + +static void navi10_od_setting_get_range(struct smu_11_0_overdrive_table *od_table, + enum SMU_11_0_ODSETTING_ID setting, + uint32_t *min, uint32_t *max) +{ + if (min) + *min = od_table->min[setting]; + if (max) + *max = od_table->max[setting]; +} + static int navi10_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, char *buf) { + uint16_t *curve_settings; int i, size = 0, ret = 0; uint32_t cur_value = 0, value = 0, count = 0; uint32_t freq_values[3] = {0}; uint32_t mark_index = 0; + struct smu_table_context *table_context = &smu->smu_table; + uint32_t gen_speed, lane_width; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; + struct amdgpu_device *adev = smu->adev; + PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; + OverDriveTable_t *od_table = + (OverDriveTable_t *)table_context->overdrive_table; + struct smu_11_0_overdrive_table *od_settings = smu->od_settings; + uint32_t min_value, max_value; switch (clk_type) { case SMU_GFXCLK: @@ -719,6 +819,118 @@ static int navi10_print_clk_levels(struct smu_context *smu, } break; + case SMU_PCIE: + gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) & + PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK) + >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT; + lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) & + PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK) + >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT; + for (i = 0; i < NUM_LINK_LEVELS; i++) + size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i, + (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," : + (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 1) ? "5.0GT/s," : + (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 2) ? "8.0GT/s," : + (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 3) ? "16.0GT/s," : "", + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 1) ? "x1" : + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 2) ? "x2" : + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 3) ? "x4" : + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 4) ? "x8" : + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 5) ? "x12" : + (dpm_context->dpm_tables.pcie_table.pcie_lane[i] == 6) ? "x16" : "", + pptable->LclkFreq[i], + (gen_speed == dpm_context->dpm_tables.pcie_table.pcie_gen[i]) && + (lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ? + "*" : ""); + break; + case SMU_OD_SCLK: + if (!smu->od_enabled || !od_table || !od_settings) + break; + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) + break; + size += sprintf(buf + size, "OD_SCLK:\n"); + size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax); + break; + case SMU_OD_MCLK: + if (!smu->od_enabled || !od_table || !od_settings) + break; + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) + break; + size += sprintf(buf + size, "OD_MCLK:\n"); + size += sprintf(buf + size, "1: %uMHz\n", od_table->UclkFmax); + break; + case SMU_OD_VDDC_CURVE: + if (!smu->od_enabled || !od_table || !od_settings) + break; + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) + break; + size += sprintf(buf + size, "OD_VDDC_CURVE:\n"); + for (i = 0; i < 3; i++) { + switch (i) { + case 0: + curve_settings = &od_table->GfxclkFreq1; + break; + case 1: + curve_settings = &od_table->GfxclkFreq2; + break; + case 2: + curve_settings = &od_table->GfxclkFreq3; + break; + default: + break; + } + size += sprintf(buf + size, "%d: %uMHz @ %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE); + } + break; + case SMU_OD_RANGE: + if (!smu->od_enabled || !od_table || !od_settings) + break; + size = sprintf(buf, "%s:\n", "OD_RANGE"); + + if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMIN, + &min_value, NULL); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_GFXCLKFMAX, + NULL, &max_value); + size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n", + min_value, max_value); + } + + if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, + &min_value, &max_value); + size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n", + min_value, max_value); + } + + if (navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", + min_value, max_value); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", + min_value, max_value); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", + min_value, max_value); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", + min_value, max_value); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", + min_value, max_value); + navi10_od_setting_get_range(od_settings, SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3, + &min_value, &max_value); + size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", + min_value, max_value); + } + + break; default: break; } @@ -744,6 +956,12 @@ static int navi10_force_clk_levels(struct smu_context *smu, case SMU_UCLK: case SMU_DCEFCLK: case SMU_FCLK: + /* There is only 2 levels for fine grained DPM */ + if (navi10_is_support_fine_grained_dpm(smu, clk_type)) { + soft_max_level = (soft_max_level >= 1 ? 1 : 0); + soft_min_level = (soft_min_level >= 1 ? 1 : 0); + } + ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); if (ret) return size; @@ -768,13 +986,13 @@ static int navi10_populate_umd_state_clk(struct smu_context *smu) int ret = 0; uint32_t min_sclk_freq = 0, min_mclk_freq = 0; - ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL); + ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL, false); if (ret) return ret; smu->pstate_sclk = min_sclk_freq * 100; - ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL); + ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL, false); if (ret) return ret; @@ -794,6 +1012,8 @@ static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, case SMU_GFXCLK: case SMU_DCEFCLK: case SMU_SOCCLK: + case SMU_MCLK: + case SMU_UCLK: ret = smu_get_dpm_level_count(smu, clk_type, &level_count); if (ret) return ret; @@ -827,7 +1047,7 @@ static int navi10_pre_display_config_changed(struct smu_context *smu) return ret; if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { - ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &max_freq); + ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &max_freq, false); if (ret) return ret; ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, max_freq); @@ -877,7 +1097,7 @@ static int navi10_force_dpm_limit_value(struct smu_context *smu, bool highest) for (i = 0; i < ARRAY_SIZE(clks); i++) { clk_type = clks[i]; - ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq); + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false); if (ret) return ret; @@ -904,7 +1124,7 @@ static int navi10_unforce_dpm_levels(struct smu_context *smu) for (i = 0; i < ARRAY_SIZE(clks); i++) { clk_type = clks[i]; - ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq); + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false); if (ret) return ret; @@ -927,8 +1147,6 @@ static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value) ret = navi10_get_metrics_table(smu, &metrics); if (ret) return ret; - if (ret) - return ret; *value = metrics.AverageSocketPower << 8; @@ -987,8 +1205,6 @@ static int navi10_get_fan_speed_rpm(struct smu_context *smu, ret = navi10_get_metrics_table(smu, &metrics); if (ret) return ret; - if (ret) - return ret; *speed = metrics.CurrFanSpeed; @@ -1017,7 +1233,7 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) { DpmActivityMonitorCoeffInt_t activity_monitor; uint32_t i, size = 0; - uint16_t workload_type = 0; + int16_t workload_type = 0; static const char *profile_name[] = { "BOOTUP_DEFAULT", "3D_FULL_SCREEN", @@ -1050,6 +1266,9 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf) for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_workload_get_type(smu, i); + if (workload_type < 0) + return -EINVAL; + result = smu_update_table(smu, SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, (void *)(&activity_monitor), false); @@ -1178,6 +1397,8 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_workload_get_type(smu, smu->power_profile_mode); + if (workload_type < 0) + return -EINVAL; smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1 << workload_type); @@ -1225,7 +1446,7 @@ static int navi10_get_profiling_clk_mask(struct smu_context *smu, return ret; } -static int navi10_notify_smc_dispaly_config(struct smu_context *smu) +static int navi10_notify_smc_display_config(struct smu_context *smu) { struct smu_clocks min_clocks = {0}; struct pp_display_clock_request clock_req; @@ -1238,7 +1459,9 @@ static int navi10_notify_smc_dispaly_config(struct smu_context *smu) if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { clock_req.clock_type = amd_pp_dcef_clock; clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; - if (!smu_display_clock_voltage_request(smu, &clock_req)) { + + ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req); + if (!ret) { if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetMinDeepSleepDcefclk, @@ -1367,6 +1590,10 @@ static int navi10_read_sensor(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; PPTable_t *pptable = table_context->driver_pptable; + if(!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); switch (sensor) { case AMDGPU_PP_SENSOR_MAX_FAN_RPM: *(uint32_t *)data = pptable->FanMaximumRpm; @@ -1388,8 +1615,9 @@ static int navi10_read_sensor(struct smu_context *smu, *size = 4; break; default: - return -EINVAL; + ret = smu_v11_0_read_sensor(smu, sensor, data, size); } + mutex_unlock(&smu->sensor_lock); return ret; } @@ -1423,194 +1651,94 @@ static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_ return 0; } -static int navi10_get_ppfeature_status(struct smu_context *smu, - char *buf) -{ - static const char *ppfeature_name[] = { - "DPM_PREFETCHER", - "DPM_GFXCLK", - "DPM_GFX_PACE", - "DPM_UCLK", - "DPM_SOCCLK", - "DPM_MP0CLK", - "DPM_LINK", - "DPM_DCEFCLK", - "MEM_VDDCI_SCALING", - "MEM_MVDD_SCALING", - "DS_GFXCLK", - "DS_SOCCLK", - "DS_LCLK", - "DS_DCEFCLK", - "DS_UCLK", - "GFX_ULV", - "FW_DSTATE", - "GFXOFF", - "BACO", - "VCN_PG", - "JPEG_PG", - "USB_PG", - "RSMU_SMN_CG", - "PPT", - "TDC", - "GFX_EDC", - "APCC_PLUS", - "GTHR", - "ACDC", - "VR0HOT", - "VR1HOT", - "FW_CTF", - "FAN_CONTROL", - "THERMAL", - "GFX_DCS", - "RM", - "LED_DISPLAY", - "GFX_SS", - "OUT_OF_BAND_MONITOR", - "TEMP_DEPENDENT_VMIN", - "MMHUB_PG", - "ATHUB_PG"}; - static const char *output_title[] = { - "FEATURES", - "BITMASK", - "ENABLEMENT"}; - uint64_t features_enabled; - uint32_t feature_mask[2]; - int i; - int ret = 0; - int size = 0; - - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); - PP_ASSERT_WITH_CODE(!ret, - "[GetPPfeatureStatus] Failed to get enabled smc features!", - return ret); - features_enabled = (uint64_t)feature_mask[0] | - (uint64_t)feature_mask[1] << 32; - - size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled); - size += sprintf(buf + size, "%-19s %-22s %s\n", - output_title[0], - output_title[1], - output_title[2]); - for (i = 0; i < (sizeof(ppfeature_name) / sizeof(ppfeature_name[0])); i++) { - size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", - ppfeature_name[i], - 1ULL << i, - (features_enabled & (1ULL << i)) ? "Y" : "N"); - } - - return size; -} +static int navi10_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level); -static int navi10_enable_smc_features(struct smu_context *smu, - bool enabled, - uint64_t feature_masks) +static int navi10_set_standard_performance_level(struct smu_context *smu) { - struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_low, feature_high; - uint32_t feature_mask[2]; + struct amdgpu_device *adev = smu->adev; int ret = 0; + uint32_t sclk_freq = 0, uclk_freq = 0; - feature_low = (uint32_t)(feature_masks & 0xFFFFFFFF); - feature_high = (uint32_t)((feature_masks & 0xFFFFFFFF00000000ULL) >> 32); - - if (enabled) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, - feature_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, - feature_high); - if (ret) - return ret; - } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, - feature_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, - feature_high); - if (ret) - return ret; + switch (adev->asic_type) { + case CHIP_NAVI10: + sclk_freq = NAVI10_UMD_PSTATE_PROFILING_GFXCLK; + uclk_freq = NAVI10_UMD_PSTATE_PROFILING_MEMCLK; + break; + case CHIP_NAVI14: + sclk_freq = NAVI14_UMD_PSTATE_PROFILING_GFXCLK; + uclk_freq = NAVI14_UMD_PSTATE_PROFILING_MEMCLK; + break; + default: + /* by default, this is same as auto performance level */ + return navi10_set_performance_level(smu, AMD_DPM_FORCED_LEVEL_AUTO); } - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq); + if (ret) + return ret; + ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq); if (ret) return ret; - mutex_lock(&feature->mutex); - bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, - feature->feature_num); - mutex_unlock(&feature->mutex); - - return 0; -} - -static int navi10_set_ppfeature_status(struct smu_context *smu, - uint64_t new_ppfeature_masks) -{ - uint64_t features_enabled; - uint32_t feature_mask[2]; - uint64_t features_to_enable; - uint64_t features_to_disable; - int ret = 0; - - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); - PP_ASSERT_WITH_CODE(!ret, - "[SetPPfeatureStatus] Failed to get enabled smc features!", - return ret); - features_enabled = (uint64_t)feature_mask[0] | - (uint64_t)feature_mask[1] << 32; - - features_to_disable = - features_enabled & ~new_ppfeature_masks; - features_to_enable = - ~features_enabled & new_ppfeature_masks; - - pr_debug("features_to_disable 0x%llx\n", features_to_disable); - pr_debug("features_to_enable 0x%llx\n", features_to_enable); - - if (features_to_disable) { - ret = navi10_enable_smc_features(smu, false, features_to_disable); - PP_ASSERT_WITH_CODE(!ret, - "[SetPPfeatureStatus] Failed to disable smc features!", - return ret); - } - - if (features_to_enable) { - ret = navi10_enable_smc_features(smu, true, features_to_enable); - PP_ASSERT_WITH_CODE(!ret, - "[SetPPfeatureStatus] Failed to enable smc features!", - return ret); - } - - return 0; + return ret; } -static int navi10_set_peak_clock_by_device(struct smu_context *smu) +static int navi10_set_peak_performance_level(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; int ret = 0; uint32_t sclk_freq = 0, uclk_freq = 0; - uint32_t uclk_level = 0; - switch (adev->pdev->revision) { - case 0xf0: /* XTX */ - case 0xc0: - sclk_freq = NAVI10_PEAK_SCLK_XTX; + switch (adev->asic_type) { + case CHIP_NAVI10: + switch (adev->pdev->revision) { + case 0xf0: /* XTX */ + case 0xc0: + sclk_freq = NAVI10_PEAK_SCLK_XTX; + break; + case 0xf1: /* XT */ + case 0xc1: + sclk_freq = NAVI10_PEAK_SCLK_XT; + break; + default: /* XL */ + sclk_freq = NAVI10_PEAK_SCLK_XL; + break; + } break; - case 0xf1: /* XT */ - case 0xc1: - sclk_freq = NAVI10_PEAK_SCLK_XT; + case CHIP_NAVI14: + switch (adev->pdev->revision) { + case 0xc7: /* XT */ + case 0xf4: + sclk_freq = NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK; + break; + case 0xc1: /* XTM */ + case 0xf2: + sclk_freq = NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK; + break; + case 0xc3: /* XLM */ + case 0xf3: + sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK; + break; + case 0xc5: /* XTX */ + case 0xf6: + sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK; + break; + default: /* XL */ + sclk_freq = NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK; + break; + } break; - default: /* XL */ - sclk_freq = NAVI10_PEAK_SCLK_XL; + case CHIP_NAVI12: + sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK; break; + default: + ret = smu_get_dpm_level_range(smu, SMU_SCLK, NULL, &sclk_freq); + if (ret) + return ret; } - ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_level); - if (ret) - return ret; - ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, uclk_level - 1, &uclk_freq); + ret = smu_get_dpm_level_range(smu, SMU_UCLK, NULL, &uclk_freq); if (ret) return ret; @@ -1624,19 +1752,45 @@ static int navi10_set_peak_clock_by_device(struct smu_context *smu) return ret; } -static int navi10_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) +static int navi10_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) { int ret = 0; + uint32_t sclk_mask, mclk_mask, soc_mask; switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + ret = smu_force_dpm_limit_value(smu, true); + break; + case AMD_DPM_FORCED_LEVEL_LOW: + ret = smu_force_dpm_limit_value(smu, false); + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + ret = smu_unforce_dpm_levels(smu); + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + ret = navi10_set_standard_performance_level(smu); + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + ret = smu_get_profiling_clk_mask(smu, level, + &sclk_mask, + &mclk_mask, + &soc_mask); + if (ret) + return ret; + smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false); + smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false); + smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false); + break; case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: - ret = navi10_set_peak_clock_by_device(smu); + ret = navi10_set_peak_performance_level(smu); break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: - ret = -EINVAL; break; } - return ret; } @@ -1649,13 +1803,474 @@ static int navi10_get_thermal_temperature_range(struct smu_context *smu, if (!range || !powerplay_table) return -EINVAL; - /* The unit is temperature */ - range->min = 0; - range->max = powerplay_table->software_shutdown_temp; + range->max = powerplay_table->software_shutdown_temp * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int navi10_display_disable_memory_clock_switch(struct smu_context *smu, + bool disable_memory_clock_switch) +{ + int ret = 0; + struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks = + (struct smu_11_0_max_sustainable_clocks *) + smu->smu_table.max_sustainable_clocks; + uint32_t min_memory_clock = smu->hard_min_uclk_req_from_dal; + uint32_t max_memory_clock = max_sustainable_clocks->uclock; + + if(smu->disable_uclk_switch == disable_memory_clock_switch) + return 0; + + if(disable_memory_clock_switch) + ret = smu_set_hard_freq_range(smu, SMU_UCLK, max_memory_clock, 0); + else + ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_memory_clock, 0); + + if(!ret) + smu->disable_uclk_switch = disable_memory_clock_switch; + + return ret; +} + +static uint32_t navi10_get_pptable_power_limit(struct smu_context *smu) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; +} + +static int navi10_get_power_limit(struct smu_context *smu, + uint32_t *limit, + bool cap) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t asic_default_power_limit = 0; + int ret = 0; + int power_src; + + if (!smu->power_limit) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { + power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC); + if (power_src < 0) + return -EINVAL; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit, + power_src << 16); + if (ret) { + pr_err("[%s] get PPT limit failed!", __func__); + return ret; + } + smu_read_smc_arg(smu, &asic_default_power_limit); + } else { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + pr_err("Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + asic_default_power_limit = + pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; + } + + smu->power_limit = asic_default_power_limit; + } + + if (cap) + *limit = smu_v11_0_get_max_power_limit(smu); + else + *limit = smu->power_limit; + + return 0; +} + +static int navi10_update_pcie_parameters(struct smu_context *smu, + uint32_t pcie_gen_cap, + uint32_t pcie_width_cap) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + int ret, i; + uint32_t smu_pcie_arg; + + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; + + for (i = 0; i < NUM_LINK_LEVELS; i++) { + smu_pcie_arg = (i << 16) | + ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) : + (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ? + pptable->PcieLaneCount[i] : pcie_width_cap); + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg); + + if (ret) + return ret; + + if (pptable->PcieGenSpeed[i] > pcie_gen_cap) + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pcie_gen_cap; + if (pptable->PcieLaneCount[i] > pcie_width_cap) + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pcie_width_cap; + } + + return 0; +} + +static inline void navi10_dump_od_table(OverDriveTable_t *od_table) { + pr_debug("OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax); + pr_debug("OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1); + pr_debug("OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2); + pr_debug("OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3); + pr_debug("OD: UclkFmax: %d\n", od_table->UclkFmax); + pr_debug("OD: OverDrivePct: %d\n", od_table->OverDrivePct); +} + +static int navi10_od_setting_check_range(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODSETTING_ID setting, uint32_t value) +{ + if (value < od_table->min[setting]) { + pr_warn("OD setting (%d, %d) is less than the minimum allowed (%d)\n", setting, value, od_table->min[setting]); + return -EINVAL; + } + if (value > od_table->max[setting]) { + pr_warn("OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]); + return -EINVAL; + } + return 0; +} + +static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu, + uint16_t *voltage, + uint32_t freq) +{ + uint32_t param = (freq & 0xFFFF) | (PPCLK_GFXCLK << 16); + uint32_t value = 0; + int ret; + + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_GetVoltageByDpm, + param); + if (ret) { + pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!"); + return ret; + } + + smu_read_smc_arg(smu, &value); + *voltage = (uint16_t)value; return 0; } +static int navi10_setup_od_limits(struct smu_context *smu) { + struct smu_11_0_overdrive_table *overdrive_table = NULL; + struct smu_11_0_powerplay_table *powerplay_table = NULL; + + if (!smu->smu_table.power_play_table) { + pr_err("powerplay table uninitialized!\n"); + return -ENOENT; + } + powerplay_table = (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table; + overdrive_table = &powerplay_table->overdrive_table; + if (!smu->od_settings) { + smu->od_settings = kmemdup(overdrive_table, sizeof(struct smu_11_0_overdrive_table), GFP_KERNEL); + } else { + memcpy(smu->od_settings, overdrive_table, sizeof(struct smu_11_0_overdrive_table)); + } + return 0; +} + +static int navi10_set_default_od_settings(struct smu_context *smu, bool initialize) { + OverDriveTable_t *od_table, *boot_od_table; + int ret = 0; + + ret = smu_v11_0_set_default_od_settings(smu, initialize, sizeof(OverDriveTable_t)); + if (ret) + return ret; + + od_table = (OverDriveTable_t *)smu->smu_table.overdrive_table; + boot_od_table = (OverDriveTable_t *)smu->smu_table.boot_overdrive_table; + if (initialize) { + ret = navi10_setup_od_limits(smu); + if (ret) { + pr_err("Failed to retrieve board OD limits\n"); + return ret; + } + if (od_table) { + if (!od_table->GfxclkVolt1) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt1, + od_table->GfxclkFreq1); + if (ret) + od_table->GfxclkVolt1 = 0; + if (boot_od_table) + boot_od_table->GfxclkVolt1 = od_table->GfxclkVolt1; + } + + if (!od_table->GfxclkVolt2) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt2, + od_table->GfxclkFreq2); + if (ret) + od_table->GfxclkVolt2 = 0; + if (boot_od_table) + boot_od_table->GfxclkVolt2 = od_table->GfxclkVolt2; + } + + if (!od_table->GfxclkVolt3) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt3, + od_table->GfxclkFreq3); + if (ret) + od_table->GfxclkVolt3 = 0; + if (boot_od_table) + boot_od_table->GfxclkVolt3 = od_table->GfxclkVolt3; + } + } + } + + if (od_table) { + navi10_dump_od_table(od_table); + } + + return ret; +} + +static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) { + int i; + int ret = 0; + struct smu_table_context *table_context = &smu->smu_table; + OverDriveTable_t *od_table; + struct smu_11_0_overdrive_table *od_settings; + enum SMU_11_0_ODSETTING_ID freq_setting, voltage_setting; + uint16_t *freq_ptr, *voltage_ptr; + od_table = (OverDriveTable_t *)table_context->overdrive_table; + + if (!smu->od_enabled) { + pr_warn("OverDrive is not enabled!\n"); + return -EINVAL; + } + + if (!smu->od_settings) { + pr_err("OD board limits are not set!\n"); + return -ENOENT; + } + + od_settings = smu->od_settings; + + switch (type) { + case PP_OD_EDIT_SCLK_VDDC_TABLE: + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) { + pr_warn("GFXCLK_LIMITS not supported!\n"); + return -ENOTSUPP; + } + if (!table_context->overdrive_table) { + pr_err("Overdrive is not initialized\n"); + return -EINVAL; + } + for (i = 0; i < size; i += 2) { + if (i + 2 > size) { + pr_info("invalid number of input parameters %d\n", size); + return -EINVAL; + } + switch (input[i]) { + case 0: + freq_setting = SMU_11_0_ODSETTING_GFXCLKFMIN; + freq_ptr = &od_table->GfxclkFmin; + if (input[i + 1] > od_table->GfxclkFmax) { + pr_info("GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n", + input[i + 1], + od_table->GfxclkFmin); + return -EINVAL; + } + break; + case 1: + freq_setting = SMU_11_0_ODSETTING_GFXCLKFMAX; + freq_ptr = &od_table->GfxclkFmax; + if (input[i + 1] < od_table->GfxclkFmin) { + pr_info("GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n", + input[i + 1], + od_table->GfxclkFmax); + return -EINVAL; + } + break; + default: + pr_info("Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]); + pr_info("Supported indices: [0:min,1:max]\n"); + return -EINVAL; + } + ret = navi10_od_setting_check_range(od_settings, freq_setting, input[i + 1]); + if (ret) + return ret; + *freq_ptr = input[i + 1]; + } + break; + case PP_OD_EDIT_MCLK_VDDC_TABLE: + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) { + pr_warn("UCLK_MAX not supported!\n"); + return -ENOTSUPP; + } + if (size < 2) { + pr_info("invalid number of parameters: %d\n", size); + return -EINVAL; + } + if (input[0] != 1) { + pr_info("Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]); + pr_info("Supported indices: [1:max]\n"); + return -EINVAL; + } + ret = navi10_od_setting_check_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]); + if (ret) + return ret; + od_table->UclkFmax = input[1]; + break; + case PP_OD_RESTORE_DEFAULT_TABLE: + if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) { + pr_err("Overdrive table was not initialized!\n"); + return -EINVAL; + } + memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t)); + break; + case PP_OD_COMMIT_DPM_TABLE: + navi10_dump_od_table(od_table); + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true); + if (ret) { + pr_err("Failed to import overdrive table!\n"); + return ret; + } + // no lock needed because smu_od_edit_dpm_table has it + ret = smu_handle_task(smu, smu->smu_dpm.dpm_level, + AMD_PP_TASK_READJUST_POWER_STATE, + false); + if (ret) { + return ret; + } + break; + case PP_OD_EDIT_VDDC_CURVE: + if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) { + pr_warn("GFXCLK_CURVE not supported!\n"); + return -ENOTSUPP; + } + if (size < 3) { + pr_info("invalid number of parameters: %d\n", size); + return -EINVAL; + } + if (!od_table) { + pr_info("Overdrive is not initialized\n"); + return -EINVAL; + } + + switch (input[0]) { + case 0: + freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P1; + voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P1; + freq_ptr = &od_table->GfxclkFreq1; + voltage_ptr = &od_table->GfxclkVolt1; + break; + case 1: + freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P2; + voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P2; + freq_ptr = &od_table->GfxclkFreq2; + voltage_ptr = &od_table->GfxclkVolt2; + break; + case 2: + freq_setting = SMU_11_0_ODSETTING_VDDGFXCURVEFREQ_P3; + voltage_setting = SMU_11_0_ODSETTING_VDDGFXCURVEVOLTAGE_P3; + freq_ptr = &od_table->GfxclkFreq3; + voltage_ptr = &od_table->GfxclkVolt3; + break; + default: + pr_info("Invalid VDDC_CURVE index: %ld\n", input[0]); + pr_info("Supported indices: [0, 1, 2]\n"); + return -EINVAL; + } + ret = navi10_od_setting_check_range(od_settings, freq_setting, input[1]); + if (ret) + return ret; + // Allow setting zero to disable the OverDrive VDDC curve + if (input[2] != 0) { + ret = navi10_od_setting_check_range(od_settings, voltage_setting, input[2]); + if (ret) + return ret; + *freq_ptr = input[1]; + *voltage_ptr = ((uint16_t)input[2]) * NAVI10_VOLTAGE_SCALE; + pr_debug("OD: set curve %ld: (%d, %d)\n", input[0], *freq_ptr, *voltage_ptr); + } else { + // If setting 0, disable all voltage curve settings + od_table->GfxclkVolt1 = 0; + od_table->GfxclkVolt2 = 0; + od_table->GfxclkVolt3 = 0; + } + navi10_dump_od_table(od_table); + break; + default: + return -ENOSYS; + } + return ret; +} + +static int navi10_run_btc(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_send_smc_msg(smu, SMU_MSG_RunBtc); + if (ret) + pr_err("RunBtc failed!\n"); + + return ret; +} + +static int navi10_dummy_pstate_control(struct smu_context *smu, bool enable) +{ + int result = 0; + + if (!enable) + result = smu_send_smc_msg(smu, SMU_MSG_DAL_DISABLE_DUMMY_PSTATE_CHANGE); + else + result = smu_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE); + + return result; +} + +static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu) +{ + uint32_t uclk_count, uclk_min, uclk_max; + uint32_t smu_version; + int ret = 0; + + ret = smu_get_smc_version(smu, NULL, &smu_version); + if (ret) + return ret; + + /* This workaround is available only for 42.50 or later SMC firmwares */ + if (smu_version < 0x2A3200) + return 0; + + ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_count); + if (ret) + return ret; + + ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)0, &uclk_min); + if (ret) + return ret; + + ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)(uclk_count - 1), &uclk_max); + if (ret) + return ret; + + /* Force UCLK out of the highest DPM */ + ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, uclk_min); + if (ret) + return ret; + + /* Revert the UCLK Hardmax */ + ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, uclk_max); + if (ret) + return ret; + + /* + * In this case, SMU already disabled dummy pstate during enablement + * of UCLK DPM, we have to re-enabled it. + * */ + return navi10_dummy_pstate_control(smu, true); +} + static const struct pptable_funcs navi10_ppt_funcs = { .tables_init = navi10_tables_init, .alloc_dpm_context = navi10_allocate_dpm_context, @@ -1671,6 +2286,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .get_allowed_feature_mask = navi10_get_allowed_feature_mask, .set_default_dpm_table = navi10_set_default_dpm_table, .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable, + .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable, .get_current_clk_freq_by_table = navi10_get_current_clk_freq_by_table, .print_clk_levels = navi10_print_clk_levels, .force_clk_levels = navi10_force_clk_levels, @@ -1678,7 +2294,7 @@ static const struct pptable_funcs navi10_ppt_funcs = { .get_clock_by_type_with_latency = navi10_get_clock_by_type_with_latency, .pre_display_config_changed = navi10_pre_display_config_changed, .display_config_changed = navi10_display_config_changed, - .notify_smc_dispaly_config = navi10_notify_smc_dispaly_config, + .notify_smc_display_config = navi10_notify_smc_display_config, .force_dpm_limit_value = navi10_force_dpm_limit_value, .unforce_dpm_levels = navi10_unforce_dpm_levels, .is_dpm_running = navi10_is_dpm_running, @@ -1690,17 +2306,69 @@ static const struct pptable_funcs navi10_ppt_funcs = { .set_watermarks_table = navi10_set_watermarks_table, .read_sensor = navi10_read_sensor, .get_uclk_dpm_states = navi10_get_uclk_dpm_states, - .get_ppfeature_status = navi10_get_ppfeature_status, - .set_ppfeature_status = navi10_set_ppfeature_status, .set_performance_level = navi10_set_performance_level, .get_thermal_temperature_range = navi10_get_thermal_temperature_range, + .display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch, + .get_power_limit = navi10_get_power_limit, + .update_pcie_parameters = navi10_update_pcie_parameters, + .init_microcode = smu_v11_0_init_microcode, + .load_microcode = smu_v11_0_load_microcode, + .init_smc_tables = smu_v11_0_init_smc_tables, + .fini_smc_tables = smu_v11_0_fini_smc_tables, + .init_power = smu_v11_0_init_power, + .fini_power = smu_v11_0_fini_power, + .check_fw_status = smu_v11_0_check_fw_status, + .setup_pptable = smu_v11_0_setup_pptable, + .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, + .get_clk_info_from_vbios = smu_v11_0_get_clk_info_from_vbios, + .check_pptable = smu_v11_0_check_pptable, + .parse_pptable = smu_v11_0_parse_pptable, + .populate_smc_tables = smu_v11_0_populate_smc_pptable, + .check_fw_version = smu_v11_0_check_fw_version, + .write_pptable = smu_v11_0_write_pptable, + .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep, + .set_driver_table_location = smu_v11_0_set_driver_table_location, + .set_tool_table_location = smu_v11_0_set_tool_table_location, + .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, + .system_features_control = smu_v11_0_system_features_control, + .send_smc_msg_with_param = smu_v11_0_send_msg_with_param, + .read_smc_arg = smu_v11_0_read_arg, + .init_display_count = smu_v11_0_init_display_count, + .set_allowed_mask = smu_v11_0_set_allowed_mask, + .get_enabled_mask = smu_v11_0_get_enabled_mask, + .notify_display_change = smu_v11_0_notify_display_change, + .set_power_limit = smu_v11_0_set_power_limit, + .get_current_clk_freq = smu_v11_0_get_current_clk_freq, + .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, + .start_thermal_control = smu_v11_0_start_thermal_control, + .stop_thermal_control = smu_v11_0_stop_thermal_control, + .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk, + .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, + .get_fan_control_mode = smu_v11_0_get_fan_control_mode, + .set_fan_control_mode = smu_v11_0_set_fan_control_mode, + .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, + .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, + .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, + .gfx_off_control = smu_v11_0_gfx_off_control, + .register_irq_handler = smu_v11_0_register_irq_handler, + .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, + .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, + .baco_is_support= smu_v11_0_baco_is_support, + .baco_get_state = smu_v11_0_baco_get_state, + .baco_set_state = smu_v11_0_baco_set_state, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, + .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, + .override_pcie_parameters = smu_v11_0_override_pcie_parameters, + .set_default_od_settings = navi10_set_default_od_settings, + .od_edit_dpm_table = navi10_od_edit_dpm_table, + .get_pptable_power_limit = navi10_get_pptable_power_limit, + .run_btc = navi10_run_btc, + .disable_umc_cdr_12gbps_workaround = navi10_disable_umc_cdr_12gbps_workaround, }; void navi10_set_ppt_funcs(struct smu_context *smu) { - struct smu_table_context *smu_table = &smu->smu_table; - smu->ppt_funcs = &navi10_ppt_funcs; - smu->smc_if_version = SMU11_DRIVER_IF_VERSION; - smu_table->table_count = TABLE_COUNT; } diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h b/drivers/gpu/drm/amd/powerplay/navi10_ppt.h index 620ff17c2fef..2abb4ba01db1 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.h +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.h @@ -27,6 +27,31 @@ #define NAVI10_PEAK_SCLK_XT (1755) #define NAVI10_PEAK_SCLK_XL (1625) +#define NAVI10_UMD_PSTATE_PROFILING_GFXCLK (1300) +#define NAVI10_UMD_PSTATE_PROFILING_SOCCLK (980) +#define NAVI10_UMD_PSTATE_PROFILING_MEMCLK (625) +#define NAVI10_UMD_PSTATE_PROFILING_VCLK (980) +#define NAVI10_UMD_PSTATE_PROFILING_DCLK (850) + +#define NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK (1670) +#define NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK (1448) +#define NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK (1181) +#define NAVI14_UMD_PSTATE_PEAK_XTX_GFXCLK (1717) +#define NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK (1448) + +#define NAVI14_UMD_PSTATE_PROFILING_GFXCLK (1200) +#define NAVI14_UMD_PSTATE_PROFILING_SOCCLK (900) +#define NAVI14_UMD_PSTATE_PROFILING_MEMCLK (600) +#define NAVI14_UMD_PSTATE_PROFILING_VCLK (900) +#define NAVI14_UMD_PSTATE_PROFILING_DCLK (800) + +#define NAVI12_UMD_PSTATE_PEAK_GFXCLK (1100) + +#define NAVI10_VOLTAGE_SCALE (4) + +#define smnPCIE_LC_SPEED_CNTL 0x11140290 +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 + extern void navi10_set_ppt_funcs(struct smu_context *smu); #endif diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c new file mode 100644 index 000000000000..861e6410363b --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c @@ -0,0 +1,931 @@ +/* + * Copyright 2019 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 "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_internal.h" +#include "soc15_common.h" +#include "smu_v12_0_ppsmc.h" +#include "smu12_driver_if.h" +#include "smu_v12_0.h" +#include "renoir_ppt.h" + + +#define CLK_MAP(clk, index) \ + [SMU_##clk] = {1, (index)} + +#define MSG_MAP(msg, index) \ + [SMU_MSG_##msg] = {1, (index)} + +#define TAB_MAP_VALID(tab) \ + [SMU_TABLE_##tab] = {1, TABLE_##tab} + +#define TAB_MAP_INVALID(tab) \ + [SMU_TABLE_##tab] = {0, TABLE_##tab} + +static struct smu_12_0_cmn2aisc_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion), + MSG_MAP(PowerUpGfx, PPSMC_MSG_PowerUpGfx), + MSG_MAP(AllowGfxOff, PPSMC_MSG_EnableGfxOff), + MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisableGfxOff), + MSG_MAP(PowerDownIspByTile, PPSMC_MSG_PowerDownIspByTile), + MSG_MAP(PowerUpIspByTile, PPSMC_MSG_PowerUpIspByTile), + MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn), + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn), + MSG_MAP(PowerDownSdma, PPSMC_MSG_PowerDownSdma), + MSG_MAP(PowerUpSdma, PPSMC_MSG_PowerUpSdma), + MSG_MAP(SetHardMinIspclkByFreq, PPSMC_MSG_SetHardMinIspclkByFreq), + MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn), + MSG_MAP(Spare1, PPSMC_MSG_spare1), + MSG_MAP(Spare2, PPSMC_MSG_spare2), + MSG_MAP(SetAllowFclkSwitch, PPSMC_MSG_SetAllowFclkSwitch), + MSG_MAP(SetMinVideoGfxclkFreq, PPSMC_MSG_SetMinVideoGfxclkFreq), + MSG_MAP(ActiveProcessNotify, PPSMC_MSG_ActiveProcessNotify), + MSG_MAP(SetCustomPolicy, PPSMC_MSG_SetCustomPolicy), + MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps), + MSG_MAP(NumOfDisplays, PPSMC_MSG_SetDisplayCount), + MSG_MAP(QueryPowerLimit, PPSMC_MSG_QueryPowerLimit), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset), + MSG_MAP(SetGfxclkOverdriveByFreqVid, PPSMC_MSG_SetGfxclkOverdriveByFreqVid), + MSG_MAP(SetHardMinDcfclkByFreq, PPSMC_MSG_SetHardMinDcfclkByFreq), + MSG_MAP(SetHardMinSocclkByFreq, PPSMC_MSG_SetHardMinSocclkByFreq), + MSG_MAP(ControlIgpuATS, PPSMC_MSG_ControlIgpuATS), + MSG_MAP(SetMinVideoFclkFreq, PPSMC_MSG_SetMinVideoFclkFreq), + MSG_MAP(SetMinDeepSleepDcfclk, PPSMC_MSG_SetMinDeepSleepDcfclk), + MSG_MAP(ForcePowerDownGfx, PPSMC_MSG_ForcePowerDownGfx), + MSG_MAP(SetPhyclkVoltageByFreq, PPSMC_MSG_SetPhyclkVoltageByFreq), + MSG_MAP(SetDppclkVoltageByFreq, PPSMC_MSG_SetDppclkVoltageByFreq), + MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn), + MSG_MAP(EnablePostCode, PPSMC_MSG_EnablePostCode), + MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency), + MSG_MAP(GetFclkFrequency, PPSMC_MSG_GetFclkFrequency), + MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxclkFrequency), + MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxclkFrequency), + MSG_MAP(SoftReset, PPSMC_MSG_SoftReset), + MSG_MAP(SetGfxCGPG, PPSMC_MSG_SetGfxCGPG), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk), + MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk), + MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq), + MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq), + MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn), + MSG_MAP(PowerGateMmHub, PPSMC_MSG_PowerGateMmHub), + MSG_MAP(UpdatePmeRestore, PPSMC_MSG_UpdatePmeRestore), + MSG_MAP(GpuChangeState, PPSMC_MSG_GpuChangeState), + MSG_MAP(SetPowerLimitPercentage, PPSMC_MSG_SetPowerLimitPercentage), + MSG_MAP(ForceGfxContentSave, PPSMC_MSG_ForceGfxContentSave), + MSG_MAP(EnableTmdp48MHzRefclkPwrDown, PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown), + MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg), + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg), + MSG_MAP(PowerGateAtHub, PPSMC_MSG_PowerGateAtHub), + MSG_MAP(SetSoftMinJpeg, PPSMC_MSG_SetSoftMinJpeg), + MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq), +}; + +static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = { + CLK_MAP(GFXCLK, CLOCK_GFXCLK), + CLK_MAP(SCLK, CLOCK_GFXCLK), + CLK_MAP(SOCCLK, CLOCK_SOCCLK), + CLK_MAP(UCLK, CLOCK_UMCCLK), + CLK_MAP(MCLK, CLOCK_UMCCLK), +}; + +static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = { + TAB_MAP_VALID(WATERMARKS), + TAB_MAP_INVALID(CUSTOM_DPM), + TAB_MAP_VALID(DPMCLOCKS), + TAB_MAP_VALID(SMU_METRICS), +}; + +static int renoir_get_smu_msg_index(struct smu_context *smc, uint32_t index) +{ + struct smu_12_0_cmn2aisc_mapping mapping; + + if (index >= SMU_MSG_MAX_COUNT) + return -EINVAL; + + mapping = renoir_message_map[index]; + if (!(mapping.valid_mapping)) + return -EINVAL; + + return mapping.map_to; +} + +static int renoir_get_smu_clk_index(struct smu_context *smc, uint32_t index) +{ + struct smu_12_0_cmn2aisc_mapping mapping; + + if (index >= SMU_CLK_COUNT) + return -EINVAL; + + mapping = renoir_clk_map[index]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } + + return mapping.map_to; +} + +static int renoir_get_smu_table_index(struct smu_context *smc, uint32_t index) +{ + struct smu_12_0_cmn2aisc_mapping mapping; + + if (index >= SMU_TABLE_COUNT) + return -EINVAL; + + mapping = renoir_table_map[index]; + if (!(mapping.valid_mapping)) + return -EINVAL; + + return mapping.map_to; +} + +static int renoir_get_metrics_table(struct smu_context *smu, + SmuMetrics_t *metrics_table) +{ + struct smu_table_context *smu_table= &smu->smu_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) { + ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, + (void *)smu_table->metrics_table, false); + if (ret) { + pr_info("Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); + return ret; + } + smu_table->metrics_time = jiffies; + } + + memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_DPMCLOCKS, sizeof(DpmClocks_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + + smu_table->clocks_table = kzalloc(sizeof(DpmClocks_t), GFP_KERNEL); + if (!smu_table->clocks_table) + return -ENOMEM; + + smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL); + if (!smu_table->metrics_table) + return -ENOMEM; + smu_table->metrics_time = 0; + + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + if (!smu_table->watermarks_table) + return -ENOMEM; + + return 0; +} + +/** + * This interface just for getting uclk ultimate freq and should't introduce + * other likewise function result in overmuch callback. + */ +static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t dpm_level, uint32_t *freq) +{ + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + + if (!clk_table || clk_type >= SMU_CLK_COUNT) + return -EINVAL; + + GET_DPM_CUR_FREQ(clk_table, clk_type, dpm_level, *freq); + + return 0; +} + +static int renoir_print_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf) +{ + int i, size = 0, ret = 0; + uint32_t cur_value = 0, value = 0, count = 0, min = 0, max = 0; + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + SmuMetrics_t metrics; + + if (!clk_table || clk_type >= SMU_CLK_COUNT) + return -EINVAL; + + memset(&metrics, 0, sizeof(metrics)); + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + /* retirve table returned paramters unit is MHz */ + cur_value = metrics.ClockFrequency[CLOCK_GFXCLK]; + ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min, &max, false); + if (!ret) { + /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ + if (cur_value == max) + i = 2; + else if (cur_value == min) + i = 0; + else + i = 1; + + size += sprintf(buf + size, "0: %uMhz %s\n", min, + i == 0 ? "*" : ""); + size += sprintf(buf + size, "1: %uMhz %s\n", + i == 1 ? cur_value : RENOIR_UMD_PSTATE_GFXCLK, + i == 1 ? "*" : ""); + size += sprintf(buf + size, "2: %uMhz %s\n", max, + i == 2 ? "*" : ""); + } + return size; + case SMU_SOCCLK: + count = NUM_SOCCLK_DPM_LEVELS; + cur_value = metrics.ClockFrequency[CLOCK_SOCCLK]; + break; + case SMU_MCLK: + count = NUM_MEMCLK_DPM_LEVELS; + cur_value = metrics.ClockFrequency[CLOCK_UMCCLK]; + break; + case SMU_DCEFCLK: + count = NUM_DCFCLK_DPM_LEVELS; + cur_value = metrics.ClockFrequency[CLOCK_DCFCLK]; + break; + case SMU_FCLK: + count = NUM_FCLK_DPM_LEVELS; + cur_value = metrics.ClockFrequency[CLOCK_FCLK]; + break; + default: + return -EINVAL; + } + + for (i = 0; i < count; i++) { + GET_DPM_CUR_FREQ(clk_table, clk_type, i, value); + size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, + cur_value == value ? "*" : ""); + } + + return size; +} + +static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context *smu) +{ + enum amd_pm_state_type pm_type; + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + + if (!smu_dpm_ctx->dpm_context || + !smu_dpm_ctx->dpm_current_power_state) + return -EINVAL; + + switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) { + case SMU_STATE_UI_LABEL_BATTERY: + pm_type = POWER_STATE_TYPE_BATTERY; + break; + case SMU_STATE_UI_LABEL_BALLANCED: + pm_type = POWER_STATE_TYPE_BALANCED; + break; + case SMU_STATE_UI_LABEL_PERFORMANCE: + pm_type = POWER_STATE_TYPE_PERFORMANCE; + break; + default: + if (smu_dpm_ctx->dpm_current_power_state->classification.flags & SMU_STATE_CLASSIFICATION_FLAG_BOOT) + pm_type = POWER_STATE_TYPE_INTERNAL_BOOT; + else + pm_type = POWER_STATE_TYPE_DEFAULT; + break; + } + + return pm_type; +} + +static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + /* vcn dpm on is a prerequisite for vcn power gate messages */ + if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0); + if (ret) + return ret; + } + power_gate->vcn_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn); + if (ret) + return ret; + } + power_gate->vcn_gated = true; + } + + return ret; +} + +static int renoir_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; + + if (enable) { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = false; + } else { + if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0); + if (ret) + return ret; + } + power_gate->jpeg_gated = true; + } + + return ret; +} + +static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + int ret = 0, clk_id = 0; + SmuMetrics_t metrics; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) + return clk_id; + + *value = metrics.ClockFrequency[clk_id]; + + return ret; +} + +static int renoir_force_dpm_limit_value(struct smu_context *smu, bool highest) +{ + int ret = 0, i = 0; + uint32_t min_freq, max_freq, force_freq; + enum smu_clk_type clk_type; + + enum smu_clk_type clks[] = { + SMU_GFXCLK, + SMU_MCLK, + SMU_SOCCLK, + }; + + for (i = 0; i < ARRAY_SIZE(clks); i++) { + clk_type = clks[i]; + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false); + if (ret) + return ret; + + force_freq = highest ? max_freq : min_freq; + ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq); + if (ret) + return ret; + } + + return ret; +} + +static int renoir_unforce_dpm_levels(struct smu_context *smu) { + + int ret = 0, i = 0; + uint32_t min_freq, max_freq; + enum smu_clk_type clk_type; + + struct clk_feature_map { + enum smu_clk_type clk_type; + uint32_t feature; + } clk_feature_map[] = { + {SMU_GFXCLK, SMU_FEATURE_DPM_GFXCLK_BIT}, + {SMU_MCLK, SMU_FEATURE_DPM_UCLK_BIT}, + {SMU_SOCCLK, SMU_FEATURE_DPM_SOCCLK_BIT}, + }; + + for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { + if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature)) + continue; + + clk_type = clk_feature_map[i].clk_type; + + ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false); + if (ret) + return ret; + + ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq); + if (ret) + return ret; + } + + return ret; +} + +static int renoir_get_gpu_temperature(struct smu_context *smu, uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + *value = (metrics.GfxTemperature / 100) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + + return 0; +} + +static int renoir_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + SmuMetrics_t metrics; + + if (!value) + return -EINVAL; + + ret = renoir_get_metrics_table(smu, &metrics); + if (ret) + return ret; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + *value = metrics.AverageGfxActivity / 100; + break; + default: + pr_err("Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return 0; +} + +static int renoir_get_workload_type(struct smu_context *smu, uint32_t profile) +{ + + uint32_t pplib_workload = 0; + + switch (profile) { + case PP_SMC_POWER_PROFILE_FULLSCREEN3D: + pplib_workload = WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT; + break; + case PP_SMC_POWER_PROFILE_CUSTOM: + pplib_workload = WORKLOAD_PPLIB_COUNT; + break; + case PP_SMC_POWER_PROFILE_VIDEO: + pplib_workload = WORKLOAD_PPLIB_VIDEO_BIT; + break; + case PP_SMC_POWER_PROFILE_VR: + pplib_workload = WORKLOAD_PPLIB_VR_BIT; + break; + case PP_SMC_POWER_PROFILE_COMPUTE: + pplib_workload = WORKLOAD_PPLIB_COMPUTE_BIT; + break; + default: + return -EINVAL; + } + + return pplib_workload; +} + +static int renoir_get_profiling_clk_mask(struct smu_context *smu, + enum amd_dpm_forced_level level, + uint32_t *sclk_mask, + uint32_t *mclk_mask, + uint32_t *soc_mask) +{ + + if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { + if (sclk_mask) + *sclk_mask = 0; + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { + if (mclk_mask) + *mclk_mask = 0; + } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { + if(sclk_mask) + /* The sclk as gfxclk and has three level about max/min/current */ + *sclk_mask = 3 - 1; + + if(mclk_mask) + *mclk_mask = NUM_MEMCLK_DPM_LEVELS - 1; + + if(soc_mask) + *soc_mask = NUM_SOCCLK_DPM_LEVELS - 1; + } + + return 0; +} + +/** + * This interface get dpm clock table for dc + */ +static int renoir_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table) +{ + DpmClocks_t *table = smu->smu_table.clocks_table; + int i; + + if (!clock_table || !table) + return -EINVAL; + + for (i = 0; i < NUM_DCFCLK_DPM_LEVELS; i++) { + clock_table->DcfClocks[i].Freq = table->DcfClocks[i].Freq; + clock_table->DcfClocks[i].Vol = table->DcfClocks[i].Vol; + } + + for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) { + clock_table->SocClocks[i].Freq = table->SocClocks[i].Freq; + clock_table->SocClocks[i].Vol = table->SocClocks[i].Vol; + } + + for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) { + clock_table->FClocks[i].Freq = table->FClocks[i].Freq; + clock_table->FClocks[i].Vol = table->FClocks[i].Vol; + } + + for (i = 0; i< NUM_MEMCLK_DPM_LEVELS; i++) { + clock_table->MemClocks[i].Freq = table->MemClocks[i].Freq; + clock_table->MemClocks[i].Vol = table->MemClocks[i].Vol; + } + + return 0; +} + +static int renoir_force_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, uint32_t mask) +{ + + int ret = 0 ; + uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0; + DpmClocks_t *clk_table = smu->smu_table.clocks_table; + + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + if (soft_min_level > 2 || soft_max_level > 2) { + pr_info("Currently sclk only support 3 levels on APU\n"); + return -EINVAL; + } + + ret = smu_get_dpm_freq_range(smu, SMU_GFXCLK, &min_freq, &max_freq, false); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, + soft_max_level == 0 ? min_freq : + soft_max_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : max_freq); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, + soft_min_level == 2 ? max_freq : + soft_min_level == 1 ? RENOIR_UMD_PSTATE_GFXCLK : min_freq); + if (ret) + return ret; + break; + case SMU_SOCCLK: + GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq); + GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq); + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq); + if (ret) + return ret; + break; + case SMU_MCLK: + case SMU_FCLK: + GET_DPM_CUR_FREQ(clk_table, clk_type, soft_min_level, min_freq); + GET_DPM_CUR_FREQ(clk_table, clk_type, soft_max_level, max_freq); + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq); + if (ret) + return ret; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq); + if (ret) + return ret; + break; + default: + break; + } + + return ret; +} + +static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +{ + int workload_type, ret; + uint32_t profile_mode = input[size]; + + if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { + pr_err("Invalid power profile mode %d\n", smu->power_profile_mode); + return -EINVAL; + } + + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ + workload_type = smu_workload_get_type(smu, smu->power_profile_mode); + if (workload_type < 0) { + pr_err("Unsupported power profile mode %d on RENOIR\n",smu->power_profile_mode); + return -EINVAL; + } + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, + 1 << workload_type); + if (ret) { + pr_err("Fail to set workload type %d\n", workload_type); + return ret; + } + + smu->power_profile_mode = profile_mode; + + return 0; +} + +static int renoir_set_peak_clock_by_device(struct smu_context *smu) +{ + int ret = 0; + uint32_t sclk_freq = 0, uclk_freq = 0; + + ret = smu_get_dpm_freq_range(smu, SMU_SCLK, NULL, &sclk_freq, false); + if (ret) + return ret; + + ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq); + if (ret) + return ret; + + ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &uclk_freq, false); + if (ret) + return ret; + + ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq); + if (ret) + return ret; + + return ret; +} + +static int renoir_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + int ret = 0; + uint32_t sclk_mask, mclk_mask, soc_mask; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + ret = smu_force_dpm_limit_value(smu, true); + break; + case AMD_DPM_FORCED_LEVEL_LOW: + ret = smu_force_dpm_limit_value(smu, false); + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + ret = smu_unforce_dpm_levels(smu); + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + ret = smu_get_profiling_clk_mask(smu, level, + &sclk_mask, + &mclk_mask, + &soc_mask); + if (ret) + return ret; + smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false); + smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false); + smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false); + break; + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + ret = renoir_set_peak_clock_by_device(smu); + break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: + default: + break; + } + return ret; +} + +/* save watermark settings into pplib smu structure, + * also pass data to smu controller + */ +static int renoir_set_watermarks_table( + struct smu_context *smu, + void *watermarks, + struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges) +{ + int i; + int ret = 0; + Watermarks_t *table = watermarks; + + if (!table || !clock_ranges) + return -EINVAL; + + if (clock_ranges->num_wm_dmif_sets > 4 || + clock_ranges->num_wm_mcif_sets > 4) + return -EINVAL; + + /* save into smu->smu_table.tables[SMU_TABLE_WATERMARKS]->cpu_addr*/ + for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { + table->WatermarkRow[WM_DCFCLK][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz)); + table->WatermarkRow[WM_DCFCLK][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz)); + table->WatermarkRow[WM_DCFCLK][i].MinMclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz)); + table->WatermarkRow[WM_DCFCLK][i].MaxMclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz)); + table->WatermarkRow[WM_DCFCLK][i].WmSetting = (uint8_t) + clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; + } + + for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { + table->WatermarkRow[WM_SOCCLK][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz)); + table->WatermarkRow[WM_SOCCLK][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz)); + table->WatermarkRow[WM_SOCCLK][i].MinMclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz)); + table->WatermarkRow[WM_SOCCLK][i].MaxMclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz)); + table->WatermarkRow[WM_SOCCLK][i].WmSetting = (uint8_t) + clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; + } + + /* pass data to smu controller */ + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_write_watermarks_table(smu); + if (ret) { + pr_err("Failed to update WMTABLE!"); + return ret; + } + smu->watermarks_bitmap |= WATERMARKS_LOADED; + } + + return 0; +} + +static int renoir_get_power_profile_mode(struct smu_context *smu, + char *buf) +{ + static const char *profile_name[] = { + "BOOTUP_DEFAULT", + "3D_FULL_SCREEN", + "POWER_SAVING", + "VIDEO", + "VR", + "COMPUTE", + "CUSTOM"}; + uint32_t i, size = 0; + int16_t workload_type = 0; + + if (!smu->pm_enabled || !buf) + return -EINVAL; + + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { + /* + * Conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT + * Not all profile modes are supported on arcturus. + */ + workload_type = smu_workload_get_type(smu, i); + if (workload_type < 0) + continue; + + size += sprintf(buf + size, "%2d %14s%s\n", + i, profile_name[i], (i == smu->power_profile_mode) ? "*" : " "); + } + + return size; +} + +static int renoir_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if (!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = renoir_get_current_activity_percent(smu, sensor, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_TEMP: + ret = renoir_get_gpu_temperature(smu, (uint32_t *)data); + *size = 4; + break; + default: + ret = smu_v12_0_read_sensor(smu, sensor, data, size); + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + +static const struct pptable_funcs renoir_ppt_funcs = { + .get_smu_msg_index = renoir_get_smu_msg_index, + .get_smu_clk_index = renoir_get_smu_clk_index, + .get_smu_table_index = renoir_get_smu_table_index, + .tables_init = renoir_tables_init, + .set_power_state = NULL, + .get_dpm_clk_limited = renoir_get_dpm_clk_limited, + .print_clk_levels = renoir_print_clk_levels, + .get_current_power_state = renoir_get_current_power_state, + .dpm_set_uvd_enable = renoir_dpm_set_uvd_enable, + .dpm_set_jpeg_enable = renoir_dpm_set_jpeg_enable, + .get_current_clk_freq_by_table = renoir_get_current_clk_freq_by_table, + .force_dpm_limit_value = renoir_force_dpm_limit_value, + .unforce_dpm_levels = renoir_unforce_dpm_levels, + .get_workload_type = renoir_get_workload_type, + .get_profiling_clk_mask = renoir_get_profiling_clk_mask, + .force_clk_levels = renoir_force_clk_levels, + .set_power_profile_mode = renoir_set_power_profile_mode, + .set_performance_level = renoir_set_performance_level, + .get_dpm_clock_table = renoir_get_dpm_clock_table, + .set_watermarks_table = renoir_set_watermarks_table, + .get_power_profile_mode = renoir_get_power_profile_mode, + .read_sensor = renoir_read_sensor, + .check_fw_status = smu_v12_0_check_fw_status, + .check_fw_version = smu_v12_0_check_fw_version, + .powergate_sdma = smu_v12_0_powergate_sdma, + .powergate_vcn = smu_v12_0_powergate_vcn, + .powergate_jpeg = smu_v12_0_powergate_jpeg, + .send_smc_msg_with_param = smu_v12_0_send_msg_with_param, + .read_smc_arg = smu_v12_0_read_arg, + .set_gfx_cgpg = smu_v12_0_set_gfx_cgpg, + .gfx_off_control = smu_v12_0_gfx_off_control, + .init_smc_tables = smu_v12_0_init_smc_tables, + .fini_smc_tables = smu_v12_0_fini_smc_tables, + .populate_smc_tables = smu_v12_0_populate_smc_tables, + .get_enabled_mask = smu_v12_0_get_enabled_mask, + .get_current_clk_freq = smu_v12_0_get_current_clk_freq, + .get_dpm_ultimate_freq = smu_v12_0_get_dpm_ultimate_freq, + .mode2_reset = smu_v12_0_mode2_reset, + .set_soft_freq_limited_range = smu_v12_0_set_soft_freq_limited_range, + .set_driver_table_location = smu_v12_0_set_driver_table_location, +}; + +void renoir_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &renoir_ppt_funcs; + smu->smc_if_version = SMU12_DRIVER_IF_VERSION; + smu->is_apu = true; +} diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.h b/drivers/gpu/drm/amd/powerplay/renoir_ppt.h new file mode 100644 index 000000000000..2a390ddd37dd --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.h @@ -0,0 +1,53 @@ +/* + * Copyright 2019 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 __RENOIR_PPT_H__ +#define __RENOIR_PPT_H__ + +extern void renoir_set_ppt_funcs(struct smu_context *smu); + +/* UMD PState Renoir Msg Parameters in MHz */ +#define RENOIR_UMD_PSTATE_GFXCLK 700 +#define RENOIR_UMD_PSTATE_SOCCLK 678 +#define RENOIR_UMD_PSTATE_FCLK 800 + +#define GET_DPM_CUR_FREQ(table, clk_type, dpm_level, freq) \ + do { \ + switch (clk_type) { \ + case SMU_SOCCLK: \ + freq = table->SocClocks[dpm_level].Freq; \ + break; \ + case SMU_MCLK: \ + freq = table->MemClocks[dpm_level].Freq; \ + break; \ + case SMU_DCEFCLK: \ + freq = table->DcfClocks[dpm_level].Freq; \ + break; \ + case SMU_FCLK: \ + freq = table->FClocks[dpm_level].Freq; \ + break; \ + default: \ + break; \ + } \ + } while (0) + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_internal.h b/drivers/gpu/drm/amd/powerplay/smu_internal.h new file mode 100644 index 000000000000..7bd200ffcda8 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smu_internal.h @@ -0,0 +1,213 @@ +/* + * Copyright 2019 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 __SMU_INTERNAL_H__ +#define __SMU_INTERNAL_H__ + +#include "amdgpu_smu.h" + +#define smu_init_microcode(smu) \ + ((smu)->ppt_funcs->init_microcode ? (smu)->ppt_funcs->init_microcode((smu)) : 0) +#define smu_init_smc_tables(smu) \ + ((smu)->ppt_funcs->init_smc_tables ? (smu)->ppt_funcs->init_smc_tables((smu)) : 0) +#define smu_fini_smc_tables(smu) \ + ((smu)->ppt_funcs->fini_smc_tables ? (smu)->ppt_funcs->fini_smc_tables((smu)) : 0) +#define smu_init_power(smu) \ + ((smu)->ppt_funcs->init_power ? (smu)->ppt_funcs->init_power((smu)) : 0) +#define smu_fini_power(smu) \ + ((smu)->ppt_funcs->fini_power ? (smu)->ppt_funcs->fini_power((smu)) : 0) + +#define smu_setup_pptable(smu) \ + ((smu)->ppt_funcs->setup_pptable ? (smu)->ppt_funcs->setup_pptable((smu)) : 0) +#define smu_powergate_sdma(smu, gate) \ + ((smu)->ppt_funcs->powergate_sdma ? (smu)->ppt_funcs->powergate_sdma((smu), (gate)) : 0) +#define smu_powergate_vcn(smu, gate) \ + ((smu)->ppt_funcs->powergate_vcn ? (smu)->ppt_funcs->powergate_vcn((smu), (gate)) : 0) +#define smu_powergate_jpeg(smu, gate) \ + ((smu)->ppt_funcs->powergate_jpeg ? (smu)->ppt_funcs->powergate_jpeg((smu), (gate)) : 0) + +#define smu_get_vbios_bootup_values(smu) \ + ((smu)->ppt_funcs->get_vbios_bootup_values ? (smu)->ppt_funcs->get_vbios_bootup_values((smu)) : 0) +#define smu_get_clk_info_from_vbios(smu) \ + ((smu)->ppt_funcs->get_clk_info_from_vbios ? (smu)->ppt_funcs->get_clk_info_from_vbios((smu)) : 0) +#define smu_check_pptable(smu) \ + ((smu)->ppt_funcs->check_pptable ? (smu)->ppt_funcs->check_pptable((smu)) : 0) +#define smu_parse_pptable(smu) \ + ((smu)->ppt_funcs->parse_pptable ? (smu)->ppt_funcs->parse_pptable((smu)) : 0) +#define smu_populate_smc_tables(smu) \ + ((smu)->ppt_funcs->populate_smc_tables ? (smu)->ppt_funcs->populate_smc_tables((smu)) : 0) +#define smu_check_fw_version(smu) \ + ((smu)->ppt_funcs->check_fw_version ? (smu)->ppt_funcs->check_fw_version((smu)) : 0) +#define smu_write_pptable(smu) \ + ((smu)->ppt_funcs->write_pptable ? (smu)->ppt_funcs->write_pptable((smu)) : 0) +#define smu_set_min_dcef_deep_sleep(smu) \ + ((smu)->ppt_funcs->set_min_dcef_deep_sleep ? (smu)->ppt_funcs->set_min_dcef_deep_sleep((smu)) : 0) +#define smu_set_driver_table_location(smu) \ + ((smu)->ppt_funcs->set_driver_table_location ? (smu)->ppt_funcs->set_driver_table_location((smu)) : 0) +#define smu_set_tool_table_location(smu) \ + ((smu)->ppt_funcs->set_tool_table_location ? (smu)->ppt_funcs->set_tool_table_location((smu)) : 0) +#define smu_notify_memory_pool_location(smu) \ + ((smu)->ppt_funcs->notify_memory_pool_location ? (smu)->ppt_funcs->notify_memory_pool_location((smu)) : 0) +#define smu_gfx_off_control(smu, enable) \ + ((smu)->ppt_funcs->gfx_off_control ? (smu)->ppt_funcs->gfx_off_control((smu), (enable)) : 0) + +#define smu_set_last_dcef_min_deep_sleep_clk(smu) \ + ((smu)->ppt_funcs->set_last_dcef_min_deep_sleep_clk ? (smu)->ppt_funcs->set_last_dcef_min_deep_sleep_clk((smu)) : 0) +#define smu_system_features_control(smu, en) \ + ((smu)->ppt_funcs->system_features_control ? (smu)->ppt_funcs->system_features_control((smu), (en)) : 0) +#define smu_init_max_sustainable_clocks(smu) \ + ((smu)->ppt_funcs->init_max_sustainable_clocks ? (smu)->ppt_funcs->init_max_sustainable_clocks((smu)) : 0) +#define smu_set_default_od_settings(smu, initialize) \ + ((smu)->ppt_funcs->set_default_od_settings ? (smu)->ppt_funcs->set_default_od_settings((smu), (initialize)) : 0) + +int smu_send_smc_msg(struct smu_context *smu, enum smu_message_type msg); + +#define smu_send_smc_msg_with_param(smu, msg, param) \ + ((smu)->ppt_funcs->send_smc_msg_with_param? (smu)->ppt_funcs->send_smc_msg_with_param((smu), (msg), (param)) : 0) +#define smu_read_smc_arg(smu, arg) \ + ((smu)->ppt_funcs->read_smc_arg? (smu)->ppt_funcs->read_smc_arg((smu), (arg)) : 0) +#define smu_alloc_dpm_context(smu) \ + ((smu)->ppt_funcs->alloc_dpm_context ? (smu)->ppt_funcs->alloc_dpm_context((smu)) : 0) +#define smu_init_display_count(smu, count) \ + ((smu)->ppt_funcs->init_display_count ? (smu)->ppt_funcs->init_display_count((smu), (count)) : 0) +#define smu_feature_set_allowed_mask(smu) \ + ((smu)->ppt_funcs->set_allowed_mask? (smu)->ppt_funcs->set_allowed_mask((smu)) : 0) +#define smu_feature_get_enabled_mask(smu, mask, num) \ + ((smu)->ppt_funcs->get_enabled_mask? (smu)->ppt_funcs->get_enabled_mask((smu), (mask), (num)) : 0) +#define smu_is_dpm_running(smu) \ + ((smu)->ppt_funcs->is_dpm_running ? (smu)->ppt_funcs->is_dpm_running((smu)) : 0) +#define smu_notify_display_change(smu) \ + ((smu)->ppt_funcs->notify_display_change? (smu)->ppt_funcs->notify_display_change((smu)) : 0) +#define smu_store_powerplay_table(smu) \ + ((smu)->ppt_funcs->store_powerplay_table ? (smu)->ppt_funcs->store_powerplay_table((smu)) : 0) +#define smu_check_powerplay_table(smu) \ + ((smu)->ppt_funcs->check_powerplay_table ? (smu)->ppt_funcs->check_powerplay_table((smu)) : 0) +#define smu_append_powerplay_table(smu) \ + ((smu)->ppt_funcs->append_powerplay_table ? (smu)->ppt_funcs->append_powerplay_table((smu)) : 0) +#define smu_set_default_dpm_table(smu) \ + ((smu)->ppt_funcs->set_default_dpm_table ? (smu)->ppt_funcs->set_default_dpm_table((smu)) : 0) +#define smu_populate_umd_state_clk(smu) \ + ((smu)->ppt_funcs->populate_umd_state_clk ? (smu)->ppt_funcs->populate_umd_state_clk((smu)) : 0) +#define smu_set_default_od8_settings(smu) \ + ((smu)->ppt_funcs->set_default_od8_settings ? (smu)->ppt_funcs->set_default_od8_settings((smu)) : 0) + +#define smu_get_current_clk_freq(smu, clk_id, value) \ + ((smu)->ppt_funcs->get_current_clk_freq? (smu)->ppt_funcs->get_current_clk_freq((smu), (clk_id), (value)) : 0) + +#define smu_tables_init(smu, tab) \ + ((smu)->ppt_funcs->tables_init ? (smu)->ppt_funcs->tables_init((smu), (tab)) : 0) +#define smu_set_thermal_fan_table(smu) \ + ((smu)->ppt_funcs->set_thermal_fan_table ? (smu)->ppt_funcs->set_thermal_fan_table((smu)) : 0) +#define smu_start_thermal_control(smu) \ + ((smu)->ppt_funcs->start_thermal_control? (smu)->ppt_funcs->start_thermal_control((smu)) : 0) +#define smu_stop_thermal_control(smu) \ + ((smu)->ppt_funcs->stop_thermal_control? (smu)->ppt_funcs->stop_thermal_control((smu)) : 0) + +#define smu_smc_read_sensor(smu, sensor, data, size) \ + ((smu)->ppt_funcs->read_sensor? (smu)->ppt_funcs->read_sensor((smu), (sensor), (data), (size)) : -EINVAL) + +#define smu_pre_display_config_changed(smu) \ + ((smu)->ppt_funcs->pre_display_config_changed ? (smu)->ppt_funcs->pre_display_config_changed((smu)) : 0) +#define smu_display_config_changed(smu) \ + ((smu)->ppt_funcs->display_config_changed ? (smu)->ppt_funcs->display_config_changed((smu)) : 0) +#define smu_apply_clocks_adjust_rules(smu) \ + ((smu)->ppt_funcs->apply_clocks_adjust_rules ? (smu)->ppt_funcs->apply_clocks_adjust_rules((smu)) : 0) +#define smu_notify_smc_display_config(smu) \ + ((smu)->ppt_funcs->notify_smc_display_config ? (smu)->ppt_funcs->notify_smc_display_config((smu)) : 0) +#define smu_force_dpm_limit_value(smu, highest) \ + ((smu)->ppt_funcs->force_dpm_limit_value ? (smu)->ppt_funcs->force_dpm_limit_value((smu), (highest)) : 0) +#define smu_unforce_dpm_levels(smu) \ + ((smu)->ppt_funcs->unforce_dpm_levels ? (smu)->ppt_funcs->unforce_dpm_levels((smu)) : 0) +#define smu_get_profiling_clk_mask(smu, level, sclk_mask, mclk_mask, soc_mask) \ + ((smu)->ppt_funcs->get_profiling_clk_mask ? (smu)->ppt_funcs->get_profiling_clk_mask((smu), (level), (sclk_mask), (mclk_mask), (soc_mask)) : 0) +#define smu_set_cpu_power_state(smu) \ + ((smu)->ppt_funcs->set_cpu_power_state ? (smu)->ppt_funcs->set_cpu_power_state((smu)) : 0) + +#define smu_msg_get_index(smu, msg) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_msg_index? (smu)->ppt_funcs->get_smu_msg_index((smu), (msg)) : -EINVAL) : -EINVAL) +#define smu_clk_get_index(smu, msg) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_clk_index? (smu)->ppt_funcs->get_smu_clk_index((smu), (msg)) : -EINVAL) : -EINVAL) +#define smu_feature_get_index(smu, msg) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_feature_index? (smu)->ppt_funcs->get_smu_feature_index((smu), (msg)) : -EINVAL) : -EINVAL) +#define smu_table_get_index(smu, tab) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_table_index? (smu)->ppt_funcs->get_smu_table_index((smu), (tab)) : -EINVAL) : -EINVAL) +#define smu_power_get_index(smu, src) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_smu_power_index? (smu)->ppt_funcs->get_smu_power_index((smu), (src)) : -EINVAL) : -EINVAL) +#define smu_workload_get_type(smu, profile) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_workload_type? (smu)->ppt_funcs->get_workload_type((smu), (profile)) : -EINVAL) : -EINVAL) +#define smu_run_btc(smu) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->run_btc? (smu)->ppt_funcs->run_btc((smu)) : 0) : 0) +#define smu_get_allowed_feature_mask(smu, feature_mask, num) \ + ((smu)->ppt_funcs? ((smu)->ppt_funcs->get_allowed_feature_mask? (smu)->ppt_funcs->get_allowed_feature_mask((smu), (feature_mask), (num)) : 0) : 0) + + +#define smu_store_cc6_data(smu, st, cc6_dis, pst_dis, pst_sw_dis) \ + ((smu)->ppt_funcs->store_cc6_data ? (smu)->ppt_funcs->store_cc6_data((smu), (st), (cc6_dis), (pst_dis), (pst_sw_dis)) : 0) + +#define smu_get_dal_power_level(smu, clocks) \ + ((smu)->ppt_funcs->get_dal_power_level ? (smu)->ppt_funcs->get_dal_power_level((smu), (clocks)) : 0) +#define smu_get_perf_level(smu, designation, level) \ + ((smu)->ppt_funcs->get_perf_level ? (smu)->ppt_funcs->get_perf_level((smu), (designation), (level)) : 0) +#define smu_get_current_shallow_sleep_clocks(smu, clocks) \ + ((smu)->ppt_funcs->get_current_shallow_sleep_clocks ? (smu)->ppt_funcs->get_current_shallow_sleep_clocks((smu), (clocks)) : 0) + +#define smu_dpm_set_uvd_enable(smu, enable) \ + ((smu)->ppt_funcs->dpm_set_uvd_enable ? (smu)->ppt_funcs->dpm_set_uvd_enable((smu), (enable)) : 0) +#define smu_dpm_set_vce_enable(smu, enable) \ + ((smu)->ppt_funcs->dpm_set_vce_enable ? (smu)->ppt_funcs->dpm_set_vce_enable((smu), (enable)) : 0) +#define smu_dpm_set_jpeg_enable(smu, enable) \ + ((smu)->ppt_funcs->dpm_set_jpeg_enable ? (smu)->ppt_funcs->dpm_set_jpeg_enable((smu), (enable)) : 0) + +#define smu_set_watermarks_table(smu, tab, clock_ranges) \ + ((smu)->ppt_funcs->set_watermarks_table ? (smu)->ppt_funcs->set_watermarks_table((smu), (tab), (clock_ranges)) : 0) +#define smu_get_current_clk_freq_by_table(smu, clk_type, value) \ + ((smu)->ppt_funcs->get_current_clk_freq_by_table ? (smu)->ppt_funcs->get_current_clk_freq_by_table((smu), (clk_type), (value)) : 0) +#define smu_thermal_temperature_range_update(smu, range, rw) \ + ((smu)->ppt_funcs->thermal_temperature_range_update? (smu)->ppt_funcs->thermal_temperature_range_update((smu), (range), (rw)) : 0) +#define smu_get_thermal_temperature_range(smu, range) \ + ((smu)->ppt_funcs->get_thermal_temperature_range? (smu)->ppt_funcs->get_thermal_temperature_range((smu), (range)) : 0) +#define smu_register_irq_handler(smu) \ + ((smu)->ppt_funcs->register_irq_handler ? (smu)->ppt_funcs->register_irq_handler(smu) : 0) + +#define smu_get_dpm_ultimate_freq(smu, param, min, max) \ + ((smu)->ppt_funcs->get_dpm_ultimate_freq ? (smu)->ppt_funcs->get_dpm_ultimate_freq((smu), (param), (min), (max)) : 0) + +#define smu_asic_set_performance_level(smu, level) \ + ((smu)->ppt_funcs->set_performance_level? (smu)->ppt_funcs->set_performance_level((smu), (level)) : -EINVAL); +#define smu_dump_pptable(smu) \ + ((smu)->ppt_funcs->dump_pptable ? (smu)->ppt_funcs->dump_pptable((smu)) : 0) +#define smu_get_dpm_clk_limited(smu, clk_type, dpm_level, freq) \ + ((smu)->ppt_funcs->get_dpm_clk_limited ? (smu)->ppt_funcs->get_dpm_clk_limited((smu), (clk_type), (dpm_level), (freq)) : -EINVAL) + +#define smu_set_soft_freq_limited_range(smu, clk_type, min, max) \ + ((smu)->ppt_funcs->set_soft_freq_limited_range ? (smu)->ppt_funcs->set_soft_freq_limited_range((smu), (clk_type), (min), (max)) : -EINVAL) + +#define smu_override_pcie_parameters(smu) \ + ((smu)->ppt_funcs->override_pcie_parameters ? (smu)->ppt_funcs->override_pcie_parameters((smu)) : 0) + +#define smu_update_pcie_parameters(smu, pcie_gen_cap, pcie_width_cap) \ + ((smu)->ppt_funcs->update_pcie_parameters ? (smu)->ppt_funcs->update_pcie_parameters((smu), (pcie_gen_cap), (pcie_width_cap)) : 0) + +#define smu_disable_umc_cdr_12gbps_workaround(smu) \ + ((smu)->ppt_funcs->disable_umc_cdr_12gbps_workaround ? (smu)->ppt_funcs->disable_umc_cdr_12gbps_workaround((smu)) : 0) + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c index 5fde5cf65b42..0dc49479a7eb 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c @@ -24,16 +24,20 @@ #include <linux/module.h> #include <linux/pci.h> +#define SMU_11_0_PARTIAL_PPTABLE + #include "pp_debug.h" #include "amdgpu.h" #include "amdgpu_smu.h" +#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" #include "smu_v11_0.h" +#include "smu_v11_0_pptable.h" #include "soc15_common.h" #include "atom.h" -#include "vega20_ppt.h" -#include "navi10_ppt.h" +#include "amd_pcie.h" +#include "amdgpu_ras.h" #include "asic_reg/thm/thm_11_0_2_offset.h" #include "asic_reg/thm/thm_11_0_2_sh_mask.h" @@ -45,7 +49,10 @@ #include "asic_reg/smuio/smuio_11_0_0_sh_mask.h" MODULE_FIRMWARE("amdgpu/vega20_smc.bin"); +MODULE_FIRMWARE("amdgpu/arcturus_smc.bin"); MODULE_FIRMWARE("amdgpu/navi10_smc.bin"); +MODULE_FIRMWARE("amdgpu/navi14_smc.bin"); +MODULE_FIRMWARE("amdgpu/navi12_smc.bin"); #define SMU11_VOLTAGE_SCALE 4 @@ -57,7 +64,7 @@ static int smu_v11_0_send_msg_without_waiting(struct smu_context *smu, return 0; } -static int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg) +int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg) { struct amdgpu_device *adev = smu->adev; @@ -73,47 +80,20 @@ static int smu_v11_0_wait_for_response(struct smu_context *smu) for (i = 0; i < timeout; i++) { cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0) - break; + return cur_value == 0x1 ? 0 : -EIO; + udelay(1); } /* timeout means wrong logic */ - if (i == timeout) - return -ETIME; - - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO; -} - -static int smu_v11_0_send_msg(struct smu_context *smu, uint16_t msg) -{ - struct amdgpu_device *adev = smu->adev; - int ret = 0, index = 0; - - index = smu_msg_get_index(smu, msg); - if (index < 0) - return index; - - smu_v11_0_wait_for_response(smu); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - smu_v11_0_send_msg_without_waiting(smu, (uint16_t)index); - - ret = smu_v11_0_wait_for_response(smu); - - if (ret) - pr_err("Failed to send message 0x%x, response 0x%x\n", index, - ret); - - return ret; - + return -ETIME; } -static int -smu_v11_0_send_msg_with_param(struct smu_context *smu, uint16_t msg, +int +smu_v11_0_send_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, uint32_t param) { - struct amdgpu_device *adev = smu->adev; int ret = 0, index = 0; @@ -122,9 +102,11 @@ smu_v11_0_send_msg_with_param(struct smu_context *smu, uint16_t msg, return index; ret = smu_v11_0_wait_for_response(smu); - if (ret) - pr_err("Failed to send message 0x%x, response 0x%x, param 0x%x\n", - index, ret, param); + if (ret) { + pr_err("Msg issuing pre-check failed and " + "SMU may be not in the right state!\n"); + return ret; + } WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); @@ -134,13 +116,13 @@ smu_v11_0_send_msg_with_param(struct smu_context *smu, uint16_t msg, ret = smu_v11_0_wait_for_response(smu); if (ret) - pr_err("Failed to send message 0x%x, response 0x%x param 0x%x\n", - index, ret, param); + pr_err("failed send message: %10s (%d) \tparam: 0x%08x response %#x\n", + smu_get_message_name(smu, msg), index, param, ret); return ret; } -static int smu_v11_0_init_microcode(struct smu_context *smu) +int smu_v11_0_init_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; const char *chip_name; @@ -154,9 +136,18 @@ static int smu_v11_0_init_microcode(struct smu_context *smu) case CHIP_VEGA20: chip_name = "vega20"; break; + case CHIP_ARCTURUS: + chip_name = "arcturus"; + break; case CHIP_NAVI10: chip_name = "navi10"; break; + case CHIP_NAVI14: + chip_name = "navi14"; + break; + case CHIP_NAVI12: + chip_name = "navi12"; + break; default: BUG(); } @@ -193,7 +184,7 @@ out: return err; } -static int smu_v11_0_load_microcode(struct smu_context *smu) +int smu_v11_0_load_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; const uint32_t *src; @@ -202,7 +193,7 @@ static int smu_v11_0_load_microcode(struct smu_context *smu) uint32_t i; uint32_t mp1_fw_flags; - hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; + hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; src = (const uint32_t *)(adev->pm.fw->data + le32_to_cpu(hdr->header.ucode_array_offset_bytes)); @@ -231,7 +222,7 @@ static int smu_v11_0_load_microcode(struct smu_context *smu) return 0; } -static int smu_v11_0_check_fw_status(struct smu_context *smu) +int smu_v11_0_check_fw_status(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; uint32_t mp1_fw_flags; @@ -246,7 +237,7 @@ static int smu_v11_0_check_fw_status(struct smu_context *smu) return -EIO; } -static int smu_v11_0_check_fw_version(struct smu_context *smu) +int smu_v11_0_check_fw_version(struct smu_context *smu) { uint32_t if_version = 0xff, smu_version = 0xff; uint16_t smu_major; @@ -261,6 +252,25 @@ static int smu_v11_0_check_fw_version(struct smu_context *smu) smu_minor = (smu_version >> 8) & 0xff; smu_debug = (smu_version >> 0) & 0xff; + switch (smu->adev->asic_type) { + case CHIP_VEGA20: + smu->smc_if_version = SMU11_DRIVER_IF_VERSION_VG20; + break; + case CHIP_ARCTURUS: + smu->smc_if_version = SMU11_DRIVER_IF_VERSION_ARCT; + break; + case CHIP_NAVI10: + smu->smc_if_version = SMU11_DRIVER_IF_VERSION_NV10; + break; + case CHIP_NAVI14: + smu->smc_if_version = SMU11_DRIVER_IF_VERSION_NV14; + break; + default: + pr_err("smu unsupported asic type:%d.\n", smu->adev->asic_type); + smu->smc_if_version = SMU11_DRIVER_IF_VERSION_INV; + break; + } + /* * 1. if_version mismatch is not critical as our fw is designed * to be backward compatible. @@ -295,7 +305,8 @@ static int smu_v11_0_set_pptable_v2_0(struct smu_context *smu, void **table, uin return 0; } -static int smu_v11_0_set_pptable_v2_1(struct smu_context *smu, void **table, uint32_t *size, uint32_t pptable_id) +static int smu_v11_0_set_pptable_v2_1(struct smu_context *smu, void **table, + uint32_t *size, uint32_t pptable_id) { struct amdgpu_device *adev = smu->adev; const struct smc_firmware_header_v2_1 *v2_1; @@ -321,12 +332,13 @@ static int smu_v11_0_set_pptable_v2_1(struct smu_context *smu, void **table, uin return 0; } -static int smu_v11_0_setup_pptable(struct smu_context *smu) +int smu_v11_0_setup_pptable(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; const struct smc_firmware_header_v1_0 *hdr; int ret, index; - uint32_t size; + uint32_t size = 0; + uint16_t atom_table_size; uint8_t frev, crev; void *table; uint16_t version_major, version_minor; @@ -335,6 +347,7 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu) version_major = le16_to_cpu(hdr->header.header_version_major); version_minor = le16_to_cpu(hdr->header.header_version_minor); if (version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) { + pr_info("use driver provided pptable %d\n", smu->smu_table.boot_values.pp_table_id); switch (version_minor) { case 0: ret = smu_v11_0_set_pptable_v2_0(smu, &table, &size); @@ -351,13 +364,15 @@ static int smu_v11_0_setup_pptable(struct smu_context *smu) return ret; } else { + pr_info("use vbios provided pptable\n"); index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, powerplayinfo); - ret = smu_get_atom_data_table(smu, index, (uint16_t *)&size, &frev, &crev, + ret = smu_get_atom_data_table(smu, index, &atom_table_size, &frev, &crev, (uint8_t **)&table); if (ret) return ret; + size = atom_table_size; } if (!smu->smu_table.power_play_table) @@ -398,13 +413,13 @@ static int smu_v11_0_fini_dpm_context(struct smu_context *smu) return 0; } -static int smu_v11_0_init_smc_tables(struct smu_context *smu) +int smu_v11_0_init_smc_tables(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *tables = NULL; int ret = 0; - if (smu_table->tables || smu_table->table_count == 0) + if (smu_table->tables) return -EINVAL; tables = kcalloc(SMU_TABLE_COUNT, sizeof(struct smu_table), @@ -425,19 +440,20 @@ static int smu_v11_0_init_smc_tables(struct smu_context *smu) return 0; } -static int smu_v11_0_fini_smc_tables(struct smu_context *smu) +int smu_v11_0_fini_smc_tables(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; int ret = 0; - if (!smu_table->tables || smu_table->table_count == 0) + if (!smu_table->tables) return -EINVAL; kfree(smu_table->tables); kfree(smu_table->metrics_table); + kfree(smu_table->watermarks_table); smu_table->tables = NULL; - smu_table->table_count = 0; smu_table->metrics_table = NULL; + smu_table->watermarks_table = NULL; smu_table->metrics_time = 0; ret = smu_v11_0_fini_dpm_context(smu); @@ -446,7 +462,7 @@ static int smu_v11_0_fini_smc_tables(struct smu_context *smu) return 0; } -static int smu_v11_0_init_power(struct smu_context *smu) +int smu_v11_0_init_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; @@ -464,7 +480,7 @@ static int smu_v11_0_init_power(struct smu_context *smu) return 0; } -static int smu_v11_0_fini_power(struct smu_context *smu) +int smu_v11_0_fini_power(struct smu_context *smu) { struct smu_power_context *smu_power = &smu->smu_power; @@ -535,10 +551,13 @@ int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.pp_table_id = v_3_3->pplib_pptable_id; } + smu->smu_table.boot_values.format_revision = header->format_revision; + smu->smu_table.boot_values.content_revision = header->content_revision; + return 0; } -static int smu_v11_0_get_clk_info_from_vbios(struct smu_context *smu) +int smu_v11_0_get_clk_info_from_vbios(struct smu_context *smu) { int ret, index; struct amdgpu_device *adev = smu->adev; @@ -614,10 +633,28 @@ static int smu_v11_0_get_clk_info_from_vbios(struct smu_context *smu) output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input; smu->smu_table.boot_values.dclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; + if ((smu->smu_table.boot_values.format_revision == 3) && + (smu->smu_table.boot_values.content_revision >= 2)) { + memset(&input, 0, sizeof(input)); + input.clk_id = SMU11_SYSPLL1_0_FCLK_ID; + input.syspll_id = SMU11_SYSPLL1_2_ID; + input.command = GET_SMU_CLOCK_INFO_V3_1_GET_CLOCK_FREQ; + index = get_index_into_master_table(atom_master_list_of_command_functions_v2_1, + getsmuclockinfo); + + ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index, + (uint32_t *)&input); + if (ret) + return -EINVAL; + + output = (struct atom_get_smu_clock_info_output_parameters_v3_1 *)&input; + smu->smu_table.boot_values.fclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; + } + return 0; } -static int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) +int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; struct smu_table *memory_pool = &smu_table->memory_pool; @@ -663,7 +700,7 @@ static int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) return ret; } -static int smu_v11_0_check_pptable(struct smu_context *smu) +int smu_v11_0_check_pptable(struct smu_context *smu) { int ret; @@ -671,7 +708,7 @@ static int smu_v11_0_check_pptable(struct smu_context *smu) return ret; } -static int smu_v11_0_parse_pptable(struct smu_context *smu) +int smu_v11_0_parse_pptable(struct smu_context *smu) { int ret; @@ -695,7 +732,7 @@ static int smu_v11_0_parse_pptable(struct smu_context *smu) return ret; } -static int smu_v11_0_populate_smc_pptable(struct smu_context *smu) +int smu_v11_0_populate_smc_pptable(struct smu_context *smu) { int ret; @@ -704,7 +741,7 @@ static int smu_v11_0_populate_smc_pptable(struct smu_context *smu) return ret; } -static int smu_v11_0_write_pptable(struct smu_context *smu) +int smu_v11_0_write_pptable(struct smu_context *smu) { struct smu_table_context *table_context = &smu->smu_table; int ret = 0; @@ -715,26 +752,7 @@ static int smu_v11_0_write_pptable(struct smu_context *smu) return ret; } -static int smu_v11_0_write_watermarks_table(struct smu_context *smu) -{ - int ret = 0; - struct smu_table_context *smu_table = &smu->smu_table; - struct smu_table *table = NULL; - - table = &smu_table->tables[SMU_TABLE_WATERMARKS]; - if (!table) - return -EINVAL; - - if (!table->cpu_addr) - return -EINVAL; - - ret = smu_update_table(smu, SMU_TABLE_WATERMARKS, 0, table->cpu_addr, - true); - - return ret; -} - -static int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) +int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) { int ret; @@ -746,7 +764,7 @@ static int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t cl return ret; } -static int smu_v11_0_set_min_dcef_deep_sleep(struct smu_context *smu) +int smu_v11_0_set_min_dcef_deep_sleep(struct smu_context *smu) { struct smu_table_context *table_context = &smu->smu_table; @@ -755,11 +773,28 @@ static int smu_v11_0_set_min_dcef_deep_sleep(struct smu_context *smu) if (!table_context) return -EINVAL; - return smu_set_deep_sleep_dcefclk(smu, - table_context->boot_values.dcefclk / 100); + return smu_v11_0_set_deep_sleep_dcefclk(smu, table_context->boot_values.dcefclk / 100); +} + +int smu_v11_0_set_driver_table_location(struct smu_context *smu) +{ + struct smu_table *driver_table = &smu->smu_table.driver_table; + int ret = 0; + + if (driver_table->mc_address) { + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrHigh, + upper_32_bits(driver_table->mc_address)); + if (!ret) + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrLow, + lower_32_bits(driver_table->mc_address)); + } + + return ret; } -static int smu_v11_0_set_tool_table_location(struct smu_context *smu) +int smu_v11_0_set_tool_table_location(struct smu_context *smu) { int ret = 0; struct smu_table *tool_table = &smu->smu_table.tables[SMU_TABLE_PMSTATUSLOG]; @@ -777,7 +812,7 @@ static int smu_v11_0_set_tool_table_location(struct smu_context *smu) return ret; } -static int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) +int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) { int ret = 0; @@ -788,46 +823,8 @@ static int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) return ret; } -static int smu_v11_0_update_feature_enable_state(struct smu_context *smu, uint32_t feature_id, bool enabled) -{ - uint32_t feature_low = 0, feature_high = 0; - int ret = 0; - - if (!smu->pm_enabled) - return ret; - if (feature_id >= 0 && feature_id < 31) - feature_low = (1 << feature_id); - else if (feature_id > 31 && feature_id < 63) - feature_high = (1 << feature_id); - else - return -EINVAL; - - if (enabled) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, - feature_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, - feature_high); - if (ret) - return ret; - - } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, - feature_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, - feature_high); - if (ret) - return ret; - - } - return ret; -} - -static int smu_v11_0_set_allowed_mask(struct smu_context *smu) +int smu_v11_0_set_allowed_mask(struct smu_context *smu) { struct smu_feature *feature = &smu->smu_feature; int ret = 0; @@ -854,62 +851,71 @@ failed: return ret; } -static int smu_v11_0_get_enabled_mask(struct smu_context *smu, +int smu_v11_0_get_enabled_mask(struct smu_context *smu, uint32_t *feature_mask, uint32_t num) { uint32_t feature_mask_high = 0, feature_mask_low = 0; + struct smu_feature *feature = &smu->smu_feature; int ret = 0; if (!feature_mask || num < 2) return -EINVAL; - ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh); - if (ret) - return ret; - ret = smu_read_smc_arg(smu, &feature_mask_high); - if (ret) - return ret; + if (bitmap_empty(feature->enabled, feature->feature_num)) { + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_high); + if (ret) + return ret; - ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow); - if (ret) - return ret; - ret = smu_read_smc_arg(smu, &feature_mask_low); - if (ret) - return ret; + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_low); + if (ret) + return ret; - feature_mask[0] = feature_mask_low; - feature_mask[1] = feature_mask_high; + feature_mask[0] = feature_mask_low; + feature_mask[1] = feature_mask_high; + } else { + bitmap_copy((unsigned long *)feature_mask, feature->enabled, + feature->feature_num); + } return ret; } -static int smu_v11_0_system_features_control(struct smu_context *smu, +int smu_v11_0_system_features_control(struct smu_context *smu, bool en) { struct smu_feature *feature = &smu->smu_feature; uint32_t feature_mask[2]; int ret = 0; - if (smu->pm_enabled) { - ret = smu_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : - SMU_MSG_DisableAllSmuFeatures)); - if (ret) - return ret; - } - - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + ret = smu_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : + SMU_MSG_DisableAllSmuFeatures)); if (ret) return ret; - bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, - feature->feature_num); - bitmap_copy(feature->supported, (unsigned long *)&feature_mask, - feature->feature_num); + if (en) { + ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + if (ret) + return ret; + + bitmap_copy(feature->enabled, (unsigned long *)&feature_mask, + feature->feature_num); + bitmap_copy(feature->supported, (unsigned long *)&feature_mask, + feature->feature_num); + } else { + bitmap_zero(feature->enabled, feature->feature_num); + bitmap_zero(feature->supported, feature->feature_num); + } return ret; } -static int smu_v11_0_notify_display_change(struct smu_context *smu) +int smu_v11_0_notify_display_change(struct smu_context *smu) { int ret = 0; @@ -927,11 +933,21 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, enum smu_clk_type clock_select) { int ret = 0; + int clk_id; if (!smu->pm_enabled) return ret; + + if ((smu_msg_get_index(smu, SMU_MSG_GetDcModeMaxDpmFreq) < 0) || + (smu_msg_get_index(smu, SMU_MSG_GetMaxDpmFreq) < 0)) + return 0; + + clk_id = smu_clk_get_index(smu, clock_select); + if (clk_id < 0) + return -EINVAL; + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq, - smu_clk_get_index(smu, clock_select) << 16); + clk_id << 16); if (ret) { pr_err("[GetMaxSustainableClock] Failed to get max DC clock from SMC!"); return ret; @@ -946,7 +962,7 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, /* if DC limit is zero, return AC limit */ ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, - smu_clk_get_index(smu, clock_select) << 16); + clk_id << 16); if (ret) { pr_err("[GetMaxSustainableClock] failed to get max AC clock from SMC!"); return ret; @@ -957,7 +973,7 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, return ret; } -static int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) +int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) { struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks; int ret = 0; @@ -1037,75 +1053,86 @@ static int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) return 0; } -static int smu_v11_0_get_power_limit(struct smu_context *smu, - uint32_t *limit, - bool get_default) -{ - int ret = 0; +uint32_t smu_v11_0_get_max_power_limit(struct smu_context *smu) { + uint32_t od_limit, max_power_limit; + struct smu_11_0_powerplay_table *powerplay_table = NULL; + struct smu_table_context *table_context = &smu->smu_table; + powerplay_table = table_context->power_play_table; - if (get_default) { - mutex_lock(&smu->mutex); - *limit = smu->default_power_limit; - if (smu->od_enabled) { - *limit *= (100 + smu->smu_table.TDPODLimit); - *limit /= 100; - } - mutex_unlock(&smu->mutex); - } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit, - smu_power_get_index(smu, SMU_POWER_SOURCE_AC) << 16); - if (ret) { - pr_err("[%s] get PPT limit failed!", __func__); - return ret; - } - smu_read_smc_arg(smu, limit); - smu->power_limit = *limit; + max_power_limit = smu_get_pptable_power_limit(smu); + + if (!max_power_limit) { + // If we couldn't get the table limit, fall back on first-read value + if (!smu->default_power_limit) + smu->default_power_limit = smu->power_limit; + max_power_limit = smu->default_power_limit; } - return ret; + if (smu->od_enabled) { + od_limit = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); + + pr_debug("ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_limit, smu->default_power_limit); + + max_power_limit *= (100 + od_limit); + max_power_limit /= 100; + } + + return max_power_limit; } -static int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n) +int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n) { - uint32_t max_power_limit; int ret = 0; + uint32_t max_power_limit; + + max_power_limit = smu_v11_0_get_max_power_limit(smu); + + if (n > max_power_limit) { + pr_err("New power limit (%d) is over the max allowed %d\n", + n, + max_power_limit); + return -EINVAL; + } if (n == 0) n = smu->default_power_limit; - max_power_limit = smu->default_power_limit; - - if (smu->od_enabled) { - max_power_limit *= (100 + smu->smu_table.TDPODLimit); - max_power_limit /= 100; + if (!smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { + pr_err("Setting new power limit is not supported!\n"); + return -EOPNOTSUPP; } - if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n); + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n); if (ret) { - pr_err("[%s] Set power limit Failed!", __func__); + pr_err("[%s] Set power limit Failed!\n", __func__); return ret; } + smu->power_limit = n; - return ret; + return 0; } -static int smu_v11_0_get_current_clk_freq(struct smu_context *smu, +int smu_v11_0_get_current_clk_freq(struct smu_context *smu, enum smu_clk_type clk_id, uint32_t *value) { int ret = 0; uint32_t freq = 0; + int asic_clk_id; if (clk_id >= SMU_CLK_COUNT || !value) return -EINVAL; + asic_clk_id = smu_clk_get_index(smu, clk_id); + if (asic_clk_id < 0) + return -EINVAL; + /* if don't has GetDpmClockFreq Message, try get current clock by SmuMetrics_t */ - if (smu_msg_get_index(smu, SMU_MSG_GetDpmClockFreq) == 0) + if (smu_msg_get_index(smu, SMU_MSG_GetDpmClockFreq) < 0) ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq); else { ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDpmClockFreq, - (smu_clk_get_index(smu, clk_id) << 16)); + (asic_clk_id << 16)); if (ret) return ret; @@ -1121,23 +1148,18 @@ static int smu_v11_0_get_current_clk_freq(struct smu_context *smu, } static int smu_v11_0_set_thermal_range(struct smu_context *smu, - struct smu_temperature_range *range) + struct smu_temperature_range range) { struct amdgpu_device *adev = smu->adev; int low = SMU_THERMAL_MINIMUM_ALERT_TEMP; int high = SMU_THERMAL_MAXIMUM_ALERT_TEMP; uint32_t val; + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_powerplay_table *powerplay_table = table_context->power_play_table; - if (!range) - return -EINVAL; - - if (low < range->min) - low = range->min; - if (high > range->max) - high = range->max; - - low = max(SMU_THERMAL_MINIMUM_ALERT_TEMP, range->min); - high = min(SMU_THERMAL_MAXIMUM_ALERT_TEMP, range->max); + low = max(SMU_THERMAL_MINIMUM_ALERT_TEMP, + range.min / SMU_TEMPERATURE_UNITS_PER_CENTIGRADES); + high = min((uint16_t)SMU_THERMAL_MAXIMUM_ALERT_TEMP, powerplay_table->software_shutdown_temp); if (low > high) return -EINVAL; @@ -1170,30 +1192,23 @@ static int smu_v11_0_enable_thermal_alert(struct smu_context *smu) return 0; } -static int smu_v11_0_start_thermal_control(struct smu_context *smu) +int smu_v11_0_start_thermal_control(struct smu_context *smu) { int ret = 0; - struct smu_temperature_range range = { - TEMP_RANGE_MIN, - TEMP_RANGE_MAX, - TEMP_RANGE_MAX, - TEMP_RANGE_MIN, - TEMP_RANGE_MAX, - TEMP_RANGE_MAX, - TEMP_RANGE_MIN, - TEMP_RANGE_MAX, - TEMP_RANGE_MAX}; + struct smu_temperature_range range; struct amdgpu_device *adev = smu->adev; if (!smu->pm_enabled) return ret; + memcpy(&range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range)); + ret = smu_get_thermal_temperature_range(smu, &range); if (ret) return ret; if (smu->smu_table.thermal_controller_type) { - ret = smu_v11_0_set_thermal_range(smu, &range); + ret = smu_v11_0_set_thermal_range(smu, range); if (ret) return ret; @@ -1206,21 +1221,28 @@ static int smu_v11_0_start_thermal_control(struct smu_context *smu) return ret; } - adev->pm.dpm.thermal.min_temp = range.min * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_temp = range.max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_edge_emergency_temp = range.edge_emergency_max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.min_hotspot_temp = range.hotspot_min * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_hotspot_crit_temp = range.hotspot_crit_max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_hotspot_emergency_temp = range.hotspot_emergency_max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.min_mem_temp = range.mem_min * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_mem_crit_temp = range.mem_crit_max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_mem_emergency_temp = range.mem_emergency_max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.min_temp = range.min * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - adev->pm.dpm.thermal.max_temp = range.max * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + adev->pm.dpm.thermal.min_temp = range.min; + adev->pm.dpm.thermal.max_temp = range.max; + adev->pm.dpm.thermal.max_edge_emergency_temp = range.edge_emergency_max; + adev->pm.dpm.thermal.min_hotspot_temp = range.hotspot_min; + adev->pm.dpm.thermal.max_hotspot_crit_temp = range.hotspot_crit_max; + adev->pm.dpm.thermal.max_hotspot_emergency_temp = range.hotspot_emergency_max; + adev->pm.dpm.thermal.min_mem_temp = range.mem_min; + adev->pm.dpm.thermal.max_mem_crit_temp = range.mem_crit_max; + adev->pm.dpm.thermal.max_mem_emergency_temp = range.mem_emergency_max; return ret; } +int smu_v11_0_stop_thermal_control(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0); + + return 0; +} + static uint16_t convert_to_vddc(uint8_t vid) { return (uint16_t) ((6200 - (vid * 25)) / SMU11_VOLTAGE_SCALE); @@ -1245,11 +1267,15 @@ static int smu_v11_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) } -static int smu_v11_0_read_sensor(struct smu_context *smu, +int smu_v11_0_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size) { int ret = 0; + + if(!data || !size) + return -EINVAL; + switch (sensor) { case AMDGPU_PP_SENSOR_GFX_MCLK: ret = smu_get_current_clk_freq(smu, SMU_UCLK, (uint32_t *)data); @@ -1272,17 +1298,13 @@ static int smu_v11_0_read_sensor(struct smu_context *smu, break; } - /* try get sensor data by asic */ - if (ret) - ret = smu_asic_read_sensor(smu, sensor, data, size); - if (ret) *size = 0; return ret; } -static int +int smu_v11_0_display_clock_voltage_request(struct smu_context *smu, struct pp_display_clock_request *clock_req) @@ -1322,37 +1344,20 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, if (ret) goto failed; - mutex_lock(&smu->mutex); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq, - (smu_clk_get_index(smu, clk_select) << 16) | clk_freq); - mutex_unlock(&smu->mutex); - } + if (clk_select == SMU_UCLK && smu->disable_uclk_switch) + return 0; -failed: - return ret; -} + ret = smu_set_hard_freq_range(smu, clk_select, clk_freq, 0); -static int -smu_v11_0_set_watermarks_for_clock_ranges(struct smu_context *smu, struct - dm_pp_wm_sets_with_clock_ranges_soc15 - *clock_ranges) -{ - int ret = 0; - struct smu_table *watermarks = &smu->smu_table.tables[SMU_TABLE_WATERMARKS]; - void *table = watermarks->cpu_addr; - - if (!smu->disable_watermark && - smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && - smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { - smu_set_watermarks_table(smu, table, clock_ranges); - smu->watermarks_bitmap |= WATERMARKS_EXIST; - smu->watermarks_bitmap &= ~WATERMARKS_LOADED; + if(clk_select == SMU_UCLK) + smu->hard_min_uclk_req_from_dal = clk_freq; } +failed: return ret; } -static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) +int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) { int ret = 0; struct amdgpu_device *adev = smu->adev; @@ -1361,14 +1366,14 @@ static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) case CHIP_VEGA20: break; case CHIP_NAVI10: + case CHIP_NAVI14: + case CHIP_NAVI12: if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; - mutex_lock(&smu->mutex); if (enable) ret = smu_send_smc_msg(smu, SMU_MSG_AllowGfxOff); else ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff); - mutex_unlock(&smu->mutex); break; default: break; @@ -1377,7 +1382,7 @@ static int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) return ret; } -static uint32_t +uint32_t smu_v11_0_get_fan_control_mode(struct smu_context *smu) { if (!smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) @@ -1387,17 +1392,17 @@ smu_v11_0_get_fan_control_mode(struct smu_context *smu) } static int -smu_v11_0_smc_fan_control(struct smu_context *smu, bool start) +smu_v11_0_auto_fan_control(struct smu_context *smu, bool auto_fan_control) { int ret = 0; if (!smu_feature_is_supported(smu, SMU_FEATURE_FAN_CONTROL_BIT)) return 0; - ret = smu_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, start); + ret = smu_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, auto_fan_control); if (ret) pr_err("[%s]%s smc FAN CONTROL feature failed!", - __func__, (start ? "Start" : "Stop")); + __func__, (auto_fan_control ? "Start" : "Stop")); return ret; } @@ -1417,20 +1422,19 @@ smu_v11_0_set_fan_static_mode(struct smu_context *smu, uint32_t mode) return 0; } -static int +int smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) { struct amdgpu_device *adev = smu->adev; - uint32_t duty100; - uint32_t duty; + uint32_t duty100, duty; uint64_t tmp64; - bool stop = 0; if (speed > 100) speed = 100; - if (smu_v11_0_smc_fan_control(smu, stop)) + if (smu_v11_0_auto_fan_control(smu, 0)) return -EINVAL; + duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1), CG_FDO_CTRL1, FMAX_DUTY100); if (!duty100) @@ -1447,23 +1451,21 @@ smu_v11_0_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) return smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC); } -static int +int smu_v11_0_set_fan_control_mode(struct smu_context *smu, uint32_t mode) { int ret = 0; - bool start = 1; - bool stop = 0; switch (mode) { case AMD_FAN_CTRL_NONE: ret = smu_v11_0_set_fan_speed_percent(smu, 100); break; case AMD_FAN_CTRL_MANUAL: - ret = smu_v11_0_smc_fan_control(smu, stop); + ret = smu_v11_0_auto_fan_control(smu, 0); break; case AMD_FAN_CTRL_AUTO: - ret = smu_v11_0_smc_fan_control(smu, start); + ret = smu_v11_0_auto_fan_control(smu, 1); break; default: break; @@ -1477,21 +1479,19 @@ smu_v11_0_set_fan_control_mode(struct smu_context *smu, return ret; } -static int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, +int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) { struct amdgpu_device *adev = smu->adev; int ret; uint32_t tach_period, crystal_clock_freq; - bool stop = 0; if (!speed) return -EINVAL; - mutex_lock(&(smu->mutex)); - ret = smu_v11_0_smc_fan_control(smu, stop); + ret = smu_v11_0_auto_fan_control(smu, 0); if (ret) - goto set_fan_speed_rpm_failed; + return ret; crystal_clock_freq = amdgpu_asic_get_xclk(adev); tach_period = 60 * crystal_clock_freq * 10000 / (8 * speed); @@ -1502,23 +1502,16 @@ static int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu, ret = smu_v11_0_set_fan_static_mode(smu, FDO_PWM_MODE_STATIC_RPM); -set_fan_speed_rpm_failed: - mutex_unlock(&(smu->mutex)); return ret; } -#define XGMI_STATE_D0 1 -#define XGMI_STATE_D3 0 - -static int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, +int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, uint32_t pstate) { int ret = 0; - mutex_lock(&(smu->mutex)); ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetXgmiMode, - pstate ? XGMI_STATE_D0 : XGMI_STATE_D3); - mutex_unlock(&(smu->mutex)); + pstate ? XGMI_MODE_PSTATE_D0 : XGMI_MODE_PSTATE_D3); return ret; } @@ -1565,7 +1558,7 @@ static const struct amdgpu_irq_src_funcs smu_v11_0_irq_funcs = .process = smu_v11_0_irq_process, }; -static int smu_v11_0_register_irq_handler(struct smu_context *smu) +int smu_v11_0_register_irq_handler(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; struct amdgpu_irq_src *irq_src = smu->irq_source; @@ -1597,7 +1590,7 @@ static int smu_v11_0_register_irq_handler(struct smu_context *smu) return ret; } -static int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, +int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks) { struct smu_table_context *table_context = &smu->smu_table; @@ -1627,13 +1620,11 @@ static int smu_v11_0_get_max_sustainable_clocks_by_dc(struct smu_context *smu, return 0; } -static int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu) +int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu) { int ret = 0; - mutex_lock(&smu->mutex); ret = smu_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME); - mutex_unlock(&smu->mutex); return ret; } @@ -1643,7 +1634,7 @@ static int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_v return smu_send_smc_msg_with_param(smu, SMU_MSG_ArmD3, baco_seq); } -static bool smu_v11_0_baco_is_support(struct smu_context *smu) +bool smu_v11_0_baco_is_support(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; struct smu_baco_context *smu_baco = &smu->smu_baco; @@ -1657,7 +1648,9 @@ static bool smu_v11_0_baco_is_support(struct smu_context *smu) if (!baco_support) return false; - if (!smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) + /* Arcturus does not support this bit mask */ + if (smu_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && + !smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) return false; val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); @@ -1667,10 +1660,10 @@ static bool smu_v11_0_baco_is_support(struct smu_context *smu) return false; } -static enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu) +enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu) { struct smu_baco_context *smu_baco = &smu->smu_baco; - enum smu_baco_state baco_state = SMU_BACO_STATE_EXIT; + enum smu_baco_state baco_state; mutex_lock(&smu_baco->mutex); baco_state = smu_baco->state; @@ -1679,10 +1672,14 @@ static enum smu_baco_state smu_v11_0_baco_get_state(struct smu_context *smu) return baco_state; } -static int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) +int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) { struct smu_baco_context *smu_baco = &smu->smu_baco; + struct amdgpu_device *adev = smu->adev; + struct amdgpu_ras *ras = amdgpu_ras_get_context(adev); + uint32_t bif_doorbell_intr_cntl; + uint32_t data; int ret = 0; if (smu_v11_0_baco_get_state(smu) == state) @@ -1690,10 +1687,37 @@ static int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state mutex_lock(&smu_baco->mutex); - if (state == SMU_BACO_STATE_ENTER) - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, BACO_SEQ_BACO); - else + bif_doorbell_intr_cntl = RREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL); + + if (state == SMU_BACO_STATE_ENTER) { + bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl, + BIF_DOORBELL_INT_CNTL, + DOORBELL_INTERRUPT_DISABLE, 1); + WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); + + if (!ras || !ras->supported) { + data = RREG32_SOC15(THM, 0, mmTHM_BACO_CNTL); + data |= 0x80000000; + WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 0); + } else { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 1); + } + } else { ret = smu_send_smc_msg(smu, SMU_MSG_ExitBaco); + if (ret) + goto out; + + bif_doorbell_intr_cntl = REG_SET_FIELD(bif_doorbell_intr_cntl, + BIF_DOORBELL_INT_CNTL, + DOORBELL_INTERRUPT_DISABLE, 0); + WREG32_SOC15(NBIO, 0, mmBIF_DOORBELL_INT_CNTL, bif_doorbell_intr_cntl); + + /* clear vbios scratch 6 and 7 for coming asic reinit */ + WREG32(adev->bios_scratch_reg_offset + 6, 0); + WREG32(adev->bios_scratch_reg_offset + 7, 0); + } if (ret) goto out; @@ -1703,13 +1727,17 @@ out: return ret; } -static int smu_v11_0_baco_reset(struct smu_context *smu) +int smu_v11_0_baco_enter(struct smu_context *smu) { + struct amdgpu_device *adev = smu->adev; int ret = 0; - ret = smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO); - if (ret) - return ret; + /* Arcturus does not need this audio workaround */ + if (adev->asic_type != CHIP_ARCTURUS) { + ret = smu_v11_0_baco_set_armd3_sequence(smu, BACO_SEQ_BACO); + if (ret) + return ret; + } ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_ENTER); if (ret) @@ -1717,6 +1745,13 @@ static int smu_v11_0_baco_reset(struct smu_context *smu) msleep(10); + return ret; +} + +int smu_v11_0_baco_exit(struct smu_context *smu) +{ + int ret = 0; + ret = smu_v11_0_baco_set_state(smu, SMU_BACO_STATE_EXIT); if (ret) return ret; @@ -1724,72 +1759,179 @@ static int smu_v11_0_baco_reset(struct smu_context *smu) return ret; } -static const struct smu_funcs smu_v11_0_funcs = { - .init_microcode = smu_v11_0_init_microcode, - .load_microcode = smu_v11_0_load_microcode, - .check_fw_status = smu_v11_0_check_fw_status, - .check_fw_version = smu_v11_0_check_fw_version, - .send_smc_msg = smu_v11_0_send_msg, - .send_smc_msg_with_param = smu_v11_0_send_msg_with_param, - .read_smc_arg = smu_v11_0_read_arg, - .setup_pptable = smu_v11_0_setup_pptable, - .init_smc_tables = smu_v11_0_init_smc_tables, - .fini_smc_tables = smu_v11_0_fini_smc_tables, - .init_power = smu_v11_0_init_power, - .fini_power = smu_v11_0_fini_power, - .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, - .get_clk_info_from_vbios = smu_v11_0_get_clk_info_from_vbios, - .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, - .check_pptable = smu_v11_0_check_pptable, - .parse_pptable = smu_v11_0_parse_pptable, - .populate_smc_pptable = smu_v11_0_populate_smc_pptable, - .write_pptable = smu_v11_0_write_pptable, - .write_watermarks_table = smu_v11_0_write_watermarks_table, - .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep, - .set_tool_table_location = smu_v11_0_set_tool_table_location, - .init_display_count = smu_v11_0_init_display_count, - .set_allowed_mask = smu_v11_0_set_allowed_mask, - .get_enabled_mask = smu_v11_0_get_enabled_mask, - .system_features_control = smu_v11_0_system_features_control, - .update_feature_enable_state = smu_v11_0_update_feature_enable_state, - .notify_display_change = smu_v11_0_notify_display_change, - .get_power_limit = smu_v11_0_get_power_limit, - .set_power_limit = smu_v11_0_set_power_limit, - .get_current_clk_freq = smu_v11_0_get_current_clk_freq, - .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, - .start_thermal_control = smu_v11_0_start_thermal_control, - .read_sensor = smu_v11_0_read_sensor, - .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk, - .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, - .set_watermarks_for_clock_ranges = smu_v11_0_set_watermarks_for_clock_ranges, - .get_fan_control_mode = smu_v11_0_get_fan_control_mode, - .set_fan_control_mode = smu_v11_0_set_fan_control_mode, - .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, - .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, - .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, - .gfx_off_control = smu_v11_0_gfx_off_control, - .register_irq_handler = smu_v11_0_register_irq_handler, - .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, - .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, - .baco_is_support = smu_v11_0_baco_is_support, - .baco_get_state = smu_v11_0_baco_get_state, - .baco_set_state = smu_v11_0_baco_set_state, - .baco_reset = smu_v11_0_baco_reset, -}; +int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + int ret = 0, clk_id = 0; + uint32_t param = 0; -void smu_v11_0_set_smu_funcs(struct smu_context *smu) + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) { + ret = -EINVAL; + goto failed; + } + param = (clk_id & 0xffff) << 16; + + if (max) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, param); + if (ret) + goto failed; + ret = smu_read_smc_arg(smu, max); + if (ret) + goto failed; + } + + if (min) { + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param); + if (ret) + goto failed; + ret = smu_read_smc_arg(smu, min); + if (ret) + goto failed; + } + +failed: + return ret; +} + +int smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t min, uint32_t max) +{ + int ret = 0, clk_id = 0; + uint32_t param; + + clk_id = smu_clk_get_index(smu, clk_type); + if (clk_id < 0) + return clk_id; + + if (max > 0) { + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, + param); + if (ret) + return ret; + } + + if (min > 0) { + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, + param); + if (ret) + return ret; + } + + return ret; +} + +int smu_v11_0_override_pcie_parameters(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + uint32_t pcie_gen = 0, pcie_width = 0; + int ret; - smu->funcs = &smu_v11_0_funcs; - switch (adev->asic_type) { - case CHIP_VEGA20: - vega20_set_ppt_funcs(smu); + if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN4) + pcie_gen = 3; + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3) + pcie_gen = 2; + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN2) + pcie_gen = 1; + else if (adev->pm.pcie_gen_mask & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN1) + pcie_gen = 0; + + /* Bit 31:16: LCLK DPM level. 0 is DPM0, and 1 is DPM1 + * Bit 15:8: PCIE GEN, 0 to 3 corresponds to GEN1 to GEN4 + * Bit 7:0: PCIE lane width, 1 to 7 corresponds is x1 to x32 + */ + if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X16) + pcie_width = 6; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X12) + pcie_width = 5; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X8) + pcie_width = 4; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X4) + pcie_width = 3; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X2) + pcie_width = 2; + else if (adev->pm.pcie_mlw_mask & CAIL_PCIE_LINK_WIDTH_SUPPORT_X1) + pcie_width = 1; + + ret = smu_update_pcie_parameters(smu, pcie_gen, pcie_width); + + if (ret) + pr_err("[%s] Attempt to override pcie params failed!\n", __func__); + + return ret; + +} + +int smu_v11_0_set_default_od_settings(struct smu_context *smu, bool initialize, size_t overdrive_table_size) +{ + struct smu_table_context *table_context = &smu->smu_table; + int ret = 0; + + if (initialize) { + if (table_context->overdrive_table) { + return -EINVAL; + } + table_context->overdrive_table = kzalloc(overdrive_table_size, GFP_KERNEL); + if (!table_context->overdrive_table) { + return -ENOMEM; + } + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, false); + if (ret) { + pr_err("Failed to export overdrive table!\n"); + return ret; + } + if (!table_context->boot_overdrive_table) { + table_context->boot_overdrive_table = kmemdup(table_context->overdrive_table, overdrive_table_size, GFP_KERNEL); + if (!table_context->boot_overdrive_table) { + return -ENOMEM; + } + } + } + ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, true); + if (ret) { + pr_err("Failed to import overdrive table!\n"); + return ret; + } + return ret; +} + +int smu_v11_0_set_performance_level(struct smu_context *smu, + enum amd_dpm_forced_level level) +{ + int ret = 0; + uint32_t sclk_mask, mclk_mask, soc_mask; + + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + ret = smu_force_dpm_limit_value(smu, true); break; - case CHIP_NAVI10: - navi10_set_ppt_funcs(smu); + case AMD_DPM_FORCED_LEVEL_LOW: + ret = smu_force_dpm_limit_value(smu, false); + break; + case AMD_DPM_FORCED_LEVEL_AUTO: + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + ret = smu_unforce_dpm_levels(smu); break; + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + ret = smu_get_profiling_clk_mask(smu, level, + &sclk_mask, + &mclk_mask, + &soc_mask); + if (ret) + return ret; + smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false); + smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false); + smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false); + break; + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: default: - pr_warn("Unknown asic for smu11\n"); + break; } + return ret; } + diff --git a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c new file mode 100644 index 000000000000..870e6db2907e --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c @@ -0,0 +1,526 @@ +/* + * Copyright 2019 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 "pp_debug.h" +#include <linux/firmware.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_internal.h" +#include "atomfirmware.h" +#include "amdgpu_atomfirmware.h" +#include "smu_v12_0.h" +#include "soc15_common.h" +#include "atom.h" + +#include "asic_reg/mp/mp_12_0_0_offset.h" +#include "asic_reg/mp/mp_12_0_0_sh_mask.h" + +#define smnMP1_FIRMWARE_FLAGS 0x3010024 + +#define mmSMUIO_GFX_MISC_CNTL 0x00c8 +#define mmSMUIO_GFX_MISC_CNTL_BASE_IDX 0 +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK 0x00000006L +#define SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT 0x1 + +int smu_v12_0_send_msg_without_waiting(struct smu_context *smu, + uint16_t msg) +{ + struct amdgpu_device *adev = smu->adev; + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + return 0; +} + +int smu_v12_0_read_arg(struct smu_context *smu, uint32_t *arg) +{ + struct amdgpu_device *adev = smu->adev; + + *arg = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); + return 0; +} + +int smu_v12_0_wait_for_response(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t cur_value, i; + + for (i = 0; i < adev->usec_timeout; i++) { + cur_value = RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); + if ((cur_value & MP1_C2PMSG_90__CONTENT_MASK) != 0) + return cur_value == 0x1 ? 0 : -EIO; + + udelay(1); + } + + /* timeout means wrong logic */ + return -ETIME; +} + +int +smu_v12_0_send_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0, index = 0; + + index = smu_msg_get_index(smu, msg); + if (index < 0) + return index; + + ret = smu_v12_0_wait_for_response(smu); + if (ret) { + pr_err("Msg issuing pre-check failed and " + "SMU may be not in the right state!\n"); + return ret; + } + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, param); + + smu_v12_0_send_msg_without_waiting(smu, (uint16_t)index); + + ret = smu_v12_0_wait_for_response(smu); + if (ret) + pr_err("Failed to send message 0x%x, response 0x%x param 0x%x\n", + index, ret, param); + + return ret; +} + +int smu_v12_0_check_fw_status(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t mp1_fw_flags; + + mp1_fw_flags = RREG32_PCIE(MP1_Public | + (smnMP1_FIRMWARE_FLAGS & 0xffffffff)); + + if ((mp1_fw_flags & MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED_MASK) >> + MP1_FIRMWARE_FLAGS__INTERRUPTS_ENABLED__SHIFT) + return 0; + + return -EIO; +} + +int smu_v12_0_check_fw_version(struct smu_context *smu) +{ + uint32_t if_version = 0xff, smu_version = 0xff; + uint16_t smu_major; + uint8_t smu_minor, smu_debug; + int ret = 0; + + ret = smu_get_smc_version(smu, &if_version, &smu_version); + if (ret) + return ret; + + smu_major = (smu_version >> 16) & 0xffff; + smu_minor = (smu_version >> 8) & 0xff; + smu_debug = (smu_version >> 0) & 0xff; + + /* + * 1. if_version mismatch is not critical as our fw is designed + * to be backward compatible. + * 2. New fw usually brings some optimizations. But that's visible + * only on the paired driver. + * Considering above, we just leave user a warning message instead + * of halt driver loading. + */ + if (if_version != smu->smc_if_version) { + pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + "smu fw version = 0x%08x (%d.%d.%d)\n", + smu->smc_if_version, if_version, + smu_version, smu_major, smu_minor, smu_debug); + pr_warn("SMU driver if version not matched\n"); + } + + return ret; +} + +int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate) +{ + if (!smu->is_apu) + return 0; + + if (gate) + return smu_send_smc_msg(smu, SMU_MSG_PowerDownSdma); + else + return smu_send_smc_msg(smu, SMU_MSG_PowerUpSdma); +} + +int smu_v12_0_powergate_vcn(struct smu_context *smu, bool gate) +{ + if (!smu->is_apu) + return 0; + + if (gate) + return smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn); + else + return smu_send_smc_msg(smu, SMU_MSG_PowerUpVcn); +} + +int smu_v12_0_powergate_jpeg(struct smu_context *smu, bool gate) +{ + if (!smu->is_apu) + return 0; + + if (gate) + return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0); + else + return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0); +} + +int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable) +{ + if (!(smu->adev->pg_flags & AMD_PG_SUPPORT_GFX_PG)) + return 0; + + return smu_v12_0_send_msg_with_param(smu, + SMU_MSG_SetGfxCGPG, enable ? 1 : 0); +} + +int smu_v12_0_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + + if(!data || !size) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = smu_get_current_clk_freq(smu, SMU_UCLK, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_MIN_FAN_RPM: + *(uint32_t *)data = 0; + *size = 4; + break; + default: + ret = smu_common_read_sensor(smu, sensor, data, size); + break; + } + + if (ret) + *size = 0; + + return ret; +} + +/** + * smu_v12_0_get_gfxoff_status - get gfxoff status + * + * @smu: amdgpu_device pointer + * + * This function will be used to get gfxoff status + * + * Returns 0=GFXOFF(default). + * Returns 1=Transition out of GFX State. + * Returns 2=Not in GFXOFF. + * Returns 3=Transition into GFXOFF. + */ +uint32_t smu_v12_0_get_gfxoff_status(struct smu_context *smu) +{ + uint32_t reg; + uint32_t gfxOff_Status = 0; + struct amdgpu_device *adev = smu->adev; + + reg = RREG32_SOC15(SMUIO, 0, mmSMUIO_GFX_MISC_CNTL); + gfxOff_Status = (reg & SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS_MASK) + >> SMUIO_GFX_MISC_CNTL__PWR_GFXOFF_STATUS__SHIFT; + + return gfxOff_Status; +} + +int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable) +{ + int ret = 0, timeout = 500; + + if (enable) { + ret = smu_send_smc_msg(smu, SMU_MSG_AllowGfxOff); + + } else { + ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff); + + /* confirm gfx is back to "on" state, timeout is 0.5 second */ + while (!(smu_v12_0_get_gfxoff_status(smu) == 2)) { + msleep(1); + timeout--; + if (timeout == 0) { + DRM_ERROR("disable gfxoff timeout and failed!\n"); + break; + } + } + } + + return ret; +} + +int smu_v12_0_init_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = NULL; + + if (smu_table->tables) + return -EINVAL; + + tables = kcalloc(SMU_TABLE_COUNT, sizeof(struct smu_table), + GFP_KERNEL); + if (!tables) + return -ENOMEM; + + smu_table->tables = tables; + + return smu_tables_init(smu, tables); +} + +int smu_v12_0_fini_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + if (!smu_table->tables) + return -EINVAL; + + kfree(smu_table->clocks_table); + kfree(smu_table->tables); + + smu_table->clocks_table = NULL; + smu_table->tables = NULL; + + return 0; +} + +int smu_v12_0_populate_smc_tables(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + + return smu_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); +} + +int smu_v12_0_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num) +{ + uint32_t feature_mask_high = 0, feature_mask_low = 0; + int ret = 0; + + if (!feature_mask || num < 2) + return -EINVAL; + + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_high); + if (ret) + return ret; + + ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow); + if (ret) + return ret; + ret = smu_read_smc_arg(smu, &feature_mask_low); + if (ret) + return ret; + + feature_mask[0] = feature_mask_low; + feature_mask[1] = feature_mask_high; + + return ret; +} + +int smu_v12_0_get_current_clk_freq(struct smu_context *smu, + enum smu_clk_type clk_id, + uint32_t *value) +{ + int ret = 0; + uint32_t freq = 0; + + if (clk_id >= SMU_CLK_COUNT || !value) + return -EINVAL; + + ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq); + if (ret) + return ret; + + freq *= 100; + *value = freq; + + return ret; +} + +int smu_v12_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + int ret = 0; + uint32_t mclk_mask, soc_mask; + + if (max) { + ret = smu_get_profiling_clk_mask(smu, AMD_DPM_FORCED_LEVEL_PROFILE_PEAK, + NULL, + &mclk_mask, + &soc_mask); + if (ret) + goto failed; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + ret = smu_send_smc_msg(smu, SMU_MSG_GetMaxGfxclkFrequency); + if (ret) { + pr_err("Attempt to get max GX frequency from SMC Failed !\n"); + goto failed; + } + ret = smu_read_smc_arg(smu, max); + if (ret) + goto failed; + break; + case SMU_UCLK: + case SMU_FCLK: + case SMU_MCLK: + ret = smu_get_dpm_clk_limited(smu, clk_type, mclk_mask, max); + if (ret) + goto failed; + break; + case SMU_SOCCLK: + ret = smu_get_dpm_clk_limited(smu, clk_type, soc_mask, max); + if (ret) + goto failed; + break; + default: + ret = -EINVAL; + goto failed; + } + } + + if (min) { + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + ret = smu_send_smc_msg(smu, SMU_MSG_GetMinGfxclkFrequency); + if (ret) { + pr_err("Attempt to get min GX frequency from SMC Failed !\n"); + goto failed; + } + ret = smu_read_smc_arg(smu, min); + if (ret) + goto failed; + break; + case SMU_UCLK: + case SMU_FCLK: + case SMU_MCLK: + ret = smu_get_dpm_clk_limited(smu, clk_type, 0, min); + if (ret) + goto failed; + break; + case SMU_SOCCLK: + ret = smu_get_dpm_clk_limited(smu, clk_type, 0, min); + if (ret) + goto failed; + break; + default: + ret = -EINVAL; + goto failed; + } + } +failed: + return ret; +} + +int smu_v12_0_mode2_reset(struct smu_context *smu){ + return smu_v12_0_send_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2); +} + +int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, + uint32_t min, uint32_t max) +{ + int ret = 0; + + if (max < min) + return -EINVAL; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min); + if (ret) + return ret; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max); + if (ret) + return ret; + break; + case SMU_FCLK: + case SMU_MCLK: + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min); + if (ret) + return ret; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max); + if (ret) + return ret; + break; + case SMU_SOCCLK: + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min); + if (ret) + return ret; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max); + if (ret) + return ret; + break; + case SMU_VCLK: + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min); + if (ret) + return ret; + + ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max); + if (ret) + return ret; + break; + default: + return -EINVAL; + } + + return ret; +} + +int smu_v12_0_set_driver_table_location(struct smu_context *smu) +{ + struct smu_table *driver_table = &smu->smu_table.driver_table; + int ret = 0; + + if (driver_table->mc_address) { + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrHigh, + upper_32_bits(driver_table->mc_address)); + if (!ret) + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_SetDriverDramAddrLow, + lower_32_bits(driver_table->mc_address)); + } + + return ret; +} diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 15590fd86ef4..868e2d5f6e62 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -653,8 +653,8 @@ static int ci_min_max_v_gnbl_pm_lid_from_bapm_vddc(struct pp_hwmgr *hwmgr) static int ci_populate_bapm_vddc_base_leakage_sidd(struct pp_hwmgr *hwmgr) { struct ci_smumgr *smu_data = (struct ci_smumgr *)(hwmgr->smu_backend); - uint16_t HiSidd = smu_data->power_tune_table.BapmVddCBaseLeakageHiSidd; - uint16_t LoSidd = smu_data->power_tune_table.BapmVddCBaseLeakageLoSidd; + uint16_t HiSidd; + uint16_t LoSidd; struct phm_cac_tdp_table *cac_table = hwmgr->dyn_state.cac_dtp_table; HiSidd = (uint16_t)(cac_table->usHighCACLeakage / 100 * 256); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c index da025b1d302d..32ebb383c456 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/fiji_smumgr.c @@ -940,7 +940,7 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, { int result; /* PP_Clocks minClocks; */ - uint32_t threshold, mvdd; + uint32_t mvdd; struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); @@ -973,8 +973,6 @@ static int fiji_populate_single_graphic_level(struct pp_hwmgr *hwmgr, level->VoltageDownHyst = 0; level->PowerThrottle = 0; - threshold = clock * data->fast_watermark_threshold / 100; - data->display_timing.min_clock_in_sr = hwmgr->display_config->min_core_set_clock_in_sr; if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_SclkDeepSleep)) @@ -1501,7 +1499,7 @@ static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, uint32_t dram_timing; uint32_t dram_timing2; uint32_t burstTime; - ULONG state, trrds, trrdl; + ULONG trrds, trrdl; int result; result = atomctrl_set_engine_dram_timings_rv770(hwmgr, @@ -1513,7 +1511,6 @@ static int fiji_populate_memory_timing_parameters(struct pp_hwmgr *hwmgr, dram_timing2 = cgs_read_register(hwmgr->device, mmMC_ARB_DRAM_TIMING2); burstTime = cgs_read_register(hwmgr->device, mmMC_ARB_BURST_TIME); - state = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, STATE0); trrds = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDS0); trrdl = PHM_GET_FIELD(burstTime, MC_ARB_BURST_TIME, TRRDL0); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c index dc754447f0dd..23c12018dbc1 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/polaris10_smumgr.c @@ -655,7 +655,7 @@ static int polaris10_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, count = SMU_MAX_SMIO_LEVELS; for (level = 0; level < count; level++) { table->SmioTable2.Pattern[level].Voltage = - PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE); + PP_HOST_TO_SMC_US(data->mvdd_voltage_table.entries[level].value * VOLTAGE_SCALE); /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/ table->SmioTable2.Pattern[level].Smio = (uint8_t) level; diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c index 7fb3e57cfc41..2319400a3fcb 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu10_smumgr.c @@ -118,6 +118,7 @@ static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr, { struct smu10_smumgr *priv = (struct smu10_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL;); @@ -135,6 +136,9 @@ static int smu10_copy_table_from_smc(struct pp_hwmgr *hwmgr, PPSMC_MSG_TransferTableSmu2Dram, priv->smu_tables.entry[table_id].table_id); + /* flush hdp cache */ + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table, (uint8_t *)priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -146,6 +150,7 @@ static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr, { struct smu10_smumgr *priv = (struct smu10_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL;); @@ -157,6 +162,8 @@ static int smu10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); + amdgpu_asic_flush_hdp(adev, NULL); + smu10_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c index 8189fe402c6d..7dca04a89217 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu8_smumgr.c @@ -177,12 +177,10 @@ static int smu8_load_mec_firmware(struct pp_hwmgr *hwmgr) uint32_t tmp; int ret = 0; struct cgs_firmware_info info = {0}; - struct smu8_smumgr *smu8_smu; if (hwmgr == NULL || hwmgr->device == NULL) return -EINVAL; - smu8_smu = hwmgr->smu_backend; ret = cgs_get_firmware_info(hwmgr->device, CGS_UCODE_ID_CP_MEC, &info); @@ -722,16 +720,17 @@ static int smu8_request_smu_load_fw(struct pp_hwmgr *hwmgr) static int smu8_start_smu(struct pp_hwmgr *hwmgr) { - struct amdgpu_device *adev = hwmgr->adev; + struct amdgpu_device *adev; uint32_t index = SMN_MP1_SRAM_START_ADDR + SMU8_FIRMWARE_HEADER_LOCATION + offsetof(struct SMU8_Firmware_Header, Version); - if (hwmgr == NULL || hwmgr->device == NULL) return -EINVAL; + adev = hwmgr->adev; + cgs_write_register(hwmgr->device, mmMP0PUB_IND_INDEX, index); hwmgr->smu_version = cgs_read_register(hwmgr->device, mmMP0PUB_IND_DATA); pr_info("smu version %02d.%02d.%02d\n", diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c index 742b3dc1f6cb..adfbcbe5d113 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/smu9_smumgr.c @@ -61,15 +61,29 @@ static uint32_t smu9_wait_for_response(struct pp_hwmgr *hwmgr) uint32_t reg; uint32_t ret; - reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + /* Due to the L1 policy problem under SRIOV, we have to use + * mmMP1_SMN_C2PMSG_103 as the driver response register + */ + if (hwmgr->pp_one_vf) { + reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_103); - ret = phm_wait_for_register_unequal(hwmgr, reg, - 0, MP1_C2PMSG_90__CONTENT_MASK); + ret = phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_103__CONTENT_MASK); - if (ret) - pr_err("No response from smu\n"); + if (ret) + pr_err("No response from smu\n"); - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103); + } else { + reg = SOC15_REG_OFFSET(MP1, 0, mmMP1_SMN_C2PMSG_90); + + ret = phm_wait_for_register_unequal(hwmgr, reg, + 0, MP1_C2PMSG_90__CONTENT_MASK); + + if (ret) + pr_err("No response from smu\n"); + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90); + } } /* @@ -83,7 +97,11 @@ static int smu9_send_msg_to_smc_without_waiting(struct pp_hwmgr *hwmgr, { struct amdgpu_device *adev = hwmgr->adev; - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + if (hwmgr->pp_one_vf) { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_101, msg); + } else { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); + } return 0; } @@ -101,7 +119,10 @@ int smu9_send_msg_to_smc(struct pp_hwmgr *hwmgr, uint16_t msg) smu9_wait_for_response(hwmgr); - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + if (hwmgr->pp_one_vf) + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0); + else + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); smu9_send_msg_to_smc_without_waiting(hwmgr, msg); @@ -127,9 +148,17 @@ int smu9_send_msg_to_smc_with_parameter(struct pp_hwmgr *hwmgr, smu9_wait_for_response(hwmgr); - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); + /* Due to the L1 policy problem under SRIOV, we have to use + * mmMP1_SMN_C2PMSG_101 as the driver message register and + * mmMP1_SMN_C2PMSG_102 as the driver parameter register. + */ + if (hwmgr->pp_one_vf) { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_103, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102, parameter); + } else { + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82, parameter); + } smu9_send_msg_to_smc_without_waiting(hwmgr, msg); @@ -144,5 +173,8 @@ uint32_t smu9_get_argument(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; - return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); + if (hwmgr->pp_one_vf) + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_102); + else + return RREG32_SOC15(MP1, 0, mmMP1_SMN_C2PMSG_82); } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c index 967d34b1dc51..715564009089 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega10_smumgr.c @@ -39,6 +39,7 @@ static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id) { struct vega10_smumgr *priv = hwmgr->smu_backend; + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL); @@ -56,6 +57,9 @@ static int vega10_copy_table_from_smc(struct pp_hwmgr *hwmgr, PPSMC_MSG_TransferTableSmu2Dram, priv->smu_tables.entry[table_id].table_id); + /* flush hdp cache */ + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -66,6 +70,13 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, uint8_t *table, int16_t table_id) { struct vega10_smumgr *priv = hwmgr->smu_backend; + struct amdgpu_device *adev = hwmgr->adev; + + /* under sriov, vbios or hypervisor driver + * has already copy table to smc so here only skip it + */ + if (!hwmgr->not_vf) + return 0; PP_ASSERT_WITH_CODE(table_id < MAX_SMU_TABLE, "Invalid SMU Table ID!", return -EINVAL); @@ -77,6 +88,8 @@ static int vega10_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); + amdgpu_asic_flush_hdp(adev, NULL); + smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)); @@ -96,6 +109,14 @@ int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, int msg = enable ? PPSMC_MSG_EnableSmuFeatures : PPSMC_MSG_DisableSmuFeatures; + /* VF has no permission to change smu feature due + * to security concern even under pp one vf mode + * it still can't do it. For vega10, the smu in + * vbios will enable the appropriate features. + * */ + if (!hwmgr->not_vf) + return 0; + return smum_send_msg_to_smc_with_parameter(hwmgr, msg, feature_mask); } diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c index bab3df85fdcd..275dbf65f1a0 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega12_smumgr.c @@ -42,6 +42,7 @@ static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, { struct vega12_smumgr *priv = (struct vega12_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, "Invalid SMU Table ID!", return -EINVAL); @@ -64,6 +65,9 @@ static int vega12_copy_table_from_smc(struct pp_hwmgr *hwmgr, "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", return -EINVAL); + /* flush hdp cache */ + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -80,6 +84,7 @@ static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, { struct vega12_smumgr *priv = (struct vega12_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, "Invalid SMU Table ID!", return -EINVAL); @@ -91,6 +96,8 @@ static int vega12_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); + amdgpu_asic_flush_hdp(adev, NULL); + PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr)) == 0, @@ -121,20 +128,20 @@ int vega12_enable_smc_features(struct pp_hwmgr *hwmgr, if (enable) { PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low) == 0, - "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!", + "[EnableDisableSMCFeatures] Attempt to enable SMU features Low failed!", return -EINVAL); PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high) == 0, - "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!", + "[EnableDisableSMCFeatures] Attempt to enable SMU features High failed!", return -EINVAL); } else { PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low) == 0, - "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!", + "[EnableDisableSMCFeatures] Attempt to disable SMU features Low failed!", return -EINVAL); PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high) == 0, - "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!", + "[EnableDisableSMCFeatures] Attempt to disable SMU features High failed!", return -EINVAL); } @@ -151,13 +158,13 @@ int vega12_get_enabled_smc_features(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesLow) == 0, - "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!", + "[GetEnabledSMCFeatures] Attempt to get SMU features Low failed!", return -EINVAL); smc_features_low = smu9_get_argument(hwmgr); PP_ASSERT_WITH_CODE(smu9_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesHigh) == 0, - "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!", + "[GetEnabledSMCFeatures] Attempt to get SMU features High failed!", return -EINVAL); smc_features_high = smu9_get_argument(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c index 957446cf467e..49e5ef3e3876 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c @@ -44,7 +44,7 @@ #define smnMP0_FW_INTF 0x30101c0 #define smnMP1_PUB_CTRL 0x3010b14 -static bool vega20_is_smc_ram_running(struct pp_hwmgr *hwmgr) +bool vega20_is_smc_ram_running(struct pp_hwmgr *hwmgr) { struct amdgpu_device *adev = hwmgr->adev; uint32_t mp1_fw_flags; @@ -163,6 +163,7 @@ static int vega20_copy_table_from_smc(struct pp_hwmgr *hwmgr, { struct vega20_smumgr *priv = (struct vega20_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; int ret = 0; PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, @@ -187,6 +188,9 @@ static int vega20_copy_table_from_smc(struct pp_hwmgr *hwmgr, "[CopyTableFromSMC] Attempt to Transfer Table From SMU Failed!", return ret); + /* flush hdp cache */ + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table, priv->smu_tables.entry[table_id].table, priv->smu_tables.entry[table_id].size); @@ -203,6 +207,7 @@ static int vega20_copy_table_to_smc(struct pp_hwmgr *hwmgr, { struct vega20_smumgr *priv = (struct vega20_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; int ret = 0; PP_ASSERT_WITH_CODE(table_id < TABLE_COUNT, @@ -215,6 +220,8 @@ static int vega20_copy_table_to_smc(struct pp_hwmgr *hwmgr, memcpy(priv->smu_tables.entry[table_id].table, table, priv->smu_tables.entry[table_id].size); + amdgpu_asic_flush_hdp(adev, NULL); + PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[table_id].mc_addr))) == 0, @@ -238,11 +245,14 @@ int vega20_set_activity_monitor_coeff(struct pp_hwmgr *hwmgr, { struct vega20_smumgr *priv = (struct vega20_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; int ret = 0; memcpy(priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table, table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size); + amdgpu_asic_flush_hdp(adev, NULL); + PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetDriverDramAddrHigh, upper_32_bits(priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].mc_addr))) == 0, @@ -266,6 +276,7 @@ int vega20_get_activity_monitor_coeff(struct pp_hwmgr *hwmgr, { struct vega20_smumgr *priv = (struct vega20_smumgr *)(hwmgr->smu_backend); + struct amdgpu_device *adev = hwmgr->adev; int ret = 0; PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, @@ -284,6 +295,9 @@ int vega20_get_activity_monitor_coeff(struct pp_hwmgr *hwmgr, "[GetActivityMonitor] Attempt to Transfer Table From SMU Failed!", return ret); + /* flush hdp cache */ + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].table, priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size); @@ -302,20 +316,20 @@ int vega20_enable_smc_features(struct pp_hwmgr *hwmgr, if (enable) { PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesLow, smu_features_low)) == 0, - "[EnableDisableSMCFeatures] Attemp to enable SMU features Low failed!", + "[EnableDisableSMCFeatures] Attempt to enable SMU features Low failed!", return ret); PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_EnableSmuFeaturesHigh, smu_features_high)) == 0, - "[EnableDisableSMCFeatures] Attemp to enable SMU features High failed!", + "[EnableDisableSMCFeatures] Attempt to enable SMU features High failed!", return ret); } else { PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesLow, smu_features_low)) == 0, - "[EnableDisableSMCFeatures] Attemp to disable SMU features Low failed!", + "[EnableDisableSMCFeatures] Attempt to disable SMU features Low failed!", return ret); PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_DisableSmuFeaturesHigh, smu_features_high)) == 0, - "[EnableDisableSMCFeatures] Attemp to disable SMU features High failed!", + "[EnableDisableSMCFeatures] Attempt to disable SMU features High failed!", return ret); } @@ -333,12 +347,12 @@ int vega20_get_enabled_smc_features(struct pp_hwmgr *hwmgr, PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesLow)) == 0, - "[GetEnabledSMCFeatures] Attemp to get SMU features Low failed!", + "[GetEnabledSMCFeatures] Attempt to get SMU features Low failed!", return ret); smc_features_low = vega20_get_argument(hwmgr); PP_ASSERT_WITH_CODE((ret = vega20_send_msg_to_smc(hwmgr, PPSMC_MSG_GetEnabledSmuFeaturesHigh)) == 0, - "[GetEnabledSMCFeatures] Attemp to get SMU features High failed!", + "[GetEnabledSMCFeatures] Attempt to get SMU features High failed!", return ret); smc_features_high = vega20_get_argument(hwmgr); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h index ec953ab13e87..62ebbfd6068f 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.h @@ -57,5 +57,7 @@ int vega20_get_activity_monitor_coeff(struct pp_hwmgr *hwmgr, uint8_t *table, uint16_t workload_type); int vega20_set_pptable_driver_address(struct pp_hwmgr *hwmgr); +bool vega20_is_smc_ram_running(struct pp_hwmgr *hwmgr); + #endif diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c index 7c960b07746f..b0e0d67cd54b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c @@ -456,7 +456,7 @@ static int vegam_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr, count = SMU_MAX_SMIO_LEVELS; for (level = 0; level < count; level++) { table->SmioTable2.Pattern[level].Voltage = PP_HOST_TO_SMC_US( - data->mvdd_voltage_table.entries[count].value * VOLTAGE_SCALE); + data->mvdd_voltage_table.entries[level].value * VOLTAGE_SCALE); /* Index into DpmTable.Smio. Drive bits from Smio entry to get this voltage level.*/ table->SmioTable2.Pattern[level].Smio = (uint8_t) level; @@ -1114,7 +1114,6 @@ static int vegam_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, (struct phm_ppt_v1_information *)(hwmgr->pptable); SMIO_Pattern vol_level; uint32_t mvdd; - uint16_t us_mvdd; table->ACPILevel.Flags &= ~PPSMC_SWSTATE_FLAG_DC; @@ -1168,17 +1167,6 @@ static int vegam_populate_smc_acpi_level(struct pp_hwmgr *hwmgr, "in Clock Dependency Table", ); - us_mvdd = 0; - if ((SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) || - (data->mclk_dpm_key_disabled)) - us_mvdd = data->vbios_boot_state.mvdd_bootup_value; - else { - if (!vegam_populate_mvdd_value(hwmgr, - data->dpm_table.mclk_table.dpm_levels[0].value, - &vol_level)) - us_mvdd = vol_level.Voltage; - } - if (!vegam_populate_mvdd_value(hwmgr, 0, &vol_level)) table->MemoryACPILevel.MinMvdd = PP_HOST_TO_SMC_UL(vol_level.Voltage); else @@ -1383,11 +1371,16 @@ static int vegam_populate_smc_boot_level(struct pp_hwmgr *hwmgr, result = phm_find_boot_level(&(data->dpm_table.sclk_table), data->vbios_boot_state.sclk_bootup_value, (uint32_t *)&(table->GraphicsBootLevel)); + if (result) + return result; result = phm_find_boot_level(&(data->dpm_table.mclk_table), data->vbios_boot_state.mclk_bootup_value, (uint32_t *)&(table->MemoryBootLevel)); + if (result) + return result; + table->BootVddc = data->vbios_boot_state.vddc_bootup_value * VOLTAGE_SCALE; table->BootVddci = data->vbios_boot_state.vddci_bootup_value * @@ -1493,7 +1486,7 @@ static int vegam_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) struct vegam_smumgr *smu_data = (struct vegam_smumgr *)(hwmgr->smu_backend); - uint8_t i, stretch_amount, stretch_amount2, volt_offset = 0; + uint8_t i, stretch_amount, volt_offset = 0; struct phm_ppt_v1_information *table_info = (struct phm_ppt_v1_information *)(hwmgr->pptable); struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table = @@ -1532,11 +1525,9 @@ static int vegam_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr) (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 5; /* Populate CKS Lookup Table */ - if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5) - stretch_amount2 = 0; - else if (stretch_amount == 3 || stretch_amount == 4) - stretch_amount2 = 1; - else { + if (!(stretch_amount == 1 || stretch_amount == 2 || + stretch_amount == 5 || stretch_amount == 3 || + stretch_amount == 4)) { phm_cap_unset(hwmgr->platform_descriptor.platformCaps, PHM_PlatformCaps_ClockStretcher); PP_ASSERT_WITH_CODE(false, diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c index dd6fd1c8bf24..4ad8d6c14ee5 100644 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c @@ -25,6 +25,7 @@ #include <linux/firmware.h> #include "amdgpu.h" #include "amdgpu_smu.h" +#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" #include "smu_v11_0.h" @@ -47,7 +48,7 @@ #define CTF_OFFSET_HBM 5 #define MSG_MAP(msg) \ - [SMU_MSG_##msg] = PPSMC_MSG_##msg + [SMU_MSG_##msg] = {1, PPSMC_MSG_##msg} #define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \ FEATURE_DPM_GFXCLK_MASK | \ @@ -59,7 +60,7 @@ FEATURE_DPM_LINK_MASK | \ FEATURE_DPM_DCEFCLK_MASK) -static int vega20_message_map[SMU_MSG_MAX_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping vega20_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(TestMessage), MSG_MAP(GetSmuVersion), MSG_MAP(GetDriverIfVersion), @@ -143,9 +144,10 @@ static int vega20_message_map[SMU_MSG_MAX_COUNT] = { MSG_MAP(PrepareMp1ForShutdown), MSG_MAP(SetMGpuFanBoostLimitRpm), MSG_MAP(GetAVFSVoltageByDpm), + MSG_MAP(DFCstateControl), }; -static int vega20_clk_map[SMU_CLK_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping vega20_clk_map[SMU_CLK_COUNT] = { CLK_MAP(GFXCLK, PPCLK_GFXCLK), CLK_MAP(VCLK, PPCLK_VCLK), CLK_MAP(DCLK, PPCLK_DCLK), @@ -159,7 +161,7 @@ static int vega20_clk_map[SMU_CLK_COUNT] = { CLK_MAP(FCLK, PPCLK_FCLK), }; -static int vega20_feature_mask_map[SMU_FEATURE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping vega20_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(DPM_PREFETCHER), FEA_MAP(DPM_GFXCLK), FEA_MAP(DPM_UCLK), @@ -195,7 +197,7 @@ static int vega20_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(XGMI), }; -static int vega20_table_map[SMU_TABLE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping vega20_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PPTABLE), TAB_MAP(WATERMARKS), TAB_MAP(AVFS), @@ -208,96 +210,109 @@ static int vega20_table_map[SMU_TABLE_COUNT] = { TAB_MAP(OVERDRIVE), }; -static int vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { +static struct smu_11_0_cmn2aisc_mapping vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { PWR_MAP(AC), PWR_MAP(DC), }; -static int vega20_workload_map[] = { +static struct smu_11_0_cmn2aisc_mapping vega20_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT, WORKLOAD_DEFAULT_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING, WORKLOAD_PPLIB_POWER_SAVING_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VIDEO, WORKLOAD_PPLIB_VIDEO_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_VR, WORKLOAD_PPLIB_VR_BIT), - WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_CUSTOM_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_COMPUTE, WORKLOAD_PPLIB_COMPUTE_BIT), WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), }; static int vega20_get_smu_table_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_TABLE_COUNT) return -EINVAL; - val = vega20_table_map[index]; - if (val >= TABLE_COUNT) + mapping = vega20_table_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_get_pwr_src_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_POWER_SOURCE_COUNT) return -EINVAL; - val = vega20_pwr_src_map[index]; - if (val >= POWER_SOURCE_COUNT) + mapping = vega20_pwr_src_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_get_smu_feature_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_FEATURE_COUNT) return -EINVAL; - val = vega20_feature_mask_map[index]; - if (val > 64) + mapping = vega20_feature_mask_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_get_smu_clk_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (index >= SMU_CLK_COUNT) return -EINVAL; - val = vega20_clk_map[index]; - if (val >= PPCLK_COUNT) + mapping = vega20_clk_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_get_smu_msg_index(struct smu_context *smc, uint32_t index) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; if (index >= SMU_MSG_MAX_COUNT) return -EINVAL; - val = vega20_message_map[index]; - if (val > PPSMC_Message_Count) + mapping = vega20_message_map[index]; + if (!(mapping.valid_mapping)) { return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile) { - int val; + struct smu_11_0_cmn2aisc_mapping mapping; + if (profile > PP_SMC_POWER_PROFILE_CUSTOM) return -EINVAL; - val = vega20_workload_map[profile]; + mapping = vega20_workload_map[profile]; + if (!(mapping.valid_mapping)) { + return -EINVAL; + } - return val; + return mapping.map_to; } static int vega20_tables_init(struct smu_context *smu, struct smu_table *tables) @@ -323,6 +338,10 @@ static int vega20_tables_init(struct smu_context *smu, struct smu_table *tables) return -ENOMEM; smu_table->metrics_time = 0; + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + if (!smu_table->watermarks_table) + return -ENOMEM; + return 0; } @@ -451,7 +470,6 @@ static int vega20_store_powerplay_table(struct smu_context *smu) sizeof(PPTable_t)); table_context->thermal_controller_type = powerplay_table->ucThermalControllerType; - table_context->TDPODLimit = le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingsMax[ATOM_VEGA20_ODSETTING_POWERPERCENTAGE]); return 0; } @@ -621,7 +639,6 @@ amd_pm_state_type vega20_get_current_power_state(struct smu_context *smu) !smu_dpm_ctx->dpm_current_power_state) return -EINVAL; - mutex_lock(&(smu->mutex)); switch (smu_dpm_ctx->dpm_current_power_state->classification.ui_label) { case SMU_STATE_UI_LABEL_BATTERY: pm_type = POWER_STATE_TYPE_BATTERY; @@ -639,7 +656,6 @@ amd_pm_state_type vega20_get_current_power_state(struct smu_context *smu) pm_type = POWER_STATE_TYPE_DEFAULT; break; } - mutex_unlock(&(smu->mutex)); return pm_type; } @@ -1261,16 +1277,8 @@ static int vega20_force_clk_levels(struct smu_context *smu, struct vega20_dpm_table *dpm_table; struct vega20_single_dpm_table *single_dpm_table; uint32_t soft_min_level, soft_max_level, hard_min_level; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; int ret = 0; - if (smu_dpm->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { - pr_info("force clock level is for dpm manual mode only.\n"); - return -EINVAL; - } - - mutex_lock(&(smu->mutex)); - soft_min_level = mask ? (ffs(mask) - 1) : 0; soft_max_level = mask ? (fls(mask) - 1) : 0; @@ -1423,7 +1431,6 @@ static int vega20_force_clk_levels(struct smu_context *smu, break; } - mutex_unlock(&(smu->mutex)); return ret; } @@ -1438,8 +1445,6 @@ static int vega20_get_clock_by_type_with_latency(struct smu_context *smu, dpm_table = smu_dpm->dpm_context; - mutex_lock(&smu->mutex); - switch (clk_type) { case SMU_GFXCLK: single_dpm_table = &(dpm_table->gfx_table); @@ -1461,7 +1466,6 @@ static int vega20_get_clock_by_type_with_latency(struct smu_context *smu, ret = -EINVAL; } - mutex_unlock(&smu->mutex); return ret; } @@ -1678,17 +1682,20 @@ static int vega20_get_metrics_table(struct smu_context *smu, struct smu_table_context *smu_table= &smu->smu_table; int ret = 0; + mutex_lock(&smu->metrics_lock); if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + HZ / 1000)) { ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0, (void *)smu_table->metrics_table, false); if (ret) { pr_info("Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); return ret; } smu_table->metrics_time = jiffies; } memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t)); + mutex_unlock(&smu->metrics_lock); return ret; } @@ -1699,22 +1706,11 @@ static int vega20_set_default_od_settings(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; int ret; - if (initialize) { - if (table_context->overdrive_table) - return -EINVAL; - - table_context->overdrive_table = kzalloc(sizeof(OverDriveTable_t), GFP_KERNEL); - - if (!table_context->overdrive_table) - return -ENOMEM; - - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, - table_context->overdrive_table, false); - if (ret) { - pr_err("Failed to export over drive table!\n"); - return ret; - } + ret = smu_v11_0_set_default_od_settings(smu, initialize, sizeof(OverDriveTable_t)); + if (ret) + return ret; + if (initialize) { ret = vega20_set_default_od8_setttings(smu); if (ret) return ret; @@ -1770,7 +1766,7 @@ static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf) { DpmActivityMonitorCoeffInt_t activity_monitor; uint32_t i, size = 0; - uint16_t workload_type = 0; + int16_t workload_type = 0; static const char *profile_name[] = { "BOOTUP_DEFAULT", "3D_FULL_SCREEN", @@ -1803,6 +1799,9 @@ static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf) for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_workload_get_type(smu, i); + if (workload_type < 0) + return -EINVAL; + result = smu_update_table(smu, SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, (void *)(&activity_monitor), false); @@ -1955,6 +1954,8 @@ static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, u /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ workload_type = smu_workload_get_type(smu, smu->power_profile_mode); + if (workload_type < 0) + return -EINVAL; smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1 << workload_type); @@ -2227,7 +2228,7 @@ static int vega20_apply_clocks_adjust_rules(struct smu_context *smu) } static int -vega20_notify_smc_dispaly_config(struct smu_context *smu) +vega20_notify_smc_display_config(struct smu_context *smu) { struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context; struct vega20_single_dpm_table *memtable = &dpm_table->mem_table; @@ -2242,7 +2243,7 @@ vega20_notify_smc_dispaly_config(struct smu_context *smu) if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { clock_req.clock_type = amd_pp_dcef_clock; clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10; - if (!smu->funcs->display_clock_voltage_request(smu, &clock_req)) { + if (!smu_v11_0_display_clock_voltage_request(smu, &clock_req)) { if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetMinDeepSleepDcefclk, @@ -2529,8 +2530,6 @@ static int vega20_set_od_percentage(struct smu_context *smu, int feature_enabled; PPCLK_e clk_id; - mutex_lock(&(smu->mutex)); - dpm_table = smu_dpm->dpm_context; golden_table = smu_dpm->golden_dpm_context; @@ -2580,11 +2579,10 @@ static int vega20_set_od_percentage(struct smu_context *smu, } ret = smu_handle_task(smu, smu_dpm->dpm_level, - AMD_PP_TASK_READJUST_POWER_STATE); + AMD_PP_TASK_READJUST_POWER_STATE, + false); set_od_failed: - mutex_unlock(&(smu->mutex)); - return ret; } @@ -2769,12 +2767,11 @@ static int vega20_odn_edit_dpm_table(struct smu_context *smu, break; case PP_OD_RESTORE_DEFAULT_TABLE: - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, false); - if (ret) { - pr_err("Failed to export over drive table!\n"); - return ret; + if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) { + pr_err("Overdrive table was not initialized!\n"); + return -EINVAL; } - + memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t)); break; case PP_OD_COMMIT_DPM_TABLE: @@ -2809,10 +2806,9 @@ static int vega20_odn_edit_dpm_table(struct smu_context *smu, } if (type == PP_OD_COMMIT_DPM_TABLE) { - mutex_lock(&(smu->mutex)); ret = smu_handle_task(smu, smu_dpm->dpm_level, - AMD_PP_TASK_READJUST_POWER_STATE); - mutex_unlock(&(smu->mutex)); + AMD_PP_TASK_READJUST_POWER_STATE, + false); } return ret; @@ -2840,157 +2836,6 @@ static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool enable) return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_VCE_BIT, enable); } -static int vega20_get_enabled_smc_features(struct smu_context *smu, - uint64_t *features_enabled) -{ - uint32_t feature_mask[2] = {0, 0}; - int ret = 0; - - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); - if (ret) - return ret; - - *features_enabled = ((((uint64_t)feature_mask[0] << SMU_FEATURES_LOW_SHIFT) & SMU_FEATURES_LOW_MASK) | - (((uint64_t)feature_mask[1] << SMU_FEATURES_HIGH_SHIFT) & SMU_FEATURES_HIGH_MASK)); - - return ret; -} - -static int vega20_enable_smc_features(struct smu_context *smu, - bool enable, uint64_t feature_mask) -{ - uint32_t smu_features_low, smu_features_high; - int ret = 0; - - smu_features_low = (uint32_t)((feature_mask & SMU_FEATURES_LOW_MASK) >> SMU_FEATURES_LOW_SHIFT); - smu_features_high = (uint32_t)((feature_mask & SMU_FEATURES_HIGH_MASK) >> SMU_FEATURES_HIGH_SHIFT); - - if (enable) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, - smu_features_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, - smu_features_high); - if (ret) - return ret; - } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, - smu_features_low); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, - smu_features_high); - if (ret) - return ret; - } - - return 0; - -} - -static int vega20_get_ppfeature_status(struct smu_context *smu, char *buf) -{ - static const char *ppfeature_name[] = { - "DPM_PREFETCHER", - "GFXCLK_DPM", - "UCLK_DPM", - "SOCCLK_DPM", - "UVD_DPM", - "VCE_DPM", - "ULV", - "MP0CLK_DPM", - "LINK_DPM", - "DCEFCLK_DPM", - "GFXCLK_DS", - "SOCCLK_DS", - "LCLK_DS", - "PPT", - "TDC", - "THERMAL", - "GFX_PER_CU_CG", - "RM", - "DCEFCLK_DS", - "ACDC", - "VR0HOT", - "VR1HOT", - "FW_CTF", - "LED_DISPLAY", - "FAN_CONTROL", - "GFX_EDC", - "GFXOFF", - "CG", - "FCLK_DPM", - "FCLK_DS", - "MP1CLK_DS", - "MP0CLK_DS", - "XGMI", - "ECC"}; - static const char *output_title[] = { - "FEATURES", - "BITMASK", - "ENABLEMENT"}; - uint64_t features_enabled; - int i; - int ret = 0; - int size = 0; - - ret = vega20_get_enabled_smc_features(smu, &features_enabled); - if (ret) - return ret; - - size += sprintf(buf + size, "Current ppfeatures: 0x%016llx\n", features_enabled); - size += sprintf(buf + size, "%-19s %-22s %s\n", - output_title[0], - output_title[1], - output_title[2]); - for (i = 0; i < GNLD_FEATURES_MAX; i++) { - size += sprintf(buf + size, "%-19s 0x%016llx %6s\n", - ppfeature_name[i], - 1ULL << i, - (features_enabled & (1ULL << i)) ? "Y" : "N"); - } - - return size; -} - -static int vega20_set_ppfeature_status(struct smu_context *smu, uint64_t new_ppfeature_masks) -{ - uint64_t features_enabled; - uint64_t features_to_enable; - uint64_t features_to_disable; - int ret = 0; - - if (new_ppfeature_masks >= (1ULL << GNLD_FEATURES_MAX)) - return -EINVAL; - - ret = vega20_get_enabled_smc_features(smu, &features_enabled); - if (ret) - return ret; - - features_to_disable = - features_enabled & ~new_ppfeature_masks; - features_to_enable = - ~features_enabled & new_ppfeature_masks; - - pr_debug("features_to_disable 0x%llx\n", features_to_disable); - pr_debug("features_to_enable 0x%llx\n", features_to_enable); - - if (features_to_disable) { - ret = vega20_enable_smc_features(smu, false, features_to_disable); - if (ret) - return ret; - } - - if (features_to_enable) { - ret = vega20_enable_smc_features(smu, true, features_to_enable); - if (ret) - return ret; - } - - return 0; -} - static bool vega20_is_dpm_running(struct smu_context *smu) { int ret = 0; @@ -3050,6 +2895,7 @@ static int vega20_get_fan_speed_percent(struct smu_context *smu, static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value) { + uint32_t smu_version; int ret = 0; SmuMetrics_t metrics; @@ -3060,7 +2906,15 @@ static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value) if (ret) return ret; - *value = metrics.CurrSocketPower << 8; + ret = smu_get_smc_version(smu, NULL, &smu_version); + if (ret) + return ret; + + /* For the 40.46 release, they changed the value name */ + if (smu_version == 0x282e00) + *value = metrics.AverageSocketPower << 8; + else + *value = metrics.CurrSocketPower << 8; return 0; } @@ -3144,6 +2998,10 @@ static int vega20_read_sensor(struct smu_context *smu, struct smu_table_context *table_context = &smu->smu_table; PPTable_t *pptable = table_context->driver_pptable; + if(!data || !size) + return -EINVAL; + + mutex_lock(&smu->sensor_lock); switch (sensor) { case AMDGPU_PP_SENSOR_MAX_FAN_RPM: *(uint32_t *)data = pptable->FanMaximumRpm; @@ -3167,8 +3025,9 @@ static int vega20_read_sensor(struct smu_context *smu, *size = 4; break; default: - return -EINVAL; + ret = smu_v11_0_read_sensor(smu, sensor, data, size); } + mutex_unlock(&smu->sensor_lock); return ret; } @@ -3243,19 +3102,66 @@ static int vega20_get_thermal_temperature_range(struct smu_context *smu, if (!range || !powerplay_table) return -EINVAL; - /* The unit is temperature */ - range->min = 0; - range->max = powerplay_table->usSoftwareShutdownTemp; - range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE); - range->hotspot_crit_max = pptable->ThotspotLimit; - range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT); - range->mem_crit_max = pptable->ThbmLimit; - range->mem_emergency_max = (pptable->ThbmLimit + CTF_OFFSET_HBM); + range->max = powerplay_table->usSoftwareShutdownTemp * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_crit_max = pptable->ThotspotLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_crit_max = pptable->ThbmLimit * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_emergency_max = (pptable->ThbmLimit + CTF_OFFSET_HBM) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; return 0; } +static int vega20_set_df_cstate(struct smu_context *smu, + enum pp_df_cstate state) +{ + uint32_t smu_version; + int ret; + + ret = smu_get_smc_version(smu, NULL, &smu_version); + if (ret) { + pr_err("Failed to get smu version!\n"); + return ret; + } + + /* PPSMC_MSG_DFCstateControl is supported with 40.50 and later fws */ + if (smu_version < 0x283200) { + pr_err("Df cstate control is supported with 40.50 and later SMC fw!\n"); + return -EINVAL; + } + + return smu_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state); +} + +static int vega20_update_pcie_parameters(struct smu_context *smu, + uint32_t pcie_gen_cap, + uint32_t pcie_width_cap) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + int ret, i; + uint32_t smu_pcie_arg; + + for (i = 0; i < NUM_LINK_LEVELS; i++) { + smu_pcie_arg = (i << 16) | + ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) : + (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ? + pptable->PcieLaneCount[i] : pcie_width_cap); + ret = smu_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg); + } + + return ret; +} + + static const struct pptable_funcs vega20_ppt_funcs = { .tables_init = vega20_tables_init, .alloc_dpm_context = vega20_allocate_dpm_context, @@ -3268,7 +3174,7 @@ static const struct pptable_funcs vega20_ppt_funcs = { .get_smu_table_index = vega20_get_smu_table_index, .get_smu_power_index = vega20_get_pwr_src_index, .get_workload_type = vega20_get_workload_type, - .run_afll_btc = vega20_run_btc_afll, + .run_btc = vega20_run_btc_afll, .get_allowed_feature_mask = vega20_get_allowed_feature_mask, .get_current_power_state = vega20_get_current_power_state, .set_default_dpm_table = vega20_set_default_dpm_table, @@ -3280,6 +3186,7 @@ static const struct pptable_funcs vega20_ppt_funcs = { .get_od_percentage = vega20_get_od_percentage, .get_power_profile_mode = vega20_get_power_profile_mode, .set_power_profile_mode = vega20_set_power_profile_mode, + .set_performance_level = smu_v11_0_set_performance_level, .set_od_percentage = vega20_set_od_percentage, .set_default_od_settings = vega20_set_default_od_settings, .od_edit_dpm_table = vega20_odn_edit_dpm_table, @@ -3289,25 +3196,71 @@ static const struct pptable_funcs vega20_ppt_funcs = { .pre_display_config_changed = vega20_pre_display_config_changed, .display_config_changed = vega20_display_config_changed, .apply_clocks_adjust_rules = vega20_apply_clocks_adjust_rules, - .notify_smc_dispaly_config = vega20_notify_smc_dispaly_config, + .notify_smc_display_config = vega20_notify_smc_display_config, .force_dpm_limit_value = vega20_force_dpm_limit_value, .unforce_dpm_levels = vega20_unforce_dpm_levels, .get_profiling_clk_mask = vega20_get_profiling_clk_mask, - .set_ppfeature_status = vega20_set_ppfeature_status, - .get_ppfeature_status = vega20_get_ppfeature_status, .is_dpm_running = vega20_is_dpm_running, .set_thermal_fan_table = vega20_set_thermal_fan_table, .get_fan_speed_percent = vega20_get_fan_speed_percent, .get_fan_speed_rpm = vega20_get_fan_speed_rpm, .set_watermarks_table = vega20_set_watermarks_table, - .get_thermal_temperature_range = vega20_get_thermal_temperature_range + .get_thermal_temperature_range = vega20_get_thermal_temperature_range, + .set_df_cstate = vega20_set_df_cstate, + .update_pcie_parameters = vega20_update_pcie_parameters, + .init_microcode = smu_v11_0_init_microcode, + .load_microcode = smu_v11_0_load_microcode, + .init_smc_tables = smu_v11_0_init_smc_tables, + .fini_smc_tables = smu_v11_0_fini_smc_tables, + .init_power = smu_v11_0_init_power, + .fini_power = smu_v11_0_fini_power, + .check_fw_status = smu_v11_0_check_fw_status, + .setup_pptable = smu_v11_0_setup_pptable, + .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, + .get_clk_info_from_vbios = smu_v11_0_get_clk_info_from_vbios, + .check_pptable = smu_v11_0_check_pptable, + .parse_pptable = smu_v11_0_parse_pptable, + .populate_smc_tables = smu_v11_0_populate_smc_pptable, + .check_fw_version = smu_v11_0_check_fw_version, + .write_pptable = smu_v11_0_write_pptable, + .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep, + .set_driver_table_location = smu_v11_0_set_driver_table_location, + .set_tool_table_location = smu_v11_0_set_tool_table_location, + .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location, + .system_features_control = smu_v11_0_system_features_control, + .send_smc_msg_with_param = smu_v11_0_send_msg_with_param, + .read_smc_arg = smu_v11_0_read_arg, + .init_display_count = smu_v11_0_init_display_count, + .set_allowed_mask = smu_v11_0_set_allowed_mask, + .get_enabled_mask = smu_v11_0_get_enabled_mask, + .notify_display_change = smu_v11_0_notify_display_change, + .set_power_limit = smu_v11_0_set_power_limit, + .get_current_clk_freq = smu_v11_0_get_current_clk_freq, + .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, + .start_thermal_control = smu_v11_0_start_thermal_control, + .stop_thermal_control = smu_v11_0_stop_thermal_control, + .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk, + .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request, + .get_fan_control_mode = smu_v11_0_get_fan_control_mode, + .set_fan_control_mode = smu_v11_0_set_fan_control_mode, + .set_fan_speed_percent = smu_v11_0_set_fan_speed_percent, + .set_fan_speed_rpm = smu_v11_0_set_fan_speed_rpm, + .set_xgmi_pstate = smu_v11_0_set_xgmi_pstate, + .gfx_off_control = smu_v11_0_gfx_off_control, + .register_irq_handler = smu_v11_0_register_irq_handler, + .set_azalia_d3_pme = smu_v11_0_set_azalia_d3_pme, + .get_max_sustainable_clocks_by_dc = smu_v11_0_get_max_sustainable_clocks_by_dc, + .baco_is_support= smu_v11_0_baco_is_support, + .baco_get_state = smu_v11_0_baco_get_state, + .baco_set_state = smu_v11_0_baco_set_state, + .baco_enter = smu_v11_0_baco_enter, + .baco_exit = smu_v11_0_baco_exit, + .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, + .override_pcie_parameters = smu_v11_0_override_pcie_parameters, }; void vega20_set_ppt_funcs(struct smu_context *smu) { - struct smu_table_context *smu_table = &smu->smu_table; - smu->ppt_funcs = &vega20_ppt_funcs; - smu->smc_if_version = SMU11_DRIVER_IF_VERSION; - smu_table->table_count = TABLE_COUNT; } |