diff options
Diffstat (limited to 'drivers/gpu/drm/amd/powerplay')
36 files changed, 9320 insertions, 8297 deletions
diff --git a/drivers/gpu/drm/amd/powerplay/Makefile b/drivers/gpu/drm/amd/powerplay/Makefile index 390345f2d601..e9c48f99f71b 100644 --- a/drivers/gpu/drm/amd/powerplay/Makefile +++ b/drivers/gpu/drm/amd/powerplay/Makefile @@ -35,7 +35,9 @@ AMD_POWERPLAY = $(addsuffix /Makefile,$(addprefix $(FULL_AMD_PATH)/powerplay/,$( include $(AMD_POWERPLAY) -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 +POWER_MGR = amd_powerplay.o amdgpu_smu.o smu_v11_0.o \ + smu_v12_0.o arcturus_ppt.o navi10_ppt.o \ + renoir_ppt.o sienna_cichlid_ppt.o smu_cmn.o AMD_PP_POWER = $(addprefix $(AMD_PP_PATH)/,$(POWER_MGR)) diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c index 8c684a6e0156..0826625573dc 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c @@ -20,406 +20,191 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#define SWSMU_CODE_LAYER_L1 + #include <linux/firmware.h> #include <linux/pci.h> #include "amdgpu.h" #include "amdgpu_smu.h" #include "smu_internal.h" -#include "smu_v11_0.h" -#include "smu_v12_0.h" #include "atom.h" -#include "vega20_ppt.h" #include "arcturus_ppt.h" #include "navi10_ppt.h" +#include "sienna_cichlid_ppt.h" #include "renoir_ppt.h" +#include "amd_pcie.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]; -} +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug size_t smu_sys_get_pp_feature_mask(struct smu_context *smu, char *buf) { - struct amdgpu_device *adev = smu->adev; 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; - - if (!adev->pm.dpm_enabled) - return -EINVAL; - mutex_lock(&smu->mutex); - - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); - if (ret) - goto failed; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; - 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++; - } + mutex_lock(&smu->mutex); - 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"); - } + size = smu_get_pp_feature_mask(smu, buf); -failed: mutex_unlock(&smu->mutex); return size; } -static int smu_feature_update_enable_state(struct smu_context *smu, - uint64_t feature_mask, - bool enabled) +int smu_sys_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) { - struct smu_feature *feature = &smu->smu_feature; - uint32_t feature_low = 0, feature_high = 0; int ret = 0; - feature_low = (feature_mask >> 0 ) & 0xffffffff; - feature_high = (feature_mask >> 32) & 0xffffffff; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; - if (enabled) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesLow, - feature_low, NULL); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnableSmuFeaturesHigh, - feature_high, NULL); - if (ret) - return ret; - } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesLow, - feature_low, NULL); - if (ret) - return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DisableSmuFeaturesHigh, - feature_high, NULL); - if (ret) - return ret; - } + mutex_lock(&smu->mutex); - 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); + ret = smu_set_pp_feature_mask(smu, new_mask); + + mutex_unlock(&smu->mutex); return ret; } -int smu_sys_set_pp_feature_mask(struct smu_context *smu, uint64_t new_mask) +int smu_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value) { 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; - struct amdgpu_device *adev = smu->adev; - - if (!adev->pm.dpm_enabled) - return -EINVAL; + struct smu_context *smu = &adev->smu; - mutex_lock(&smu->mutex); + if (is_support_sw_smu(adev) && smu->ppt_funcs->get_gfx_off_status) + *value = smu_get_gfx_off_status(smu); + else + ret = -EINVAL; - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); - if (ret) - goto out; + return ret; +} - feature_enables = ((uint64_t)feature_mask[1] << 32 | (uint64_t)feature_mask[0]); +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; - feature_2_enabled = ~feature_enables & new_mask; - feature_2_disabled = feature_enables & ~new_mask; + mutex_lock(&smu->mutex); - 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; - } + if (smu->ppt_funcs->set_soft_freq_limited_range) + ret = smu->ppt_funcs->set_soft_freq_limited_range(smu, + clk_type, + min, + max); -out: mutex_unlock(&smu->mutex); return ret; } -int smu_get_smc_version(struct smu_context *smu, uint32_t *if_version, uint32_t *smu_version) +int smu_get_dpm_freq_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, + uint32_t *max) { int ret = 0; - if (!if_version && !smu_version) + if (!min && !max) return -EINVAL; - if (smu->smc_fw_if_version && smu->smc_fw_version) - { - if (if_version) - *if_version = smu->smc_fw_if_version; - - if (smu_version) - *smu_version = smu->smc_fw_version; - - return 0; - } - - if (if_version) { - ret = smu_send_smc_msg(smu, SMU_MSG_GetDriverIfVersion, if_version); - if (ret) - return ret; - - smu->smc_fw_if_version = *if_version; - } + mutex_lock(&smu->mutex); - if (smu_version) { - ret = smu_send_smc_msg(smu, SMU_MSG_GetSmuVersion, smu_version); - if (ret) - return ret; + if (smu->ppt_funcs->get_dpm_ultimate_freq) + ret = smu->ppt_funcs->get_dpm_ultimate_freq(smu, + clk_type, + min, + max); - smu->smc_fw_version = *smu_version; - } + mutex_unlock(&smu->mutex); return ret; } -int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max, bool lock_needed) +static int smu_dpm_set_vcn_enable_locked(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 (!smu_clk_dpm_is_enabled(smu, clk_type)) + if (!smu->ppt_funcs->dpm_set_vcn_enable) return 0; - if (lock_needed) - mutex_lock(&smu->mutex); - ret = smu_set_soft_freq_limited_range(smu, clk_type, min, max); - if (lock_needed) - mutex_unlock(&smu->mutex); - - return ret; -} - -int smu_set_hard_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; - - if (min <= 0 && max <= 0) - return -EINVAL; - - if (!smu_clk_dpm_is_enabled(smu, clk_type)) + if (atomic_read(&power_gate->vcn_gated) ^ enable) 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_SetHardMaxByFreq, - param, NULL); - 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_SetHardMinByFreq, - param, NULL); - if (ret) - return ret; - } - + ret = smu->ppt_funcs->dpm_set_vcn_enable(smu, enable); + if (!ret) + atomic_set(&power_gate->vcn_gated, !enable); return ret; } -int smu_get_dpm_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t *min, uint32_t *max, bool lock_needed) +static int smu_dpm_set_vcn_enable(struct smu_context *smu, + bool enable) { - uint32_t clock_limit; + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; int ret = 0; - if (!min && !max) - return -EINVAL; + mutex_lock(&power_gate->vcn_gate_lock); - if (lock_needed) - mutex_lock(&smu->mutex); + ret = smu_dpm_set_vcn_enable_locked(smu, enable); - if (!smu_clk_dpm_is_enabled(smu, clk_type)) { - switch (clk_type) { - case SMU_MCLK: - case SMU_UCLK: - clock_limit = smu->smu_table.boot_values.uclk; - break; - case SMU_GFXCLK: - case SMU_SCLK: - clock_limit = smu->smu_table.boot_values.gfxclk; - break; - case SMU_SOCCLK: - clock_limit = smu->smu_table.boot_values.socclk; - break; - default: - clock_limit = 0; - break; - } - - /* clock in Mhz unit */ - if (min) - *min = clock_limit / 100; - if (max) - *max = clock_limit / 100; - } 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 (lock_needed) - mutex_unlock(&smu->mutex); + mutex_unlock(&power_gate->vcn_gate_lock); return ret; } -int smu_get_dpm_freq_by_index(struct smu_context *smu, enum smu_clk_type clk_type, - uint16_t level, uint32_t *value) +static int smu_dpm_set_jpeg_enable_locked(struct smu_context *smu, + bool enable) { - int ret = 0, clk_id = 0; - uint32_t param; - - if (!value) - return -EINVAL; + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int ret = 0; - if (!smu_clk_dpm_is_enabled(smu, clk_type)) + if (!smu->ppt_funcs->dpm_set_jpeg_enable) return 0; - clk_id = smu_clk_get_index(smu, clk_type); - if (clk_id < 0) - return clk_id; - - param = (uint32_t)(((clk_id & 0xffff) << 16) | (level & 0xffff)); - - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDpmFreqByIndex, - param, value); - if (ret) - return ret; + if (atomic_read(&power_gate->jpeg_gated) ^ enable) + return 0; - /* BIT31: 0 - Fine grained DPM, 1 - Dicrete DPM - * now, we un-support it */ - *value = *value & 0x7fffffff; + ret = smu->ppt_funcs->dpm_set_jpeg_enable(smu, enable); + if (!ret) + atomic_set(&power_gate->jpeg_gated, !enable); return ret; } -int smu_get_dpm_level_count(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t *value) -{ - 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) +static int smu_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; - uint32_t level_count = 0; - if (!min_value && !max_value) - return -EINVAL; + mutex_lock(&power_gate->jpeg_gate_lock); - 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; - } + ret = smu_dpm_set_jpeg_enable_locked(smu, enable); - 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; - } + mutex_unlock(&power_gate->jpeg_gate_lock); 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; - - switch (clk_type) { - case SMU_MCLK: - case SMU_UCLK: - feature_id = SMU_FEATURE_DPM_UCLK_BIT; - break; - case SMU_GFXCLK: - case SMU_SCLK: - feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; - break; - case SMU_SOCCLK: - feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; - break; - default: - return true; - } - - if(!smu_feature_is_enabled(smu, feature_id)) { - return false; - } - - return true; -} - /** * smu_dpm_set_power_gate - power gate/ungate the specific IP block * @@ -437,30 +222,44 @@ bool smu_clk_dpm_is_enabled(struct smu_context *smu, enum smu_clk_type clk_type) int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, bool gate) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; switch (block_type) { + /* + * Some legacy code of amdgpu_vcn.c and vcn_v2*.c still uses + * AMD_IP_BLOCK_TYPE_UVD for VCN. So, here both of them are kept. + */ case AMD_IP_BLOCK_TYPE_UVD: - ret = smu_dpm_set_uvd_enable(smu, !gate); - break; - case AMD_IP_BLOCK_TYPE_VCE: - ret = smu_dpm_set_vce_enable(smu, !gate); + case AMD_IP_BLOCK_TYPE_VCN: + ret = smu_dpm_set_vcn_enable(smu, !gate); + if (ret) + dev_err(smu->adev->dev, "Failed to power %s VCN!\n", + gate ? "gate" : "ungate"); break; case AMD_IP_BLOCK_TYPE_GFX: ret = smu_gfx_off_control(smu, gate); + if (ret) + dev_err(smu->adev->dev, "Failed to %s gfxoff!\n", + gate ? "enable" : "disable"); break; case AMD_IP_BLOCK_TYPE_SDMA: ret = smu_powergate_sdma(smu, gate); + if (ret) + dev_err(smu->adev->dev, "Failed to power %s SDMA!\n", + gate ? "gate" : "ungate"); break; case AMD_IP_BLOCK_TYPE_JPEG: ret = smu_dpm_set_jpeg_enable(smu, !gate); + if (ret) + dev_err(smu->adev->dev, "Failed to power %s JPEG!\n", + gate ? "gate" : "ungate"); break; default: - break; + dev_err(smu->adev->dev, "Unsupported block type!\n"); + return -EINVAL; } return ret; @@ -480,108 +279,9 @@ int smu_get_power_num_states(struct smu_context *smu, return 0; } -int smu_common_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, - void *data, uint32_t *size) -{ - struct smu_power_context *smu_power = &smu->smu_power; - 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; - *size = 4; - break; - case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK: - *((uint32_t *)data) = smu->pstate_mclk; - *size = 4; - break; - case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: - ret = smu_feature_get_enabled_mask(smu, (uint32_t *)data, 2); - *size = 8; - break; - case AMDGPU_PP_SENSOR_UVD_POWER: - *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT) ? 1 : 0; - *size = 4; - break; - case AMDGPU_PP_SENSOR_VCE_POWER: - *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT) ? 1 : 0; - *size = 4; - break; - case AMDGPU_PP_SENSOR_VCN_POWER_STATE: - *(uint32_t *)data = power_gate->vcn_gated ? 0 : 1; - *size = 4; - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - *size = 0; - - return ret; -} - -int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int argument, - void *table_data, bool drv2smu) -{ - struct smu_table_context *smu_table = &smu->smu_table; - 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_COUNT || table_id < 0) - return -EINVAL; - - table_size = smu_table->tables[table_index].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, drv2smu ? - SMU_MSG_TransferTableDram2Smu : - SMU_MSG_TransferTableSmu2Dram, - table_id | ((argument & 0xFFFF) << 16), - NULL); - if (ret) - return ret; - - if (!drv2smu) { - amdgpu_asic_flush_hdp(adev, NULL); - memcpy(table_data, table->cpu_addr, table_size); - } - - return ret; -} - 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_ARCTURUS) { - if (amdgpu_sriov_is_pp_one_vf(adev) || !amdgpu_sriov_vf(adev)) - return true; - } - 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) + if (adev->asic_type >= CHIP_ARCTURUS) return true; return false; @@ -590,11 +290,10 @@ bool is_support_sw_smu_xgmi(struct amdgpu_device *adev) int smu_sys_get_pp_table(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; - struct amdgpu_device *adev = smu->adev; uint32_t powerplay_table_size; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!smu_table->power_play_table && !smu_table->hardcode_pptable) return -EINVAL; @@ -616,15 +315,14 @@ 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) { struct smu_table_context *smu_table = &smu->smu_table; - struct amdgpu_device *adev = smu->adev; ATOM_COMMON_TABLE_HEADER *header = (ATOM_COMMON_TABLE_HEADER *)buf; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (header->usStructureSize != size) { - pr_err("pp table size not matched !\n"); + dev_err(smu->adev->dev, "pp table size not matched !\n"); return -EIO; } @@ -648,7 +346,7 @@ int smu_sys_set_pp_table(struct smu_context *smu, void *buf, size_t size) ret = smu_reset(smu); if (ret) - pr_info("smu reset failed, ret = %d\n", ret); + dev_info(smu->adev->dev, "smu reset failed, ret = %d\n", ret); smu->uploading_custom_pp_table = false; @@ -657,7 +355,7 @@ failed: return ret; } -int smu_feature_init_dpm(struct smu_context *smu) +static int smu_get_driver_allowed_feature_mask(struct smu_context *smu) { struct smu_feature *feature = &smu->smu_feature; int ret = 0; @@ -681,88 +379,6 @@ 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; - 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); - - mutex_lock(&feature->mutex); - ret = test_bit(feature_id, feature->enabled); - mutex_unlock(&feature->mutex); - - return ret; -} - -int smu_feature_set_enabled(struct smu_context *smu, enum smu_feature_mask mask, - bool enable) -{ - struct smu_feature *feature = &smu->smu_feature; - int feature_id; - - feature_id = smu_feature_get_index(smu, mask); - if (feature_id < 0) - return -EINVAL; - - WARN_ON(feature_id > feature->feature_num); - - 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; - 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); - - mutex_lock(&feature->mutex); - ret = test_bit(feature_id, feature->supported); - mutex_unlock(&feature->mutex); - - return ret; -} - -int smu_feature_set_supported(struct smu_context *smu, - enum smu_feature_mask mask, - bool enable) -{ - struct smu_feature *feature = &smu->smu_feature; - 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); - - mutex_lock(&feature->mutex); - if (enable) - test_and_set_bit(feature_id, feature->supported); - else - test_and_clear_bit(feature_id, feature->supported); - mutex_unlock(&feature->mutex); - - return ret; -} - static int smu_set_funcs(struct amdgpu_device *adev) { struct smu_context *smu = &adev->smu; @@ -771,10 +387,6 @@ static int smu_set_funcs(struct amdgpu_device *adev) 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: case CHIP_NAVI14: case CHIP_NAVI12: @@ -786,6 +398,10 @@ static int smu_set_funcs(struct amdgpu_device *adev) /* OD is not supported on Arcturus */ smu->od_enabled =false; break; + case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: + sienna_cichlid_set_ppt_funcs(smu); + break; case CHIP_RENOIR: renoir_set_ppt_funcs(smu); break; @@ -809,14 +425,85 @@ static int smu_early_init(void *handle) return smu_set_funcs(adev); } +static int smu_set_default_dpm_table(struct smu_context *smu) +{ + struct smu_power_context *smu_power = &smu->smu_power; + struct smu_power_gate *power_gate = &smu_power->power_gate; + int vcn_gate, jpeg_gate; + int ret = 0; + + if (!smu->ppt_funcs->set_default_dpm_table) + return 0; + + mutex_lock(&power_gate->vcn_gate_lock); + mutex_lock(&power_gate->jpeg_gate_lock); + + vcn_gate = atomic_read(&power_gate->vcn_gated); + jpeg_gate = atomic_read(&power_gate->jpeg_gated); + + ret = smu_dpm_set_vcn_enable_locked(smu, true); + if (ret) + goto err0_out; + + ret = smu_dpm_set_jpeg_enable_locked(smu, true); + if (ret) + goto err1_out; + + ret = smu->ppt_funcs->set_default_dpm_table(smu); + if (ret) + dev_err(smu->adev->dev, + "Failed to setup default dpm clock tables!\n"); + + smu_dpm_set_jpeg_enable_locked(smu, !jpeg_gate); +err1_out: + smu_dpm_set_vcn_enable_locked(smu, !vcn_gate); +err0_out: + mutex_unlock(&power_gate->jpeg_gate_lock); + mutex_unlock(&power_gate->vcn_gate_lock); + + return ret; +} + static int smu_late_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = &adev->smu; + int ret = 0; if (!smu->pm_enabled) return 0; + ret = smu_set_default_od_settings(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup default OD settings!\n"); + return ret; + } + + /* + * Set initialized values (get from vbios) to dpm tables context such as + * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each + * type of clks. + */ + ret = smu_set_default_dpm_table(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup default dpm clock tables!\n"); + return ret; + } + + ret = smu_populate_umd_state_clk(smu); + if (ret) { + dev_err(adev->dev, "Failed to populate UMD state clocks!\n"); + return ret; + } + + ret = smu_get_asic_power_limits(smu); + if (ret) { + dev_err(adev->dev, "Failed to get asic power limits!\n"); + return ret; + } + + smu_get_unique_id(smu); + smu_handle_task(&adev->smu, smu->smu_dpm.dpm_level, AMD_PP_TASK_COMPLETE_INIT, @@ -825,45 +512,160 @@ static int smu_late_init(void *handle) return 0; } -int smu_get_atom_data_table(struct smu_context *smu, uint32_t table, - uint16_t *size, uint8_t *frev, uint8_t *crev, - uint8_t **addr) +static int smu_init_fb_allocations(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; - uint16_t data_start; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + struct smu_table *driver_table = &(smu_table->driver_table); + uint32_t max_table_size = 0; + int ret, i; - if (!amdgpu_atom_parse_data_header(adev->mode_info.atom_context, table, - size, frev, crev, &data_start)) - return -EINVAL; + /* VRAM allocation for tool table */ + if (tables[SMU_TABLE_PMSTATUSLOG].size) { + ret = amdgpu_bo_create_kernel(adev, + 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) { + dev_err(adev->dev, "VRAM allocation for tool table failed!\n"); + return ret; + } + } - *addr = (uint8_t *)adev->mode_info.atom_context->bios + data_start; + /* VRAM allocation for driver table */ + for (i = 0; i < SMU_TABLE_COUNT; i++) { + if (tables[i].size == 0) + continue; - return 0; + 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) { + dev_err(adev->dev, "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; } -static int smu_initialize_pptable(struct smu_context *smu) +static int smu_fini_fb_allocations(struct smu_context *smu) { - /* TODO */ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + struct smu_table *driver_table = &(smu_table->driver_table); + + if (!tables) + 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); + + amdgpu_bo_free_kernel(&driver_table->bo, + &driver_table->mc_address, + &driver_table->cpu_addr); + return 0; } -static int smu_smc_table_sw_init(struct smu_context *smu) +/** + * smu_alloc_memory_pool - allocate memory pool in the system memory + * + * @smu: amdgpu_device pointer + * + * This memory pool will be used for SMC use and msg SetSystemVirtualDramAddr + * and DramLogSetDramAddr can notify it changed. + * + * Returns 0 on success, error on failure. + */ +static int smu_alloc_memory_pool(struct smu_context *smu) { - int ret; + struct amdgpu_device *adev = smu->adev; + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *memory_pool = &smu_table->memory_pool; + uint64_t pool_size = smu->pool_size; + int ret = 0; - ret = smu_initialize_pptable(smu); - if (ret) { - pr_err("Failed to init smu_initialize_pptable!\n"); + if (pool_size == SMU_MEMORY_POOL_SIZE_ZERO) return ret; + + memory_pool->size = pool_size; + memory_pool->align = PAGE_SIZE; + memory_pool->domain = AMDGPU_GEM_DOMAIN_GTT; + + switch (pool_size) { + case SMU_MEMORY_POOL_SIZE_256_MB: + case SMU_MEMORY_POOL_SIZE_512_MB: + case SMU_MEMORY_POOL_SIZE_1_GB: + case SMU_MEMORY_POOL_SIZE_2_GB: + ret = amdgpu_bo_create_kernel(adev, + memory_pool->size, + memory_pool->align, + memory_pool->domain, + &memory_pool->bo, + &memory_pool->mc_address, + &memory_pool->cpu_addr); + if (ret) + dev_err(adev->dev, "VRAM allocation for dramlog failed!\n"); + break; + default: + break; } + return ret; +} + +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; + + if (memory_pool->size == SMU_MEMORY_POOL_SIZE_ZERO) + return 0; + + amdgpu_bo_free_kernel(&memory_pool->bo, + &memory_pool->mc_address, + &memory_pool->cpu_addr); + + memset(memory_pool, 0, sizeof(struct smu_table)); + + return 0; +} + +static int smu_smc_table_sw_init(struct smu_context *smu) +{ + int ret; + /** * Create smu_table structure, and init smc tables such as * TABLE_PPTABLE, TABLE_WATERMARKS, TABLE_SMU_METRICS, and etc. */ ret = smu_init_smc_tables(smu); if (ret) { - pr_err("Failed to init smc tables!\n"); + dev_err(smu->adev->dev, "Failed to init smc tables!\n"); return ret; } @@ -873,10 +675,25 @@ static int smu_smc_table_sw_init(struct smu_context *smu) */ ret = smu_init_power(smu); if (ret) { - pr_err("Failed to init smu_init_power!\n"); + dev_err(smu->adev->dev, "Failed to init smu_init_power!\n"); return ret; } + /* + * allocate vram bos to store smc table contents. + */ + ret = smu_init_fb_allocations(smu); + if (ret) + return ret; + + ret = smu_alloc_memory_pool(smu); + if (ret) + return ret; + + ret = smu_i2c_init(smu, &smu->adev->pm.smu_i2c); + if (ret) + return ret; + return 0; } @@ -884,15 +701,39 @@ static int smu_smc_table_sw_fini(struct smu_context *smu) { int ret; + smu_i2c_fini(smu, &smu->adev->pm.smu_i2c); + + ret = smu_free_memory_pool(smu); + if (ret) + return ret; + + ret = smu_fini_fb_allocations(smu); + if (ret) + return ret; + + ret = smu_fini_power(smu); + if (ret) { + dev_err(smu->adev->dev, "Failed to init smu_fini_power!\n"); + return ret; + } + ret = smu_fini_smc_tables(smu); if (ret) { - pr_err("Failed to smu_fini_smc_tables!\n"); + dev_err(smu->adev->dev, "Failed to smu_fini_smc_tables!\n"); return ret; } return 0; } +static void smu_throttling_logging_work_fn(struct work_struct *work) +{ + struct smu_context *smu = container_of(work, struct smu_context, + throttling_logging_work); + + smu_log_thermal_throttling(smu); +} + static int smu_sw_init(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; @@ -914,10 +755,16 @@ static int smu_sw_init(void *handle) mutex_init(&smu->metrics_lock); mutex_init(&smu->message_lock); + INIT_WORK(&smu->throttling_logging_work, smu_throttling_logging_work_fn); 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; + atomic_set(&smu->smu_power.power_gate.vcn_gated, 1); + atomic_set(&smu->smu_power.power_gate.jpeg_gated, 1); + mutex_init(&smu->smu_power.power_gate.vcn_gate_lock); + mutex_init(&smu->smu_power.power_gate.jpeg_gate_lock); + smu->workload_mask = 1 << smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT]; smu->workload_prority[PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT] = 0; smu->workload_prority[PP_SMC_POWER_PROFILE_FULLSCREEN3D] = 1; @@ -940,19 +787,19 @@ static int smu_sw_init(void *handle) smu->smu_dpm.requested_dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; ret = smu_init_microcode(smu); if (ret) { - pr_err("Failed to load smu firmware!\n"); + dev_err(adev->dev, "Failed to load smu firmware!\n"); return ret; } ret = smu_smc_table_sw_init(smu); if (ret) { - pr_err("Failed to sw init smc table!\n"); + dev_err(adev->dev, "Failed to sw init smc table!\n"); return ret; } ret = smu_register_irq_handler(smu); if (ret) { - pr_err("Failed to register smc irq handler!\n"); + dev_err(adev->dev, "Failed to register smc irq handler!\n"); return ret; } @@ -965,346 +812,192 @@ static int smu_sw_fini(void *handle) struct smu_context *smu = &adev->smu; int ret; - kfree(smu->irq_source); - smu->irq_source = NULL; - ret = smu_smc_table_sw_fini(smu); if (ret) { - pr_err("Failed to sw fini smc table!\n"); + dev_err(adev->dev, "Failed to sw fini smc table!\n"); return ret; } - ret = smu_fini_power(smu); - if (ret) { - pr_err("Failed to init smu_fini_power!\n"); - return ret; - } + smu_fini_microcode(smu); return 0; } -static int smu_init_fb_allocations(struct smu_context *smu) +static int smu_get_thermal_temperature_range(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; - struct smu_table *driver_table = &(smu_table->driver_table); - uint32_t max_table_size = 0; - int ret, i; - - /* VRAM allocation for tool table */ - if (tables[SMU_TABLE_PMSTATUSLOG].size) { - ret = amdgpu_bo_create_kernel(adev, - 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; - } - } - - /* VRAM allocation for driver table */ - for (i = 0; i < SMU_TABLE_COUNT; i++) { - if (tables[i].size == 0) - continue; - - 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; -} - -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; - struct smu_table *driver_table = &(smu_table->driver_table); + struct smu_temperature_range *range = + &smu->thermal_range; + int ret = 0; - if (!tables) + if (!smu->ppt_funcs->get_thermal_temperature_range) 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); + ret = smu->ppt_funcs->get_thermal_temperature_range(smu, range); + if (ret) + return ret; - amdgpu_bo_free_kernel(&driver_table->bo, - &driver_table->mc_address, - &driver_table->cpu_addr); + 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 0; + return ret; } -static int smu_smc_table_hw_init(struct smu_context *smu, - bool initialize) +static int smu_smc_hw_setup(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; + uint32_t pcie_gen = 0, pcie_width = 0; int ret; - if (smu_is_dpm_running(smu) && adev->in_suspend) { - pr_info("dpm has been enabled\n"); + if (adev->in_suspend && smu_is_dpm_running(smu)) { + dev_info(adev->dev, "dpm has been enabled\n"); return 0; } - 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. */ - ret = smu_get_vbios_bootup_values(smu); - if (ret) - return ret; - - ret = smu_setup_pptable(smu); - if (ret) - return ret; - - ret = smu_get_clk_info_from_vbios(smu); - if (ret) - return ret; - - /* - * check if the format_revision in vbios is up to pptable header - * version, and the structure size is not 0. - */ - ret = smu_check_pptable(smu); - if (ret) - return ret; - - /* - * allocate vram bos to store smc table contents. - */ - ret = smu_init_fb_allocations(smu); - if (ret) - return ret; - - /* - * Parse pptable format and fill PPTable_t smc_pptable to - * smu_table_context structure. And read the smc_dpm_table from vbios, - * then fill it into smc_pptable. - */ - ret = smu_parse_pptable(smu); - if (ret) - return ret; - - /* - * Send msg GetDriverIfVersion to check if the return value is equal - * with DRIVER_IF_VERSION of smc header. - */ - ret = smu_check_fw_version(smu); - if (ret) - return ret; + ret = smu_init_display_count(smu, 0); + if (ret) { + dev_info(adev->dev, "Failed to pre-set display count as 0!\n"); + return ret; } ret = smu_set_driver_table_location(smu); - if (ret) + if (ret) { + dev_err(adev->dev, "Failed to SetDriverDramAddr!\n"); return ret; - - /* smu_dump_pptable(smu); */ - if (!amdgpu_sriov_vf(adev)) { - /* - * 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 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_system_features_control(smu, true); - 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 (smu->ppt_funcs->set_power_source) { - /* - * For Navi1X, manually switch it to AC mode as PMFW - * may boot it with DC mode. - */ - if (adev->pm.ac_power) - ret = smu_set_power_source(smu, SMU_POWER_SOURCE_AC); - else - ret = smu_set_power_source(smu, SMU_POWER_SOURCE_DC); - if (ret) { - pr_err("Failed to switch to %s mode!\n", adev->pm.ac_power ? "AC" : "DC"); - 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 PMSTATUSLOG table bo address with SetToolsDramAddr MSG for tools. + */ + ret = smu_set_tool_table_location(smu); + if (ret) { + dev_err(adev->dev, "Failed to SetToolsDramAddr!\n"); + return ret; } /* - * Set initialized values (get from vbios) to dpm tables context such as - * gfxclk, memclk, dcefclk, and etc. And enable the DPM feature for each - * type of clks. + * Use msg SetSystemVirtualDramAddr and DramLogSetDramAddr can notify + * pool location. */ - if (initialize) { - ret = smu_populate_smc_tables(smu); - if (ret) - return ret; - - ret = smu_init_max_sustainable_clocks(smu); - if (ret) - return ret; + ret = smu_notify_memory_pool_location(smu); + if (ret) { + dev_err(adev->dev, "Failed to SetDramLogDramAddr!\n"); + return ret; } - if (adev->asic_type != CHIP_ARCTURUS) { - ret = smu_override_pcie_parameters(smu); - if (ret) - return ret; + /* smu_dump_pptable(smu); */ + /* + * Copy pptable bo in the vram to smc with SMU MSGs such as + * SetDriverDramAddr and TransferTableDram2Smu. + */ + ret = smu_write_pptable(smu); + if (ret) { + dev_err(adev->dev, "Failed to transfer pptable to SMC!\n"); + return ret; } - ret = smu_set_default_od_settings(smu, initialize); + /* issue Run*Btc msg */ + ret = smu_run_btc(smu); if (ret) return ret; - if (initialize) { - ret = smu_populate_umd_state_clk(smu); - if (ret) - return ret; + ret = smu_feature_set_allowed_mask(smu); + if (ret) { + dev_err(adev->dev, "Failed to set driver allowed features mask!\n"); + return ret; + } - ret = smu_get_power_limit(smu, &smu->default_power_limit, false, false); - if (ret) - return ret; + ret = smu_system_features_control(smu, true); + if (ret) { + dev_err(adev->dev, "Failed to enable requested dpm features!\n"); + return ret; } - /* - * Set PMSTATUSLOG table bo address with SetToolsDramAddr MSG for tools. + if (!smu_is_dpm_running(smu)) + dev_info(adev->dev, "dpm has been disabled\n"); + + 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 (!amdgpu_sriov_vf(adev)) { - ret = smu_set_tool_table_location(smu); + 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) { + dev_err(adev->dev, "Attempt to override pcie params failed!\n"); + return ret; } - if (!smu_is_dpm_running(smu)) - pr_info("dpm has been disabled\n"); - - return ret; -} - -/** - * smu_alloc_memory_pool - allocate memory pool in the system memory - * - * @smu: amdgpu_device pointer - * - * This memory pool will be used for SMC use and msg SetSystemVirtualDramAddr - * and DramLogSetDramAddr can notify it changed. - * - * Returns 0 on success, error on failure. - */ -static int smu_alloc_memory_pool(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - struct smu_table_context *smu_table = &smu->smu_table; - struct smu_table *memory_pool = &smu_table->memory_pool; - uint64_t pool_size = smu->pool_size; - int ret = 0; - if (pool_size == SMU_MEMORY_POOL_SIZE_ZERO) + ret = smu_get_thermal_temperature_range(smu); + if (ret) { + dev_err(adev->dev, "Failed to get thermal temperature ranges!\n"); return ret; - - memory_pool->size = pool_size; - memory_pool->align = PAGE_SIZE; - memory_pool->domain = AMDGPU_GEM_DOMAIN_GTT; - - switch (pool_size) { - case SMU_MEMORY_POOL_SIZE_256_MB: - case SMU_MEMORY_POOL_SIZE_512_MB: - case SMU_MEMORY_POOL_SIZE_1_GB: - case SMU_MEMORY_POOL_SIZE_2_GB: - ret = amdgpu_bo_create_kernel(adev, - memory_pool->size, - memory_pool->align, - memory_pool->domain, - &memory_pool->bo, - &memory_pool->mc_address, - &memory_pool->cpu_addr); - break; - default: - break; } - return ret; -} + ret = smu_enable_thermal_alert(smu); + if (ret) { + dev_err(adev->dev, "Failed to enable thermal alert!\n"); + return ret; + } -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; + ret = smu_disable_umc_cdr_12gbps_workaround(smu); + if (ret) { + dev_err(adev->dev, "Workaround failed to disable UMC CDR feature on 12Gbps SKU!\n"); + return ret; + } - if (memory_pool->size == SMU_MEMORY_POOL_SIZE_ZERO) - return 0; + /* + * For Navi1X, manually switch it to AC mode as PMFW + * may boot it with DC mode. + */ + ret = smu_set_power_source(smu, + adev->pm.ac_power ? SMU_POWER_SOURCE_AC : + SMU_POWER_SOURCE_DC); + if (ret) { + dev_err(adev->dev, "Failed to switch to %s mode!\n", adev->pm.ac_power ? "AC" : "DC"); + return ret; + } - amdgpu_bo_free_kernel(&memory_pool->bo, - &memory_pool->mc_address, - &memory_pool->cpu_addr); + ret = smu_notify_display_change(smu); + if (ret) + return ret; - memset(memory_pool, 0, sizeof(struct smu_table)); + /* + * Set min deep sleep dce fclk with bootup value from vbios via + * SetMinDeepSleepDcefclk MSG. + */ + ret = smu_set_min_dcef_deep_sleep(smu, + smu->smu_table.boot_values.dcefclk / 100); + if (ret) + return ret; - return 0; + return ret; } static int smu_start_smc_engine(struct smu_context *smu) @@ -1324,10 +1017,20 @@ static int smu_start_smc_engine(struct smu_context *smu) if (smu->ppt_funcs->check_fw_status) { ret = smu->ppt_funcs->check_fw_status(smu); - if (ret) - pr_err("SMC is not ready\n"); + if (ret) { + dev_err(adev->dev, "SMC is not ready\n"); + return ret; + } } + /* + * Send msg GetDriverIfVersion to check if the return value is equal + * with DRIVER_IF_VERSION of smc header. + */ + ret = smu_check_fw_version(smu); + if (ret) + return ret; + return ret; } @@ -1337,76 +1040,151 @@ static int smu_hw_init(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)) + if (amdgpu_sriov_vf(adev) && !amdgpu_sriov_is_pp_one_vf(adev)) { + smu->pm_enabled = false; return 0; + } ret = smu_start_smc_engine(smu); if (ret) { - pr_err("SMU is not ready yet!\n"); + dev_err(adev->dev, "SMC engine is not correctly up!\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_dpm_set_vcn_enable(smu, true); + smu_dpm_set_jpeg_enable(smu, true); smu_set_gfx_cgpg(&adev->smu, true); } if (!smu->pm_enabled) return 0; - ret = smu_feature_init_dpm(smu); - if (ret) - goto failed; + /* get boot_values from vbios to set revision, gfxclk, and etc. */ + ret = smu_get_vbios_bootup_values(smu); + if (ret) { + dev_err(adev->dev, "Failed to get VBIOS boot clock values!\n"); + return ret; + } - ret = smu_smc_table_hw_init(smu, true); - if (ret) - goto failed; + ret = smu_setup_pptable(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup pptable!\n"); + return ret; + } - ret = smu_alloc_memory_pool(smu); + ret = smu_get_driver_allowed_feature_mask(smu); if (ret) - goto failed; + return ret; + + ret = smu_smc_hw_setup(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup smc hw!\n"); + return ret; + } /* - * Use msg SetSystemVirtualDramAddr and DramLogSetDramAddr can notify - * pool location. + * Move maximum sustainable clock retrieving here considering + * 1. It is not needed on resume(from S3). + * 2. DAL settings come between .hw_init and .late_init of SMU. + * And DAL needs to know the maximum sustainable clocks. Thus + * it cannot be put in .late_init(). */ - ret = smu_notify_memory_pool_location(smu); - if (ret) - goto failed; - - ret = smu_start_thermal_control(smu); - if (ret) - goto failed; - - ret = smu_i2c_eeprom_init(smu, &adev->pm.smu_i2c); - if (ret) - goto failed; + ret = smu_init_max_sustainable_clocks(smu); + if (ret) { + dev_err(adev->dev, "Failed to init max sustainable clocks!\n"); + return ret; + } adev->pm.dpm_enabled = true; - pr_info("SMU is initialized successfully!\n"); + dev_info(adev->dev, "SMU is initialized successfully!\n"); return 0; +} + +static int smu_disable_dpms(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + bool use_baco = !smu->is_apu && + ((adev->in_gpu_reset && + (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || + ((adev->in_runpm || adev->in_hibernate) && amdgpu_asic_supports_baco(adev))); + + /* + * 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)) + return 0; + + /* + * For Sienna_Cichlid, PMFW will handle the features disablement properly + * on BACO in. Driver involvement is unnecessary. + */ + if ((adev->asic_type == CHIP_SIENNA_CICHLID) && + use_baco) + return 0; + + /* + * For gpu reset, runpm and hibernation through BACO, + * BACO feature has to be kept enabled. + */ + if (use_baco && smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) { + ret = smu_disable_all_features_with_exception(smu, + SMU_FEATURE_BACO_BIT); + if (ret) + dev_err(adev->dev, "Failed to disable smu features except BACO.\n"); + } else { + ret = smu_system_features_control(smu, false); + if (ret) + dev_err(adev->dev, "Failed to disable smu features.\n"); + } + + if (adev->asic_type >= CHIP_NAVI10 && + adev->gfx.rlc.funcs->stop) + adev->gfx.rlc.funcs->stop(adev); -failed: return ret; } -static int smu_stop_dpms(struct smu_context *smu) +static int smu_smc_hw_cleanup(struct smu_context *smu) { - if (amdgpu_sriov_vf(smu->adev)) - return 0; + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + cancel_work_sync(&smu->throttling_logging_work); - return smu_system_features_control(smu, false); + ret = smu_disable_thermal_alert(smu); + if (ret) { + dev_err(adev->dev, "Fail to disable thermal alert!\n"); + return ret; + } + + ret = smu_disable_dpms(smu); + if (ret) { + dev_err(adev->dev, "Fail to disable dpm features!\n"); + return ret; + } + + return 0; } static int smu_hw_fini(void *handle) { struct amdgpu_device *adev = (struct amdgpu_device *)handle; struct smu_context *smu = &adev->smu; - struct smu_table_context *table_context = &smu->smu_table; int ret = 0; if (amdgpu_sriov_vf(adev)&& !amdgpu_sriov_is_pp_one_vf(adev)) @@ -1414,8 +1192,8 @@ static int smu_hw_fini(void *handle) if (smu->is_apu) { smu_powergate_sdma(&adev->smu, true); - smu_powergate_vcn(&adev->smu, true); - smu_powergate_jpeg(&adev->smu, true); + smu_dpm_set_vcn_enable(smu, false); + smu_dpm_set_jpeg_enable(smu, false); } if (!smu->pm_enabled) @@ -1423,51 +1201,7 @@ static int smu_hw_fini(void *handle) adev->pm.dpm_enabled = false; - smu_i2c_eeprom_fini(smu, &adev->pm.smu_i2c); - - 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; - - kfree(table_context->max_sustainable_clocks); - table_context->max_sustainable_clocks = NULL; - - kfree(table_context->overdrive_table); - table_context->overdrive_table = NULL; - - ret = smu_fini_fb_allocations(smu); - if (ret) - return ret; - - ret = smu_free_memory_pool(smu); + ret = smu_smc_hw_cleanup(smu); if (ret) return ret; @@ -1487,67 +1221,7 @@ int smu_reset(struct smu_context *smu) if (ret) return ret; - return ret; -} - -static int smu_disable_dpm(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t smu_version; - int ret = 0; - bool use_baco = !smu->is_apu && - ((adev->in_gpu_reset && - (amdgpu_asic_reset_method(adev) == AMD_RESET_METHOD_BACO)) || - ((adev->in_runpm || adev->in_hibernate) && amdgpu_asic_supports_baco(adev))); - - ret = smu_get_smc_version(smu, NULL, &smu_version); - if (ret) { - pr_err("Failed to get smu version.\n"); - return ret; - } - - /* - * Disable all enabled SMU features. - * This should be handled in SMU FW, as a backup - * driver can issue call to SMU FW until sequence - * in SMU FW is operational. - */ - ret = smu_system_features_control(smu, false); - if (ret) { - pr_err("Failed to disable smu features.\n"); - return ret; - } - - /* - * Arcturus does not have BACO bit in disable feature mask. - * Enablement of BACO bit on Arcturus should be skipped. - */ - if (adev->asic_type == CHIP_ARCTURUS) { - if (use_baco && (smu_version > 0x360e00)) - return 0; - } - - /* For baco, need to leave BACO feature enabled */ - if (use_baco) { - /* - * Correct the way for checking whether SMU_FEATURE_BACO_BIT - * is supported. - * - * Since 'smu_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)' will - * always return false as the 'smu_system_features_control(smu, false)' - * was just issued above which disabled all SMU features. - * - * Thus 'smu_feature_get_index(smu, SMU_FEATURE_BACO_BIT)' is used - * now for the checking. - */ - if (smu_feature_get_index(smu, SMU_FEATURE_BACO_BIT) >= 0) { - ret = smu_feature_set_enabled(smu, SMU_FEATURE_BACO_BIT, true); - if (ret) { - pr_warn("set BACO feature enabled failed, return %d\n", ret); - return ret; - } - } - } + ret = smu_late_init(adev); return ret; } @@ -1566,19 +1240,12 @@ static int smu_suspend(void *handle) adev->pm.dpm_enabled = false; - smu_i2c_eeprom_fini(smu, &adev->pm.smu_i2c); - - if(!amdgpu_sriov_vf(adev)) { - ret = smu_disable_dpm(smu); - if (ret) - return ret; - } + ret = smu_smc_hw_cleanup(smu); + if (ret) + return ret; smu->watermarks_bitmap &= ~(WATERMARKS_LOADED); - 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); @@ -1597,25 +1264,19 @@ static int smu_resume(void *handle) if (!smu->pm_enabled) return 0; - pr_info("SMU is resuming...\n"); + dev_info(adev->dev, "SMU is resuming...\n"); ret = smu_start_smc_engine(smu); if (ret) { - pr_err("SMU is not ready yet!\n"); - goto failed; + dev_err(adev->dev, "SMC engine is not correctly up!\n"); + return ret; } - ret = smu_smc_table_hw_init(smu, false); - if (ret) - goto failed; - - ret = smu_start_thermal_control(smu); - if (ret) - goto failed; - - ret = smu_i2c_eeprom_init(smu, &adev->pm.smu_i2c); - if (ret) - goto failed; + ret = smu_smc_hw_setup(smu); + if (ret) { + dev_err(adev->dev, "Failed to setup smc hw!\n"); + return ret; + } if (smu->is_apu) smu_set_gfx_cgpg(&adev->smu, true); @@ -1624,35 +1285,27 @@ static int smu_resume(void *handle) adev->pm.dpm_enabled = true; - pr_info("SMU is resumed successfully!\n"); + dev_info(adev->dev, "SMU is resumed successfully!\n"); return 0; - -failed: - return ret; } int smu_display_configuration_change(struct smu_context *smu, const struct amd_pp_display_configuration *display_config) { - struct amdgpu_device *adev = smu->adev; int index = 0; int num_of_active_display = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; - - if (!is_support_sw_smu(smu->adev)) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!display_config) return -EINVAL; mutex_lock(&smu->mutex); - 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); + smu_set_min_dcef_deep_sleep(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) @@ -1704,15 +1357,11 @@ int smu_get_current_clocks(struct smu_context *smu, struct amd_pp_clock_info *clocks) { struct amd_pp_simple_clock_info simple_clocks = {0}; - struct amdgpu_device *adev = smu->adev; struct smu_clock_info hw_clocks; int ret = 0; - if (!is_support_sw_smu(smu->adev)) - return -EINVAL; - - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -1725,7 +1374,7 @@ int smu_get_current_clocks(struct smu_context *smu, ret = smu_get_clock_info(smu, &hw_clocks, PERF_LEVEL_ACTIVITY); if (ret) { - pr_err("Error in smu_get_clock_info\n"); + dev_err(smu->adev->dev, "Error in smu_get_clock_info\n"); goto failed; } @@ -1809,7 +1458,7 @@ static int smu_enable_umd_pstate(void *handle, return 0; } -int smu_adjust_power_state_dynamic(struct smu_context *smu, +static int smu_adjust_power_state_dynamic(struct smu_context *smu, enum amd_dpm_forced_level level, bool skip_display_settings) { @@ -1821,21 +1470,21 @@ int smu_adjust_power_state_dynamic(struct smu_context *smu, if (!skip_display_settings) { ret = smu_display_config_changed(smu); if (ret) { - pr_err("Failed to change display config!"); + dev_err(smu->adev->dev, "Failed to change display config!"); return ret; } } ret = smu_apply_clocks_adjust_rules(smu); if (ret) { - pr_err("Failed to apply clocks adjust rules!"); + dev_err(smu->adev->dev, "Failed to apply clocks adjust rules!"); return ret; } if (!skip_display_settings) { ret = smu_notify_smc_display_config(smu); if (ret) { - pr_err("Failed to notify smc display config!"); + dev_err(smu->adev->dev, "Failed to notify smc display config!"); return ret; } } @@ -1843,7 +1492,7 @@ 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) { - pr_err("Failed to set performance level!"); + dev_err(smu->adev->dev, "Failed to set performance level!"); return ret; } @@ -1868,11 +1517,10 @@ int smu_handle_task(struct smu_context *smu, enum amd_pp_task task_id, bool lock_needed) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (lock_needed) mutex_lock(&smu->mutex); @@ -1907,12 +1555,11 @@ int smu_switch_power_profile(struct smu_context *smu, bool en) { struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - struct amdgpu_device *adev = smu->adev; long workload; uint32_t index; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!(type < PP_SMC_POWER_PROFILE_CUSTOM)) return -EINVAL; @@ -1942,11 +1589,10 @@ int smu_switch_power_profile(struct smu_context *smu, enum amd_dpm_forced_level smu_get_performance_level(struct smu_context *smu) { struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - struct amdgpu_device *adev = smu->adev; enum amd_dpm_forced_level level; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!smu->is_apu && !smu_dpm_ctx->dpm_context) return -EINVAL; @@ -1961,11 +1607,10 @@ 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) { struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!smu->is_apu && !smu_dpm_ctx->dpm_context) return -EINVAL; @@ -1989,11 +1634,10 @@ int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_lev int smu_set_display_count(struct smu_context *smu, uint32_t count) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); ret = smu_init_display_count(smu, count); @@ -2004,29 +1648,25 @@ int smu_set_display_count(struct smu_context *smu, uint32_t count) int smu_force_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t mask, - bool lock_needed) + uint32_t mask) { struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { - pr_debug("force clock level is for dpm manual mode only.\n"); + dev_dbg(smu->adev->dev, "force clock level is for dpm manual mode only.\n"); return -EINVAL; } - if (lock_needed) - mutex_lock(&smu->mutex); + 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); + mutex_unlock(&smu->mutex); return ret; } @@ -2044,6 +1684,9 @@ int smu_set_mp1_state(struct smu_context *smu, uint16_t msg; int ret; + if (!smu->pm_enabled) + return -EOPNOTSUPP; + mutex_lock(&smu->mutex); switch (mp1_state) { @@ -2062,15 +1705,12 @@ int smu_set_mp1_state(struct smu_context *smu, 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, NULL); + /* some asics may not support those messages */ + if (ret == -EINVAL) + ret = 0; if (ret) - pr_err("[PrepareMp1] Failed!\n"); + dev_err(smu->adev->dev, "[PrepareMp1] Failed!\n"); mutex_unlock(&smu->mutex); @@ -2080,11 +1720,10 @@ int smu_set_mp1_state(struct smu_context *smu, int smu_set_df_cstate(struct smu_context *smu, enum pp_df_cstate state) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!smu->ppt_funcs || !smu->ppt_funcs->set_df_cstate) return 0; @@ -2093,7 +1732,7 @@ int smu_set_df_cstate(struct smu_context *smu, ret = smu->ppt_funcs->set_df_cstate(smu, state); if (ret) - pr_err("[SetDfCstate] failed!\n"); + dev_err(smu->adev->dev, "[SetDfCstate] failed!\n"); mutex_unlock(&smu->mutex); @@ -2102,11 +1741,10 @@ int smu_set_df_cstate(struct smu_context *smu, int smu_allow_xgmi_power_down(struct smu_context *smu, bool en) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (!smu->ppt_funcs || !smu->ppt_funcs->allow_xgmi_power_down) return 0; @@ -2115,7 +1753,7 @@ int smu_allow_xgmi_power_down(struct smu_context *smu, bool en) ret = smu->ppt_funcs->allow_xgmi_power_down(smu, en); if (ret) - pr_err("[AllowXgmiPowerDown] failed!\n"); + dev_err(smu->adev->dev, "[AllowXgmiPowerDown] failed!\n"); mutex_unlock(&smu->mutex); @@ -2124,36 +1762,34 @@ int smu_allow_xgmi_power_down(struct smu_context *smu, bool en) int smu_write_watermarks_table(struct smu_context *smu) { - void *watermarks_table = smu->smu_table.watermarks_table; + int ret = 0; - if (!watermarks_table) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; - return smu_update_table(smu, - SMU_TABLE_WATERMARKS, - 0, - watermarks_table, - true); + mutex_lock(&smu->mutex); + + ret = smu_set_watermarks_table(smu, NULL); + + mutex_unlock(&smu->mutex); + + return ret; } 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; - struct amdgpu_device *adev = smu->adev; - - if (!adev->pm.dpm_enabled) - return -EINVAL; + int ret = 0; - if (!table) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; 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); + ret = smu_set_watermarks_table(smu, clock_ranges); if (!(smu->watermarks_bitmap & WATERMARKS_EXIST)) { smu->watermarks_bitmap |= WATERMARKS_EXIST; @@ -2163,31 +1799,27 @@ int smu_set_watermarks_for_clock_ranges(struct smu_context *smu, mutex_unlock(&smu->mutex); - return 0; + return ret; } int smu_set_ac_dc(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; /* controlled by firmware */ if (smu->dc_controlled_by_gpio) return 0; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_power_source) { - if (smu->adev->pm.ac_power) - ret = smu_set_power_source(smu, SMU_POWER_SOURCE_AC); - else - ret = smu_set_power_source(smu, SMU_POWER_SOURCE_DC); - if (ret) - pr_err("Failed to switch to %s mode!\n", - smu->adev->pm.ac_power ? "AC" : "DC"); - } + ret = smu_set_power_source(smu, + smu->adev->pm.ac_power ? SMU_POWER_SOURCE_AC : + SMU_POWER_SOURCE_DC); + if (ret) + dev_err(smu->adev->dev, "Failed to switch to %s mode!\n", + smu->adev->pm.ac_power ? "AC" : "DC"); mutex_unlock(&smu->mutex); return ret; @@ -2232,11 +1864,10 @@ const struct amdgpu_ip_block_version smu_v12_0_ip_block = int smu_load_microcode(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2250,11 +1881,10 @@ int smu_load_microcode(struct smu_context *smu) int smu_check_fw_status(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2282,11 +1912,10 @@ int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2300,41 +1929,43 @@ 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) + bool max_setting) { - struct amdgpu_device *adev = smu->adev; - int ret = 0; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; - if (lock_needed) { - if (!adev->pm.dpm_enabled) - return -EINVAL; - - mutex_lock(&smu->mutex); - } + mutex_lock(&smu->mutex); - if (smu->ppt_funcs->get_power_limit) - ret = smu->ppt_funcs->get_power_limit(smu, limit, def); + *limit = (max_setting ? smu->max_power_limit : smu->current_power_limit); - if (lock_needed) - mutex_unlock(&smu->mutex); + mutex_unlock(&smu->mutex); - return ret; + return 0; } int smu_set_power_limit(struct smu_context *smu, uint32_t limit) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); + if (limit > smu->max_power_limit) { + dev_err(smu->adev->dev, + "New power limit (%d) is over the max allowed %d\n", + limit, smu->max_power_limit); + goto out; + } + + if (!limit) + limit = smu->current_power_limit; + if (smu->ppt_funcs->set_power_limit) ret = smu->ppt_funcs->set_power_limit(smu, limit); +out: mutex_unlock(&smu->mutex); return ret; @@ -2342,11 +1973,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2360,11 +1990,10 @@ int smu_print_clk_levels(struct smu_context *smu, enum smu_clk_type clk_type, ch int smu_get_od_percentage(struct smu_context *smu, enum smu_clk_type type) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2378,11 +2007,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2398,16 +2026,21 @@ int smu_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long *input, uint32_t size) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->od_edit_dpm_table) + if (smu->ppt_funcs->od_edit_dpm_table) { ret = smu->ppt_funcs->od_edit_dpm_table(smu, type, input, size); + if (!ret && (type == PP_OD_COMMIT_DPM_TABLE)) + ret = smu_handle_task(smu, + smu->smu_dpm.dpm_level, + AMD_PP_TASK_READJUST_POWER_STATE, + false); + } mutex_unlock(&smu->mutex); @@ -2418,17 +2051,58 @@ int smu_read_sensor(struct smu_context *smu, enum amd_pp_sensors sensor, void *data, uint32_t *size) { - struct amdgpu_device *adev = smu->adev; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; int ret = 0; - if (!adev->pm.dpm_enabled) + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; + + if (!data || !size) return -EINVAL; mutex_lock(&smu->mutex); if (smu->ppt_funcs->read_sensor) - ret = smu->ppt_funcs->read_sensor(smu, sensor, data, size); + if (!smu->ppt_funcs->read_sensor(smu, sensor, data, size)) + goto unlock; + switch (sensor) { + case AMDGPU_PP_SENSOR_STABLE_PSTATE_SCLK: + *((uint32_t *)data) = pstate_table->gfxclk_pstate.standard * 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_STABLE_PSTATE_MCLK: + *((uint32_t *)data) = pstate_table->uclk_pstate.standard * 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_ENABLED_SMC_FEATURES_MASK: + ret = smu_feature_get_enabled_mask(smu, (uint32_t *)data, 2); + *size = 8; + break; + case AMDGPU_PP_SENSOR_UVD_POWER: + *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT) ? 1 : 0; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VCE_POWER: + *(uint32_t *)data = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT) ? 1 : 0; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VCN_POWER_STATE: + *(uint32_t *)data = atomic_read(&smu->smu_power.power_gate.vcn_gated) ? 0: 1; + *size = 4; + break; + case AMDGPU_PP_SENSOR_MIN_FAN_RPM: + *(uint32_t *)data = 0; + *size = 4; + break; + default: + *size = 0; + ret = -EOPNOTSUPP; + break; + } + +unlock: mutex_unlock(&smu->mutex); return ret; @@ -2436,11 +2110,10 @@ int smu_read_sensor(struct smu_context *smu, int smu_get_power_profile_mode(struct smu_context *smu, char *buf) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2457,11 +2130,10 @@ int smu_set_power_profile_mode(struct smu_context *smu, uint32_t param_size, bool lock_needed) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (lock_needed) mutex_lock(&smu->mutex); @@ -2478,11 +2150,10 @@ int smu_set_power_profile_mode(struct smu_context *smu, int smu_get_fan_control_mode(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2496,11 +2167,10 @@ int smu_get_fan_control_mode(struct smu_context *smu) int smu_set_fan_control_mode(struct smu_context *smu, int value) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2514,11 +2184,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2532,11 +2201,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2550,11 +2218,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2568,16 +2235,14 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_deep_sleep_dcefclk) - ret = smu->ppt_funcs->set_deep_sleep_dcefclk(smu, clk); + ret = smu_set_min_dcef_deep_sleep(smu, clk); mutex_unlock(&smu->mutex); @@ -2586,11 +2251,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; if (smu->ppt_funcs->set_active_display_count) ret = smu->ppt_funcs->set_active_display_count(smu, count); @@ -2602,11 +2266,10 @@ int smu_get_clock_by_type(struct smu_context *smu, enum amd_pp_clock_type type, struct amd_pp_clocks *clocks) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2621,11 +2284,10 @@ int smu_get_clock_by_type(struct smu_context *smu, int smu_get_max_high_clocks(struct smu_context *smu, struct amd_pp_simple_clock_info *clocks) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2641,11 +2303,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2661,11 +2322,10 @@ 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) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2681,11 +2341,10 @@ int smu_get_clock_by_type_with_voltage(struct smu_context *smu, int smu_display_clock_voltage_request(struct smu_context *smu, struct pp_display_clock_request *clock_req) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2700,11 +2359,10 @@ int smu_display_clock_voltage_request(struct smu_context *smu, int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disable_memory_clock_switch) { - struct amdgpu_device *adev = smu->adev; int ret = -EINVAL; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2718,11 +2376,10 @@ int smu_display_disable_memory_clock_switch(struct smu_context *smu, bool disabl int smu_notify_smu_enable_pwe(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2737,11 +2394,10 @@ int smu_notify_smu_enable_pwe(struct smu_context *smu) int smu_set_xgmi_pstate(struct smu_context *smu, uint32_t pstate) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2750,16 +2406,18 @@ int smu_set_xgmi_pstate(struct smu_context *smu, mutex_unlock(&smu->mutex); + if(ret) + dev_err(smu->adev->dev, "Failed to set XGMI pstate!\n"); + return ret; } int smu_set_azalia_d3_pme(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2783,6 +2441,9 @@ bool smu_baco_is_support(struct smu_context *smu) { bool ret = false; + if (!smu->pm_enabled) + return false; + mutex_lock(&smu->mutex); if (smu->ppt_funcs && smu->ppt_funcs->baco_is_support) @@ -2809,6 +2470,9 @@ int smu_baco_enter(struct smu_context *smu) { int ret = 0; + if (!smu->pm_enabled) + return -EOPNOTSUPP; + mutex_lock(&smu->mutex); if (smu->ppt_funcs->baco_enter) @@ -2816,6 +2480,9 @@ int smu_baco_enter(struct smu_context *smu) mutex_unlock(&smu->mutex); + if (ret) + dev_err(smu->adev->dev, "Failed to enter BACO state!\n"); + return ret; } @@ -2823,6 +2490,9 @@ int smu_baco_exit(struct smu_context *smu) { int ret = 0; + if (!smu->pm_enabled) + return -EOPNOTSUPP; + mutex_lock(&smu->mutex); if (smu->ppt_funcs->baco_exit) @@ -2830,6 +2500,43 @@ int smu_baco_exit(struct smu_context *smu) mutex_unlock(&smu->mutex); + if (ret) + dev_err(smu->adev->dev, "Failed to exit BACO state!\n"); + + return ret; +} + +bool smu_mode1_reset_is_support(struct smu_context *smu) +{ + bool ret = false; + + if (!smu->pm_enabled) + return false; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs && smu->ppt_funcs->mode1_reset_is_support) + ret = smu->ppt_funcs->mode1_reset_is_support(smu); + + mutex_unlock(&smu->mutex); + + return ret; +} + +int smu_mode1_reset(struct smu_context *smu) +{ + int ret = 0; + + if (!smu->pm_enabled) + return -EOPNOTSUPP; + + mutex_lock(&smu->mutex); + + if (smu->ppt_funcs->mode1_reset) + ret = smu->ppt_funcs->mode1_reset(smu); + + mutex_unlock(&smu->mutex); + return ret; } @@ -2837,6 +2544,9 @@ int smu_mode2_reset(struct smu_context *smu) { int ret = 0; + if (!smu->pm_enabled) + return -EOPNOTSUPP; + mutex_lock(&smu->mutex); if (smu->ppt_funcs->mode2_reset) @@ -2844,17 +2554,19 @@ int smu_mode2_reset(struct smu_context *smu) mutex_unlock(&smu->mutex); + if (ret) + dev_err(smu->adev->dev, "Mode2 reset failed!\n"); + return ret; } int smu_get_max_sustainable_clocks_by_dc(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2870,11 +2582,10 @@ int smu_get_uclk_dpm_states(struct smu_context *smu, unsigned int *clock_values_in_khz, unsigned int *num_states) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2889,10 +2600,9 @@ int smu_get_uclk_dpm_states(struct smu_context *smu, 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; - struct amdgpu_device *adev = smu->adev; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2907,11 +2617,10 @@ enum amd_pm_state_type smu_get_current_power_state(struct smu_context *smu) int smu_get_dpm_clock_table(struct smu_context *smu, struct dpm_clocks *clock_table) { - struct amdgpu_device *adev = smu->adev; int ret = 0; - if (!adev->pm.dpm_enabled) - return -EINVAL; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return -EOPNOTSUPP; mutex_lock(&smu->mutex); @@ -2922,13 +2631,3 @@ int smu_get_dpm_clock_table(struct smu_context *smu, 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; -} diff --git a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c index 27c5fc9572b2..6c991de8f371 100644 --- a/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/arcturus_ppt.c @@ -21,12 +21,14 @@ * */ +#define SWSMU_CODE_LAYER_L2 + #include <linux/firmware.h> #include "amdgpu.h" #include "amdgpu_smu.h" -#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" #include "smu_v11_0.h" #include "smu11_driver_if_arcturus.h" #include "soc15_common.h" @@ -37,19 +39,26 @@ #include "arcturus_ppsmc.h" #include "nbio/nbio_7_4_offset.h" #include "nbio/nbio_7_4_sh_mask.h" +#include "thm/thm_11_0_2_offset.h" +#include "thm/thm_11_0_2_sh_mask.h" #include "amdgpu_xgmi.h" #include <linux/i2c.h> #include <linux/pci.h> #include "amdgpu_ras.h" +#include "smu_cmn.h" -#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug -#define CTF_OFFSET_EDGE 5 -#define CTF_OFFSET_HOTSPOT 5 -#define CTF_OFFSET_HBM 5 +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) -#define MSG_MAP(msg, index) \ - [SMU_MSG_##msg] = {1, (index)} #define ARCTURUS_FEA_MAP(smu_feature, arcturus_feature) \ [smu_feature] = {1, (arcturus_feature)} @@ -70,68 +79,70 @@ /* 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), - MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl), - MSG_MAP(GmiPwrDnControl, PPSMC_MSG_GmiPwrDnControl), +static const struct cmn2asic_msg_mapping arcturus_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 0), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow, 0), + MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh, 0), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), + MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow, 1), + MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh, 1), + MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow, 0), + MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 0), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 0), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 0), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), + MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), + MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), + MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), + MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable, 0), + MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh, 0), + MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow, 0), + MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0), + MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0), + MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 0), + MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 0), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 0), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), + MSG_MAP(SetDfSwitchType, PPSMC_MSG_SetDfSwitchType, 0), + MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0), + MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 1), + MSG_MAP(PowerUpVcn0, PPSMC_MSG_PowerUpVcn0, 0), + MSG_MAP(PowerDownVcn0, PPSMC_MSG_PowerDownVcn0, 0), + MSG_MAP(PowerUpVcn1, PPSMC_MSG_PowerUpVcn1, 0), + MSG_MAP(PowerDownVcn1, PPSMC_MSG_PowerDownVcn1, 0), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 0), + MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), + MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown, 0), + MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 0), + MSG_MAP(RunAfllBtc, PPSMC_MSG_RunAfllBtc, 0), + MSG_MAP(RunDcBtc, PPSMC_MSG_RunDcBtc, 0), + MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), + MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), + MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0), + MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData, 0), + MSG_MAP(WaflTest, PPSMC_MSG_WaflTest, 0), + MSG_MAP(SetXgmiMode, PPSMC_MSG_SetXgmiMode, 0), + MSG_MAP(SetMemoryChannelEnable, PPSMC_MSG_SetMemoryChannelEnable, 0), + MSG_MAP(DFCstateControl, PPSMC_MSG_DFCstateControl, 0), + MSG_MAP(GmiPwrDnControl, PPSMC_MSG_GmiPwrDnControl, 0), + MSG_MAP(ReadSerialNumTop32, PPSMC_MSG_ReadSerialNumTop32, 1), + MSG_MAP(ReadSerialNumBottom32, PPSMC_MSG_ReadSerialNumBottom32, 1), }; -static struct smu_11_0_cmn2aisc_mapping arcturus_clk_map[SMU_CLK_COUNT] = { +static const struct cmn2asic_mapping arcturus_clk_map[SMU_CLK_COUNT] = { CLK_MAP(GFXCLK, PPCLK_GFXCLK), CLK_MAP(SCLK, PPCLK_GFXCLK), CLK_MAP(SOCCLK, PPCLK_SOCCLK), @@ -142,7 +153,7 @@ static struct smu_11_0_cmn2aisc_mapping arcturus_clk_map[SMU_CLK_COUNT] = { CLK_MAP(VCLK, PPCLK_VCLK), }; -static struct smu_11_0_cmn2aisc_mapping arcturus_feature_mask_map[SMU_FEATURE_COUNT] = { +static const struct cmn2asic_mapping arcturus_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(DPM_PREFETCHER), FEA_MAP(DPM_GFXCLK), FEA_MAP(DPM_UCLK), @@ -171,7 +182,7 @@ static struct smu_11_0_cmn2aisc_mapping arcturus_feature_mask_map[SMU_FEATURE_CO FEA_MAP(TEMP_DEPENDENT_VMIN), }; -static struct smu_11_0_cmn2aisc_mapping arcturus_table_map[SMU_TABLE_COUNT] = { +static const struct cmn2asic_mapping arcturus_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PPTABLE), TAB_MAP(AVFS), TAB_MAP(AVFS_PSM_DEBUG), @@ -184,12 +195,12 @@ static struct smu_11_0_cmn2aisc_mapping arcturus_table_map[SMU_TABLE_COUNT] = { TAB_MAP(ACTIVITY_MONITOR_COEFF), }; -static struct smu_11_0_cmn2aisc_mapping arcturus_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { +static const struct cmn2asic_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] = { +static const struct cmn2asic_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), @@ -197,101 +208,10 @@ static struct smu_11_0_cmn2aisc_mapping arcturus_workload_map[PP_SMC_POWER_PROFI 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) +static int arcturus_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -321,23 +241,11 @@ 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), + smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), 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_context_size = sizeof(struct smu_11_0_dpm_context); smu_dpm->dpm_current_power_state = kzalloc(sizeof(struct smu_power_state), GFP_KERNEL); @@ -352,6 +260,21 @@ static int arcturus_allocate_dpm_context(struct smu_context *smu) return 0; } +static int arcturus_init_smc_tables(struct smu_context *smu) +{ + int ret = 0; + + ret = arcturus_tables_init(smu); + if (ret) + return ret; + + ret = arcturus_allocate_dpm_context(smu); + if (ret) + return ret; + + return smu_v11_0_init_smc_tables(smu); +} + static int arcturus_get_allowed_feature_mask(struct smu_context *smu, uint32_t *feature_mask, uint32_t num) @@ -365,161 +288,117 @@ arcturus_get_allowed_feature_mask(struct smu_context *smu, 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), - &num_of_levels); - if (ret) { - pr_err("[%s] failed to get dpm levels!\n", __func__); - return ret; - } - - 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), - &clk); - if (ret) { - pr_err("[%s] failed to get dpm freq by index!\n", __func__); - return ret; - } - 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; + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + PPTable_t *driver_ppt = smu->smu_table.driver_pptable; + struct smu_11_0_dpm_table *dpm_table = NULL; + int ret = 0; - /* 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__); + /* socclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.soc_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_SOCCLK, + dpm_table); + if (ret) return ret; - } + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; } - 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!"); + /* gfxclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_GFXCLK, + dpm_table); + if (ret) return ret; - } + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; } - 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!"); + /* memclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_UCLK, + dpm_table); + if (ret) return ret; - } + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; } - 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!"); + /* fclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_FCLK, + dpm_table); + if (ret) return ret; - } + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete; } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; } - 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) { + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_powerplay_table *powerplay_table = + table_context->power_play_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; + + 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); + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; + 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; + struct smu_11_0_powerplay_table *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; + return 0; } static int arcturus_append_powerplay_table(struct smu_context *smu) @@ -532,12 +411,12 @@ static int arcturus_append_powerplay_table(struct smu_context *smu) 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, + ret = amdgpu_atombios_get_data_table(smu->adev, 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", + dev_info(smu->adev->dev, "smc_dpm_info table revision(format.content): %d.%d\n", smc_dpm_table->table_header.format_revision, smc_dpm_table->table_header.content_revision); @@ -550,48 +429,88 @@ static int arcturus_append_powerplay_table(struct smu_context *smu) return 0; } +static int arcturus_setup_pptable(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v11_0_setup_pptable(smu); + if (ret) + return ret; + + ret = arcturus_store_powerplay_table(smu); + if (ret) + return ret; + + ret = arcturus_append_powerplay_table(smu); + if (ret) + return ret; + + ret = arcturus_check_powerplay_table(smu); + if (ret) + return ret; + + return ret; +} + static int arcturus_run_btc(struct smu_context *smu) { int ret = 0; - ret = smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL); if (ret) { - pr_err("RunAfllBtc failed!\n"); + dev_err(smu->adev->dev, "RunAfllBtc failed!\n"); return ret; } - return smu_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); + return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL); } 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; + struct smu_11_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_11_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_11_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_11_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + + pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.peak = gfx_table->max; + + pstate_table->uclk_pstate.min = mem_table->min; + pstate_table->uclk_pstate.peak = mem_table->max; + + pstate_table->socclk_pstate.min = soc_table->min; + pstate_table->socclk_pstate.peak = soc_table->max; 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; + mem_table->count > ARCTURUS_UMD_PSTATE_MCLK_LEVEL && + soc_table->count > ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL) { + pstate_table->gfxclk_pstate.standard = + gfx_table->dpm_levels[ARCTURUS_UMD_PSTATE_GFXCLK_LEVEL].value; + pstate_table->uclk_pstate.standard = + mem_table->dpm_levels[ARCTURUS_UMD_PSTATE_MCLK_LEVEL].value; + pstate_table->socclk_pstate.standard = + soc_table->dpm_levels[ARCTURUS_UMD_PSTATE_SOCCLK_LEVEL].value; + } else { + pstate_table->gfxclk_pstate.standard = + pstate_table->gfxclk_pstate.min; + pstate_table->uclk_pstate.standard = + pstate_table->uclk_pstate.min; + pstate_table->socclk_pstate.standard = + pstate_table->socclk_pstate.min; } - 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) + struct smu_11_0_dpm_table *dpm_table) { int i, count; @@ -613,33 +532,209 @@ static int arcturus_freqs_in_same_level(int32_t frequency1, return (abs(frequency1 - frequency2) <= EPSILON); } +static int arcturus_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + + if (!smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { + ret = smu_cmn_update_table(smu, + SMU_TABLE_SMU_METRICS, + 0, + smu_table->metrics_table, + false); + if (ret) { + dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); + return ret; + } + smu_table->metrics_time = jiffies; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_FCLK: + *value = metrics->CurrClock[PPCLK_FCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + *value = metrics->AverageGfxclkFrequency; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequency; + break; + case METRICS_AVERAGE_VCLK: + *value = metrics->AverageVclkFrequency; + break; + case METRICS_AVERAGE_DCLK: + *value = metrics->AverageDclkFrequency; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_VCNACTIVITY: + *value = metrics->VcnActivityPercentage; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureHBM * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRMEM: + *value = metrics->TemperatureVrMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; +} + +static int arcturus_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + int clk_id = 0; + + if (!value) + return -EINVAL; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return -EINVAL; + + 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/vclk/dclk. + */ + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) + member_type = METRICS_CURR_GFXCLK; + else + member_type = METRICS_AVERAGE_GFXCLK; + break; + case PPCLK_UCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) + member_type = METRICS_CURR_UCLK; + else + member_type = METRICS_AVERAGE_UCLK; + break; + case PPCLK_SOCCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) + member_type = METRICS_CURR_SOCCLK; + else + member_type = METRICS_AVERAGE_SOCCLK; + break; + case PPCLK_VCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) + member_type = METRICS_CURR_VCLK; + else + member_type = METRICS_AVERAGE_VCLK; + break; + case PPCLK_DCLK: + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) + member_type = METRICS_CURR_DCLK; + else + member_type = METRICS_AVERAGE_DCLK; + break; + case PPCLK_FCLK: + member_type = METRICS_CURR_FCLK; + break; + default: + return -EINVAL; + } + + return arcturus_get_smu_metrics_data(smu, + member_type, + value); +} + 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_11_0_dpm_table *single_dpm_table; struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct arcturus_dpm_table *dpm_table = NULL; + struct smu_11_0_dpm_context *dpm_context = NULL; if (amdgpu_ras_intr_triggered()) return snprintf(buf, PAGE_SIZE, "unavailable\n"); - dpm_table = smu_dpm->dpm_context; + dpm_context = smu_dpm->dpm_context; switch (type) { case SMU_SCLK: - ret = smu_get_current_clk_freq(smu, SMU_GFXCLK, &now); + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_GFXCLK, &now); if (ret) { - pr_err("Attempt to get current gfx clk Failed!"); + dev_err(smu->adev->dev, "Attempt to get current gfx clk Failed!"); return ret; } - single_dpm_table = &(dpm_table->gfx_table); + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); if (ret) { - pr_err("Attempt to get gfx clk levels Failed!"); + dev_err(smu->adev->dev, "Attempt to get gfx clk levels Failed!"); return ret; } @@ -653,20 +748,20 @@ static int arcturus_print_clk_levels(struct smu_context *smu, (clocks.num_levels == 1) ? "*" : (arcturus_freqs_in_same_level( clocks.data[i].clocks_in_khz / 1000, - now / 100) ? "*" : "")); + now) ? "*" : "")); break; case SMU_MCLK: - ret = smu_get_current_clk_freq(smu, SMU_UCLK, &now); + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_UCLK, &now); if (ret) { - pr_err("Attempt to get current mclk Failed!"); + dev_err(smu->adev->dev, "Attempt to get current mclk Failed!"); return ret; } - single_dpm_table = &(dpm_table->mem_table); + single_dpm_table = &(dpm_context->dpm_tables.uclk_table); ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); if (ret) { - pr_err("Attempt to get memory clk levels Failed!"); + dev_err(smu->adev->dev, "Attempt to get memory clk levels Failed!"); return ret; } @@ -676,20 +771,20 @@ static int arcturus_print_clk_levels(struct smu_context *smu, (clocks.num_levels == 1) ? "*" : (arcturus_freqs_in_same_level( clocks.data[i].clocks_in_khz / 1000, - now / 100) ? "*" : "")); + now) ? "*" : "")); break; case SMU_SOCCLK: - ret = smu_get_current_clk_freq(smu, SMU_SOCCLK, &now); + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_SOCCLK, &now); if (ret) { - pr_err("Attempt to get current socclk Failed!"); + dev_err(smu->adev->dev, "Attempt to get current socclk Failed!"); return ret; } - single_dpm_table = &(dpm_table->soc_table); + single_dpm_table = &(dpm_context->dpm_tables.soc_table); ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); if (ret) { - pr_err("Attempt to get socclk levels Failed!"); + dev_err(smu->adev->dev, "Attempt to get socclk levels Failed!"); return ret; } @@ -699,20 +794,20 @@ static int arcturus_print_clk_levels(struct smu_context *smu, (clocks.num_levels == 1) ? "*" : (arcturus_freqs_in_same_level( clocks.data[i].clocks_in_khz / 1000, - now / 100) ? "*" : "")); + now) ? "*" : "")); break; case SMU_FCLK: - ret = smu_get_current_clk_freq(smu, SMU_FCLK, &now); + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_FCLK, &now); if (ret) { - pr_err("Attempt to get current fclk Failed!"); + dev_err(smu->adev->dev, "Attempt to get current fclk Failed!"); return ret; } - single_dpm_table = &(dpm_table->fclk_table); + single_dpm_table = &(dpm_context->dpm_tables.fclk_table); ret = arcturus_get_clk_table(smu, &clocks, single_dpm_table); if (ret) { - pr_err("Attempt to get fclk levels Failed!"); + dev_err(smu->adev->dev, "Attempt to get fclk levels Failed!"); return ret; } @@ -722,7 +817,7 @@ static int arcturus_print_clk_levels(struct smu_context *smu, (clocks.num_levels == 1) ? "*" : (arcturus_freqs_in_same_level( clocks.data[i].clocks_in_khz / 1000, - now / 100) ? "*" : "")); + now) ? "*" : "")); break; default: @@ -732,58 +827,53 @@ static int arcturus_print_clk_levels(struct smu_context *smu, return size; } -static int arcturus_upload_dpm_level(struct smu_context *smu, bool max, - uint32_t feature_mask) +static int arcturus_upload_dpm_level(struct smu_context *smu, + bool max, + uint32_t feature_mask, + uint32_t level) { - struct arcturus_single_dpm_table *single_dpm_table; - struct arcturus_dpm_table *dpm_table = + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; uint32_t freq; int ret = 0; - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT) && + if (smu_cmn_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, + freq = dpm_context->dpm_tables.gfx_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), (PPCLK_GFXCLK << 16) | (freq & 0xffff), NULL); if (ret) { - pr_err("Failed to set soft %s gfxclk !\n", + dev_err(smu->adev->dev, "Failed to set soft %s gfxclk !\n", max ? "max" : "min"); return ret; } } - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && + if (smu_cmn_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, + freq = dpm_context->dpm_tables.uclk_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), (PPCLK_UCLK << 16) | (freq & 0xffff), NULL); if (ret) { - pr_err("Failed to set soft %s memclk !\n", + dev_err(smu->adev->dev, "Failed to set soft %s memclk !\n", max ? "max" : "min"); return ret; } } - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT) && + if (smu_cmn_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, + freq = dpm_context->dpm_tables.soc_table.dpm_levels[level].value; + ret = smu_cmn_send_smc_msg_with_param(smu, (max ? SMU_MSG_SetSoftMaxByFreq : SMU_MSG_SetSoftMinByFreq), (PPCLK_SOCCLK << 16) | (freq & 0xffff), NULL); if (ret) { - pr_err("Failed to set soft %s socclk !\n", + dev_err(smu->adev->dev, "Failed to set soft %s socclk !\n", max ? "max" : "min"); return ret; } @@ -795,20 +885,20 @@ static int arcturus_upload_dpm_level(struct smu_context *smu, bool max, 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; + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + struct smu_11_0_dpm_table *single_dpm_table = NULL; uint32_t soft_min_level, soft_max_level; uint32_t smu_version; int ret = 0; - ret = smu_get_smc_version(smu, NULL, &smu_version); + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) { - pr_err("Failed to get smu version!\n"); + dev_err(smu->adev->dev, "Failed to get smu version!\n"); return ret; } if (smu_version >= 0x361200) { - pr_err("Forcing clock level is not supported with " + dev_err(smu->adev->dev, "Forcing clock level is not supported with " "54.18 and onwards SMU firmwares\n"); return -EOPNOTSUPP; } @@ -816,33 +906,31 @@ static int arcturus_force_clk_levels(struct smu_context *smu, 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); - + single_dpm_table = &(dpm_context->dpm_tables.gfx_table); if (soft_max_level >= single_dpm_table->count) { - pr_err("Clock level specified %d is over max allowed %d\n", + dev_err(smu->adev->dev, "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); + ret = arcturus_upload_dpm_level(smu, + false, + FEATURE_DPM_GFXCLK_MASK, + soft_min_level); if (ret) { - pr_err("Failed to upload boot level to lowest!\n"); + dev_err(smu->adev->dev, "Failed to upload boot level to lowest!\n"); break; } - ret = arcturus_upload_dpm_level(smu, true, FEATURE_DPM_GFXCLK_MASK); + ret = arcturus_upload_dpm_level(smu, + true, + FEATURE_DPM_GFXCLK_MASK, + soft_max_level); if (ret) - pr_err("Failed to upload dpm max level to highest!\n"); + dev_err(smu->adev->dev, "Failed to upload dpm max level to highest!\n"); break; @@ -866,11 +954,16 @@ static int arcturus_force_clk_levels(struct smu_context *smu, static int arcturus_get_thermal_temperature_range(struct smu_context *smu, struct smu_temperature_range *range) { + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_powerplay_table *powerplay_table = + table_context->power_play_table; PPTable_t *pptable = smu->smu_table.driver_pptable; if (!range) return -EINVAL; + memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range)); + range->max = pptable->TedgeLimit * SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) * @@ -881,116 +974,82 @@ static int arcturus_get_thermal_temperature_range(struct smu_context *smu, 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)* + range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_MEM)* SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->software_shutdown_temp = powerplay_table->software_shutdown_temp; 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; + ret = arcturus_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, + value); break; case AMDGPU_PP_SENSOR_MEM_LOAD: - *value = metrics.AverageUclkActivity; + ret = arcturus_get_smu_metrics_data(smu, + METRICS_AVERAGE_MEMACTIVITY, + value); break; default: - pr_err("Invalid sensor for retrieving clock activity\n"); + dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n"); return -EINVAL; } - return 0; + return ret; } 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; + return arcturus_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, + value); } 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; + ret = arcturus_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, + value); break; case AMDGPU_PP_SENSOR_EDGE_TEMP: - *value = metrics.TemperatureEdge * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + ret = arcturus_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_EDGE, + value); break; case AMDGPU_PP_SENSOR_MEM_TEMP: - *value = metrics.TemperatureHBM * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + ret = arcturus_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_MEM, + value); break; default: - pr_err("Invalid sensor for retrieving temp\n"); + dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n"); return -EINVAL; } - return 0; + return ret; } static int arcturus_read_sensor(struct smu_context *smu, @@ -1031,8 +1090,24 @@ static int arcturus_read_sensor(struct smu_context *smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); + /* the output clock frequency in 10K unit */ + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = arcturus_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data); + *size = 4; + break; default: - ret = smu_v11_0_read_sensor(smu, sensor, data, size); + ret = -EOPNOTSUPP; + break; } mutex_unlock(&smu->sensor_lock); @@ -1042,19 +1117,12 @@ static int arcturus_read_sensor(struct smu_context *smu, 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; + return arcturus_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); } static int arcturus_get_fan_speed_percent(struct smu_context *smu, @@ -1077,263 +1145,33 @@ static int arcturus_get_fan_speed_percent(struct smu_context *smu, 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) +static int arcturus_get_power_limit(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; + struct smu_11_0_powerplay_table *powerplay_table = + (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t power_limit, od_percent; - 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 (smu_v11_0_get_current_power_limit(smu, &power_limit)) { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + power_limit = + pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; } + smu->current_power_limit = power_limit; - 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; - } + if (smu->od_enabled) { + od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); - return 0; -} + dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit); -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, &asic_default_power_limit); - if (ret) { - pr_err("[%s] get PPT limit failed!", __func__); - return ret; - } - } 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; + power_limit *= (100 + od_percent); + power_limit /= 100; } - - if (cap) - *limit = smu_v11_0_get_max_power_limit(smu); - else - *limit = smu->power_limit; + smu->max_power_limit = power_limit; return 0; } @@ -1341,7 +1179,6 @@ static int arcturus_get_power_limit(struct smu_context *smu, 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", @@ -1371,11 +1208,11 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu, if (!buf) return -EINVAL; - result = smu_get_smc_version(smu, NULL, &smu_version); + result = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (result) return result; - if (smu_version >= 0x360d00 && !amdgpu_sriov_vf(adev)) + if (smu_version >= 0x360d00) 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]); @@ -1388,18 +1225,20 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu, * 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); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + i); if (workload_type < 0) continue; - if (smu_version >= 0x360d00 && !amdgpu_sriov_vf(adev)) { - result = smu_update_table(smu, + if (smu_version >= 0x360d00) { + result = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); return result; } } @@ -1407,7 +1246,7 @@ static int arcturus_get_power_profile_mode(struct smu_context *smu, 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)) { + if (smu_version >= 0x360d00) { size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", " ", 0, @@ -1452,23 +1291,23 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu, uint32_t smu_version; if (profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - pr_err("Invalid power profile mode %d\n", profile_mode); + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); return -EINVAL; } - ret = smu_get_smc_version(smu, NULL, &smu_version); + ret = smu_cmn_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, + ret = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); return ret; } @@ -1497,13 +1336,13 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu, break; } - ret = smu_update_table(smu, + ret = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); return ret; } } @@ -1512,18 +1351,20 @@ static int arcturus_set_power_profile_mode(struct smu_context *smu, * 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); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + profile_mode); if (workload_type < 0) { - pr_err("Unsupported power profile mode %d on arcturus\n", profile_mode); + dev_err(smu->adev->dev, "Unsupported power profile mode %d on arcturus\n", profile_mode); return -EINVAL; } - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1 << workload_type, NULL); if (ret) { - pr_err("Fail to set workload type %d\n", workload_type); + dev_err(smu->adev->dev, "Fail to set workload type %d\n", workload_type); return ret; } @@ -1538,9 +1379,9 @@ static int arcturus_set_performance_level(struct smu_context *smu, uint32_t smu_version; int ret; - ret = smu_get_smc_version(smu, NULL, &smu_version); + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) { - pr_err("Failed to get smu version!\n"); + dev_err(smu->adev->dev, "Failed to get smu version!\n"); return ret; } @@ -1552,7 +1393,7 @@ static int arcturus_set_performance_level(struct smu_context *smu, case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: if (smu_version >= 0x361200) { - pr_err("Forcing clock level is not supported with " + dev_err(smu->adev->dev, "Forcing clock level is not supported with " "54.18 and onwards SMU firmwares\n"); return -EOPNOTSUPP; } @@ -1570,53 +1411,53 @@ static void arcturus_dump_pptable(struct smu_context *smu) PPTable_t *pptable = table_context->driver_pptable; int i; - pr_info("Dumped PPTable:\n"); + dev_info(smu->adev->dev, "Dumped PPTable:\n"); - pr_info("Version = 0x%08x\n", pptable->Version); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "SocketPowerLimitAc[%d] = %d\n", i, pptable->SocketPowerLimitAc[i]); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "TdcLimitSoc = %d\n", pptable->TdcLimitSoc); + dev_info(smu->adev->dev, "TdcLimitSocTau = %d\n", pptable->TdcLimitSocTau); + dev_info(smu->adev->dev, "TdcLimitGfx = %d\n", pptable->TdcLimitGfx); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "TedgeLimit = %d\n", pptable->TedgeLimit); + dev_info(smu->adev->dev, "ThotspotLimit = %d\n", pptable->ThotspotLimit); + dev_info(smu->adev->dev, "TmemLimit = %d\n", pptable->TmemLimit); + dev_info(smu->adev->dev, "Tvr_gfxLimit = %d\n", pptable->Tvr_gfxLimit); + dev_info(smu->adev->dev, "Tvr_memLimit = %d\n", pptable->Tvr_memLimit); + dev_info(smu->adev->dev, "Tvr_socLimit = %d\n", pptable->Tvr_socLimit); + dev_info(smu->adev->dev, "FitLimit = %d\n", pptable->FitLimit); - pr_info("PpmPowerLimit = %d\n", pptable->PpmPowerLimit); - pr_info("PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); + dev_info(smu->adev->dev, "PpmPowerLimit = %d\n", pptable->PpmPowerLimit); + dev_info(smu->adev->dev, "PpmTemperatureThreshold = %d\n", pptable->PpmTemperatureThreshold); - pr_info("ThrottlerControlMask = %d\n", pptable->ThrottlerControlMask); + dev_info(smu->adev->dev, "ThrottlerControlMask = %d\n", pptable->ThrottlerControlMask); - pr_info("UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); - pr_info("UlvPadding = 0x%08x\n", pptable->UlvPadding); + dev_info(smu->adev->dev, "UlvVoltageOffsetGfx = %d\n", pptable->UlvVoltageOffsetGfx); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "UlvGfxclkBypass = %d\n", pptable->UlvGfxclkBypass); + dev_info(smu->adev->dev, "Padding234[0] = 0x%02x\n", pptable->Padding234[0]); + dev_info(smu->adev->dev, "Padding234[1] = 0x%02x\n", pptable->Padding234[1]); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "MinVoltageGfx = %d\n", pptable->MinVoltageGfx); + dev_info(smu->adev->dev, "MinVoltageSoc = %d\n", pptable->MinVoltageSoc); + dev_info(smu->adev->dev, "MaxVoltageGfx = %d\n", pptable->MaxVoltageGfx); + dev_info(smu->adev->dev, "MaxVoltageSoc = %d\n", pptable->MaxVoltageSoc); - pr_info("LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); - pr_info("LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); + dev_info(smu->adev->dev, "LoadLineResistanceGfx = %d\n", pptable->LoadLineResistanceGfx); + dev_info(smu->adev->dev, "LoadLineResistanceSoc = %d\n", pptable->LoadLineResistanceSoc); - pr_info("[PPCLK_GFXCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_GFXCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1637,7 +1478,7 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_GFXCLK].SsFmin, pptable->DpmDescriptor[PPCLK_GFXCLK].Padding16); - pr_info("[PPCLK_VCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_VCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1658,7 +1499,7 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_VCLK].SsFmin, pptable->DpmDescriptor[PPCLK_VCLK].Padding16); - pr_info("[PPCLK_DCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_DCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1679,7 +1520,7 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_DCLK].SsFmin, pptable->DpmDescriptor[PPCLK_DCLK].Padding16); - pr_info("[PPCLK_SOCCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_SOCCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1700,7 +1541,7 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_SOCCLK].SsFmin, pptable->DpmDescriptor[PPCLK_SOCCLK].Padding16); - pr_info("[PPCLK_UCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_UCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1721,7 +1562,7 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_UCLK].SsFmin, pptable->DpmDescriptor[PPCLK_UCLK].Padding16); - pr_info("[PPCLK_FCLK]\n" + dev_info(smu->adev->dev, "[PPCLK_FCLK]\n" " .VoltageMode = 0x%02x\n" " .SnapToDiscrete = 0x%02x\n" " .NumDiscreteLevels = 0x%02x\n" @@ -1743,255 +1584,255 @@ static void arcturus_dump_pptable(struct smu_context *smu) pptable->DpmDescriptor[PPCLK_FCLK].Padding16); - pr_info("FreqTableGfx\n"); + dev_info(smu->adev->dev, "FreqTableGfx\n"); for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableGfx[i]); - pr_info("FreqTableVclk\n"); + dev_info(smu->adev->dev, "FreqTableVclk\n"); for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableVclk[i]); - pr_info("FreqTableDclk\n"); + dev_info(smu->adev->dev, "FreqTableDclk\n"); for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableDclk[i]); - pr_info("FreqTableSocclk\n"); + dev_info(smu->adev->dev, "FreqTableSocclk\n"); for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableSocclk[i]); - pr_info("FreqTableUclk\n"); + dev_info(smu->adev->dev, "FreqTableUclk\n"); for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableUclk[i]); - pr_info("FreqTableFclk\n"); + dev_info(smu->adev->dev, "FreqTableFclk\n"); for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) - pr_info(" .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); + dev_info(smu->adev->dev, " .[%02d] = %d\n", i, pptable->FreqTableFclk[i]); - pr_info("Mp0clkFreq\n"); + dev_info(smu->adev->dev, "Mp0clkFreq\n"); for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->Mp0clkFreq[i]); - pr_info("Mp0DpmVoltage\n"); + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->Mp0DpmVoltage[i]); + + dev_info(smu->adev->dev, "GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); + dev_info(smu->adev->dev, "GfxclkSlewRate = 0x%x\n", pptable->GfxclkSlewRate); + dev_info(smu->adev->dev, "Padding567[0] = 0x%x\n", pptable->Padding567[0]); + dev_info(smu->adev->dev, "Padding567[1] = 0x%x\n", pptable->Padding567[1]); + dev_info(smu->adev->dev, "Padding567[2] = 0x%x\n", pptable->Padding567[2]); + dev_info(smu->adev->dev, "Padding567[3] = 0x%x\n", pptable->Padding567[3]); + dev_info(smu->adev->dev, "GfxclkDsMaxFreq = %d\n", pptable->GfxclkDsMaxFreq); + dev_info(smu->adev->dev, "GfxclkSource = 0x%x\n", pptable->GfxclkSource); + dev_info(smu->adev->dev, "Padding456 = 0x%x\n", pptable->Padding456); + + dev_info(smu->adev->dev, "EnableTdpm = %d\n", pptable->EnableTdpm); + dev_info(smu->adev->dev, "TdpmHighHystTemperature = %d\n", pptable->TdpmHighHystTemperature); + dev_info(smu->adev->dev, "TdpmLowHystTemperature = %d\n", pptable->TdpmLowHystTemperature); + dev_info(smu->adev->dev, "GfxclkFreqHighTempLimit = %d\n", pptable->GfxclkFreqHighTempLimit); + + dev_info(smu->adev->dev, "FanStopTemp = %d\n", pptable->FanStopTemp); + dev_info(smu->adev->dev, "FanStartTemp = %d\n", pptable->FanStartTemp); + + dev_info(smu->adev->dev, "FanGainEdge = %d\n", pptable->FanGainEdge); + dev_info(smu->adev->dev, "FanGainHotspot = %d\n", pptable->FanGainHotspot); + dev_info(smu->adev->dev, "FanGainVrGfx = %d\n", pptable->FanGainVrGfx); + dev_info(smu->adev->dev, "FanGainVrSoc = %d\n", pptable->FanGainVrSoc); + dev_info(smu->adev->dev, "FanGainVrMem = %d\n", pptable->FanGainVrMem); + dev_info(smu->adev->dev, "FanGainHbm = %d\n", pptable->FanGainHbm); + + dev_info(smu->adev->dev, "FanPwmMin = %d\n", pptable->FanPwmMin); + dev_info(smu->adev->dev, "FanAcousticLimitRpm = %d\n", pptable->FanAcousticLimitRpm); + dev_info(smu->adev->dev, "FanThrottlingRpm = %d\n", pptable->FanThrottlingRpm); + dev_info(smu->adev->dev, "FanMaximumRpm = %d\n", pptable->FanMaximumRpm); + dev_info(smu->adev->dev, "FanTargetTemperature = %d\n", pptable->FanTargetTemperature); + dev_info(smu->adev->dev, "FanTargetGfxclk = %d\n", pptable->FanTargetGfxclk); + dev_info(smu->adev->dev, "FanZeroRpmEnable = %d\n", pptable->FanZeroRpmEnable); + dev_info(smu->adev->dev, "FanTachEdgePerRev = %d\n", pptable->FanTachEdgePerRev); + dev_info(smu->adev->dev, "FanTempInputSelect = %d\n", pptable->FanTempInputSelect); + + dev_info(smu->adev->dev, "FuzzyFan_ErrorSetDelta = %d\n", pptable->FuzzyFan_ErrorSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_ErrorRateSetDelta = %d\n", pptable->FuzzyFan_ErrorRateSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_PwmSetDelta = %d\n", pptable->FuzzyFan_PwmSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_Reserved = %d\n", pptable->FuzzyFan_Reserved); + + dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "Padding8_Avfs[0] = %d\n", pptable->Padding8_Avfs[0]); + dev_info(smu->adev->dev, "Padding8_Avfs[1] = %d\n", pptable->Padding8_Avfs[1]); + + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "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]); + dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); - pr_info("XgmiDpmPstates\n"); + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiDpmPstates[i]); + dev_info(smu->adev->dev, "XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); + dev_info(smu->adev->dev, "XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); + + dev_info(smu->adev->dev, "VDDGFX_TVmin = %d\n", pptable->VDDGFX_TVmin); + dev_info(smu->adev->dev, "VDDSOC_TVmin = %d\n", pptable->VDDSOC_TVmin); + dev_info(smu->adev->dev, "VDDGFX_Vmin_HiTemp = %d\n", pptable->VDDGFX_Vmin_HiTemp); + dev_info(smu->adev->dev, "VDDGFX_Vmin_LoTemp = %d\n", pptable->VDDGFX_Vmin_LoTemp); + dev_info(smu->adev->dev, "VDDSOC_Vmin_HiTemp = %d\n", pptable->VDDSOC_Vmin_HiTemp); + dev_info(smu->adev->dev, "VDDSOC_Vmin_LoTemp = %d\n", pptable->VDDSOC_Vmin_LoTemp); + dev_info(smu->adev->dev, "VDDGFX_TVminHystersis = %d\n", pptable->VDDGFX_TVminHystersis); + dev_info(smu->adev->dev, "VDDSOC_TVminHystersis = %d\n", pptable->VDDSOC_TVminHystersis); + + dev_info(smu->adev->dev, "DebugOverrides = 0x%x\n", pptable->DebugOverrides); + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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", + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "MinVoltageUlvGfx = %d\n", pptable->MinVoltageUlvGfx); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "TotalPowerConfig = %d\n", pptable->TotalPowerConfig); + dev_info(smu->adev->dev, "TotalPowerSpare1 = %d\n", pptable->TotalPowerSpare1); + dev_info(smu->adev->dev, "TotalPowerSpare2 = %d\n", pptable->TotalPowerSpare2); - pr_info("PccThresholdLow = %d\n", pptable->PccThresholdLow); - pr_info("PccThresholdHigh = %d\n", pptable->PccThresholdHigh); + dev_info(smu->adev->dev, "PccThresholdLow = %d\n", pptable->PccThresholdLow); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "Board Parameters:\n"); + dev_info(smu->adev->dev, "MaxVoltageStepGfx = 0x%x\n", pptable->MaxVoltageStepGfx); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); + dev_info(smu->adev->dev, "VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); + dev_info(smu->adev->dev, "VddMemVrMapping = 0x%x\n", pptable->VddMemVrMapping); + dev_info(smu->adev->dev, "BoardVrMapping = 0x%x\n", pptable->BoardVrMapping); - pr_info("GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); - pr_info("ExternalSensorPresent = 0x%x\n", pptable->ExternalSensorPresent); + dev_info(smu->adev->dev, "GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); + dev_info(smu->adev->dev, "GfxOffset = 0x%x\n", pptable->GfxOffset); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); + dev_info(smu->adev->dev, "SocOffset = 0x%x\n", pptable->SocOffset); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "MemMaxCurrent = 0x%x\n", pptable->MemMaxCurrent); + dev_info(smu->adev->dev, "MemOffset = 0x%x\n", pptable->MemOffset); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "BoardMaxCurrent = 0x%x\n", pptable->BoardMaxCurrent); + dev_info(smu->adev->dev, "BoardOffset = 0x%x\n", pptable->BoardOffset); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "VR0HotGpio = %d\n", pptable->VR0HotGpio); + dev_info(smu->adev->dev, "VR0HotPolarity = %d\n", pptable->VR0HotPolarity); + dev_info(smu->adev->dev, "VR1HotGpio = %d\n", pptable->VR1HotGpio); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "PllGfxclkSpreadEnabled = %d\n", pptable->PllGfxclkSpreadEnabled); + dev_info(smu->adev->dev, "PllGfxclkSpreadPercent = %d\n", pptable->PllGfxclkSpreadPercent); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "UclkSpreadEnabled = %d\n", pptable->UclkSpreadEnabled); + dev_info(smu->adev->dev, "UclkSpreadPercent = %d\n", pptable->UclkSpreadPercent); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "FclkSpreadEnabled = %d\n", pptable->FclkSpreadEnabled); + dev_info(smu->adev->dev, "FclkSpreadPercent = %d\n", pptable->FclkSpreadPercent); + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "FllGfxclkSpreadEnabled = %d\n", pptable->FllGfxclkSpreadEnabled); + dev_info(smu->adev->dev, "FllGfxclkSpreadPercent = %d\n", pptable->FllGfxclkSpreadPercent); + dev_info(smu->adev->dev, "FllGfxclkSpreadFreq = %d\n", pptable->FllGfxclkSpreadFreq); for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { - pr_info("I2cControllers[%d]:\n", i); - pr_info(" .Enabled = %d\n", + dev_info(smu->adev->dev, "I2cControllers[%d]:\n", i); + dev_info(smu->adev->dev, " .Enabled = %d\n", pptable->I2cControllers[i].Enabled); - pr_info(" .SlaveAddress = 0x%x\n", + dev_info(smu->adev->dev, " .SlaveAddress = 0x%x\n", pptable->I2cControllers[i].SlaveAddress); - pr_info(" .ControllerPort = %d\n", + dev_info(smu->adev->dev, " .ControllerPort = %d\n", pptable->I2cControllers[i].ControllerPort); - pr_info(" .ControllerName = %d\n", + dev_info(smu->adev->dev, " .ControllerName = %d\n", pptable->I2cControllers[i].ControllerName); - pr_info(" .ThermalThrottler = %d\n", + dev_info(smu->adev->dev, " .ThermalThrottler = %d\n", pptable->I2cControllers[i].ThermalThrotter); - pr_info(" .I2cProtocol = %d\n", + dev_info(smu->adev->dev, " .I2cProtocol = %d\n", pptable->I2cControllers[i].I2cProtocol); - pr_info(" .Speed = %d\n", + dev_info(smu->adev->dev, " .Speed = %d\n", pptable->I2cControllers[i].Speed); } - pr_info("MemoryChannelEnabled = %d\n", pptable->MemoryChannelEnabled); - pr_info("DramBitWidth = %d\n", pptable->DramBitWidth); + dev_info(smu->adev->dev, "MemoryChannelEnabled = %d\n", pptable->MemoryChannelEnabled); + dev_info(smu->adev->dev, "DramBitWidth = %d\n", pptable->DramBitWidth); - pr_info("TotalBoardPower = %d\n", pptable->TotalBoardPower); + dev_info(smu->adev->dev, "TotalBoardPower = %d\n", pptable->TotalBoardPower); - pr_info("XgmiLinkSpeed\n"); + dev_info(smu->adev->dev, "XgmiLinkSpeed\n"); for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); - pr_info("XgmiLinkWidth\n"); + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiLinkSpeed[i]); + dev_info(smu->adev->dev, "XgmiLinkWidth\n"); for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); - pr_info("XgmiFclkFreq\n"); + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiLinkWidth[i]); + dev_info(smu->adev->dev, "XgmiFclkFreq\n"); for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); - pr_info("XgmiSocVoltage\n"); + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiFclkFreq[i]); + dev_info(smu->adev->dev, "XgmiSocVoltage\n"); for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) - pr_info(" .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); + dev_info(smu->adev->dev, " .[%d] = %d\n", i, pptable->XgmiSocVoltage[i]); } @@ -2000,50 +1841,43 @@ 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); + ret = smu_cmn_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) +static int arcturus_dpm_set_vcn_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 (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 1); if (ret) { - pr_err("[EnableVCNDPM] failed!\n"); + dev_err(smu->adev->dev, "[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 (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_VCN_PG_BIT, 0); if (ret) { - pr_err("[DisableVCNDPM] failed!\n"); + dev_err(smu->adev->dev, "[DisableVCNDPM] failed!\n"); return ret; } } - power_gate->vcn_gated = true; } return ret; } - -static void arcturus_fill_eeprom_i2c_req(SwI2cRequest_t *req, bool write, +static void arcturus_fill_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; @@ -2070,7 +1904,7 @@ static void arcturus_fill_eeprom_i2c_req(SwI2cRequest_t *req, bool write, } } -static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control, +static int arcturus_i2c_read_data(struct i2c_adapter *control, uint8_t address, uint8_t *data, uint32_t numbytes) @@ -2081,12 +1915,18 @@ static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control, struct smu_table_context *smu_table = &adev->smu.smu_table; struct smu_table *table = &smu_table->driver_table; + if (numbytes > MAX_SW_I2C_COMMANDS) { + dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", + numbytes, MAX_SW_I2C_COMMANDS); + return -EINVAL; + } + memset(&req, 0, sizeof(req)); - arcturus_fill_eeprom_i2c_req(&req, false, address, numbytes, data); + arcturus_fill_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, + ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true); mutex_unlock(&adev->smu.mutex); @@ -2097,18 +1937,18 @@ static int arcturus_i2c_eeprom_read_data(struct i2c_adapter *control, for (i = 0; i < numbytes; i++) data[i] = res->SwI2cCmds[i].Data; - pr_debug("arcturus_i2c_eeprom_read_data, address = %x, bytes = %d, data :", + dev_dbg(adev->dev, "arcturus_i2c_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); + dev_err(adev->dev, "arcturus_i2c_read_data - error occurred :%x", ret); return ret; } -static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control, +static int arcturus_i2c_write_data(struct i2c_adapter *control, uint8_t address, uint8_t *data, uint32_t numbytes) @@ -2117,15 +1957,21 @@ static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control, SwI2cRequest_t req; struct amdgpu_device *adev = to_amdgpu_device(control); + if (numbytes > MAX_SW_I2C_COMMANDS) { + dev_err(adev->dev, "numbytes requested %d is over max allowed %d\n", + numbytes, MAX_SW_I2C_COMMANDS); + return -EINVAL; + } + memset(&req, 0, sizeof(req)); - arcturus_fill_eeprom_i2c_req(&req, true, address, numbytes, data); + arcturus_fill_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); + ret = smu_cmn_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: ", + dev_dbg(adev->dev, "arcturus_i2c_write(), address = %x, bytes = %d , data: ", (uint16_t)address, numbytes); print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, @@ -2139,12 +1985,12 @@ static int arcturus_i2c_eeprom_write_data(struct i2c_adapter *control, msleep(10); } else - pr_err("arcturus_i2c_write- error occurred :%x", ret); + dev_err(adev->dev, "arcturus_i2c_write- error occurred :%x", ret); return ret; } -static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap, +static int arcturus_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; @@ -2167,18 +2013,18 @@ static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap, 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); + ret = arcturus_i2c_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); + ret = arcturus_i2c_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, MAX_SW_I2C_COMMANDS); } if (ret) { @@ -2195,17 +2041,17 @@ static int arcturus_i2c_eeprom_i2c_xfer(struct i2c_adapter *i2c_adap, 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); + ret = arcturus_i2c_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); + ret = arcturus_i2c_write_data(i2c_adap, + (uint8_t)msgs[i].addr, + data_chunk, (data_size % data_chunk_size) + 2); } if (ret) { @@ -2219,18 +2065,18 @@ fail: return num; } -static u32 arcturus_i2c_eeprom_i2c_func(struct i2c_adapter *adap) +static u32 arcturus_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 const struct i2c_algorithm arcturus_i2c_algo = { + .master_xfer = arcturus_i2c_xfer, + .functionality = arcturus_i2c_func, }; -static int arcturus_i2c_eeprom_control_init(struct i2c_adapter *control) +static int arcturus_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) { struct amdgpu_device *adev = to_amdgpu_device(control); int res; @@ -2238,8 +2084,8 @@ static int arcturus_i2c_eeprom_control_init(struct i2c_adapter *control) 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), "AMDGPU EEPROM"); + control->algo = &arcturus_i2c_algo; + snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); res = i2c_add_adapter(control); if (res) @@ -2248,11 +2094,40 @@ static int arcturus_i2c_eeprom_control_init(struct i2c_adapter *control) return res; } -static void arcturus_i2c_eeprom_control_fini(struct i2c_adapter *control) +static void arcturus_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control) { i2c_del_adapter(control); } +static void arcturus_get_unique_id(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t top32 = 0, bottom32 = 0, smu_version; + uint64_t id; + + if (smu_cmn_get_smc_version(smu, NULL, &smu_version)) { + dev_warn(adev->dev, "Failed to get smu version, cannot get unique_id or serial_number\n"); + return; + } + + /* PPSMC_MSG_ReadSerial* is supported by 54.23.0 and onwards */ + if (smu_version < 0x361700) { + dev_warn(adev->dev, "ReadSerial is only supported by PMFW 54.23.0 and onwards\n"); + return; + } + + /* Get the SN to turn into a Unique ID */ + smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumTop32, &top32); + smu_cmn_send_smc_msg(smu, SMU_MSG_ReadSerialNumBottom32, &bottom32); + + id = ((uint64_t)bottom32 << 32) | top32; + adev->unique_id = id; + /* For Arcturus-and-later, unique_id == serial_number, so convert it to a + * 16-digit HEX string for convenience and backwards-compatibility + */ + sprintf(adev->serial, "%llx", id); +} + static bool arcturus_is_baco_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -2265,32 +2140,25 @@ static bool arcturus_is_baco_supported(struct smu_context *smu) return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false; } -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 int arcturus_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); + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) { - pr_err("Failed to get smu version!\n"); + dev_err(smu->adev->dev, "Failed to get smu version!\n"); return ret; } /* PPSMC_MSG_DFCstateControl is supported by 54.15.0 and onwards */ if (smu_version < 0x360F00) { - pr_err("DFCstateControl is only supported by PMFW 54.15.0 and onwards\n"); + dev_err(smu->adev->dev, "DFCstateControl is only supported by PMFW 54.15.0 and onwards\n"); return -EINVAL; } - return smu_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state, NULL); + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DFCstateControl, state, NULL); } static int arcturus_allow_xgmi_power_down(struct smu_context *smu, bool en) @@ -2298,45 +2166,76 @@ static int arcturus_allow_xgmi_power_down(struct smu_context *smu, bool en) uint32_t smu_version; int ret; - ret = smu_get_smc_version(smu, NULL, &smu_version); + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) { - pr_err("Failed to get smu version!\n"); + dev_err(smu->adev->dev, "Failed to get smu version!\n"); return ret; } /* PPSMC_MSG_GmiPwrDnControl is supported by 54.23.0 and onwards */ if (smu_version < 0x00361700) { - pr_err("XGMI power down control is only supported by PMFW 54.23.0 and onwards\n"); + dev_err(smu->adev->dev, "XGMI power down control is only supported by PMFW 54.23.0 and onwards\n"); return -EINVAL; } if (en) - return smu_send_smc_msg_with_param(smu, + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GmiPwrDnControl, 1, NULL); - return smu_send_smc_msg_with_param(smu, + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GmiPwrDnControl, 0, NULL); } +static const struct throttling_logging_label { + uint32_t feature_mask; + const char *label; +} logging_label[] = { + {(1U << THROTTLER_TEMP_HOTSPOT_BIT), "GPU"}, + {(1U << THROTTLER_TEMP_MEM_BIT), "HBM"}, + {(1U << THROTTLER_TEMP_VR_GFX_BIT), "VR of GFX rail"}, + {(1U << THROTTLER_TEMP_VR_MEM_BIT), "VR of HBM rail"}, + {(1U << THROTTLER_TEMP_VR_SOC_BIT), "VR of SOC rail"}, + {(1U << THROTTLER_VRHOT0_BIT), "VR0 HOT"}, + {(1U << THROTTLER_VRHOT1_BIT), "VR1 HOT"}, +}; +static void arcturus_log_thermal_throttling_event(struct smu_context *smu) +{ + int throttler_idx, throtting_events = 0, buf_idx = 0; + struct amdgpu_device *adev = smu->adev; + uint32_t throttler_status; + char log_buf[256]; + + arcturus_get_smu_metrics_data(smu, + METRICS_THROTTLER_STATUS, + &throttler_status); + + memset(log_buf, 0, sizeof(log_buf)); + for (throttler_idx = 0; throttler_idx < ARRAY_SIZE(logging_label); + throttler_idx++) { + if (throttler_status & logging_label[throttler_idx].feature_mask) { + throtting_events++; + buf_idx += snprintf(log_buf + buf_idx, + sizeof(log_buf) - buf_idx, + "%s%s", + throtting_events > 1 ? " and " : "", + logging_label[throttler_idx].label); + if (buf_idx >= sizeof(log_buf)) { + dev_err(adev->dev, "buffer overflow!\n"); + log_buf[sizeof(log_buf) - 1] = '\0'; + break; + } + } + } + + dev_warn(adev->dev, "WARN: GPU thermal throttling temperature reached, expect performance decrease. %s.\n", + log_buf); +} + 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 */ @@ -2345,15 +2244,11 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .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 = arcturus_set_performance_level, @@ -2361,40 +2256,40 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .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, + .dpm_set_vcn_enable = arcturus_dpm_set_vcn_enable, + .i2c_init = arcturus_i2c_control_init, + .i2c_fini = arcturus_i2c_control_fini, + .get_unique_id = arcturus_get_unique_id, .init_microcode = smu_v11_0_init_microcode, .load_microcode = smu_v11_0_load_microcode, - .init_smc_tables = smu_v11_0_init_smc_tables, + .fini_microcode = smu_v11_0_fini_microcode, + .init_smc_tables = arcturus_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, + /* pptable related */ + .setup_pptable = arcturus_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, + .write_pptable = smu_cmn_write_pptable, .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, - .init_display_count = smu_v11_0_init_display_count, + .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, + .send_smc_msg = smu_cmn_send_smc_msg, + .init_display_count = NULL, .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, + .get_enabled_mask = smu_cmn_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, + .notify_display_change = NULL, .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, + .enable_thermal_alert = smu_v11_0_enable_thermal_alert, + .disable_thermal_alert = smu_v11_0_disable_thermal_alert, + .set_min_dcef_deep_sleep = NULL, .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, @@ -2412,13 +2307,20 @@ static const struct pptable_funcs arcturus_ppt_funcs = { .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, .set_df_cstate = arcturus_set_df_cstate, .allow_xgmi_power_down = arcturus_allow_xgmi_power_down, + .log_thermal_throttling_event = arcturus_log_thermal_throttling_event, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, }; void arcturus_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &arcturus_ppt_funcs; + smu->message_map = arcturus_message_map; + smu->clock_map = arcturus_clk_map; + smu->feature_map = arcturus_feature_mask_map; + smu->table_map = arcturus_table_map; + smu->pwr_src_map = arcturus_pwr_src_map; + smu->workload_map = arcturus_workload_map; } diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c index 753cb2cf6b77..ffe05b7cc1f0 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu7_hwmgr.c @@ -1487,7 +1487,7 @@ static int smu7_update_avfs(struct pp_hwmgr *hwmgr) return 0; } -int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) +static int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) { int tmp_result, result = 0; @@ -1548,12 +1548,6 @@ int smu7_disable_dpm_tasks(struct pp_hwmgr *hwmgr) return result; } -int smu7_reset_asic_tasks(struct pp_hwmgr *hwmgr) -{ - - return 0; -} - static void smu7_init_dpm_defaults(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c index a6c6a793e98e..35ed47ebaf09 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/smu8_hwmgr.c @@ -1879,7 +1879,7 @@ static int smu8_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) return 0; } -int smu8_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) +static int smu8_dpm_update_uvd_dpm(struct pp_hwmgr *hwmgr, bool bgate) { struct smu8_hwmgr *data = hwmgr->backend; struct phm_uvd_clock_voltage_dependency_table *ptable = diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index 675c7cab7cfc..c378a000c934 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -90,7 +90,7 @@ typedef enum { static const ULONG PhwVega10_Magic = (ULONG)(PHM_VIslands_Magic); -struct vega10_power_state *cast_phw_vega10_power_state( +static struct vega10_power_state *cast_phw_vega10_power_state( struct pp_hw_power_state *hw_ps) { PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic), @@ -100,7 +100,7 @@ struct vega10_power_state *cast_phw_vega10_power_state( return (struct vega10_power_state *)hw_ps; } -const struct vega10_power_state *cast_const_phw_vega10_power_state( +static const struct vega10_power_state *cast_const_phw_vega10_power_state( const struct pp_hw_power_state *hw_ps) { PP_ASSERT_WITH_CODE((PhwVega10_Magic == hw_ps->magic), @@ -2330,7 +2330,7 @@ static int vega10_acg_disable(struct pp_hwmgr *hwmgr) { struct vega10_hwmgr *data = hwmgr->backend; - if (data->smu_features[GNLD_ACG].supported && + if (data->smu_features[GNLD_ACG].supported && data->smu_features[GNLD_ACG].enabled) if (!vega10_enable_smc_features(hwmgr, false, data->smu_features[GNLD_ACG].smu_feature_bitmap)) @@ -3905,7 +3905,7 @@ static void vega10_notify_smc_display_change(struct pp_hwmgr *hwmgr, NULL); } -int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +static int vega10_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock_req) { int result = 0; @@ -4672,7 +4672,7 @@ static int vega10_display_configuration_changed_task(struct pp_hwmgr *hwmgr) return result; } -int vega10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) +static int vega10_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) { struct vega10_hwmgr *data = hwmgr->backend; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c index 7783c7fd7ccb..468bdd6f6697 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c @@ -499,7 +499,7 @@ int vega10_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) * @param Result the last failure code * @return result from set temperature range routine */ -int vega10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) +static int vega10_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) { int ret; struct vega10_hwmgr *data = hwmgr->backend; @@ -602,7 +602,7 @@ int vega10_enable_mgpu_fan_boost(struct pp_hwmgr *hwmgr) * @param Result the last failure code * @return result from set temperature range routine */ -int vega10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) +static int vega10_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) { /* If the fantable setup has failed we could have disabled * PHM_PlatformCaps_MicrocodeFanControl even after diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c index f4d1692cccf3..a678a67f1c0d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_hwmgr.c @@ -1436,7 +1436,7 @@ static int vega12_notify_smc_display_change(struct pp_hwmgr *hwmgr, return 0; } -int vega12_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +static int vega12_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock_req) { int result = 0; @@ -2404,7 +2404,7 @@ static int vega12_display_configuration_changed_task(struct pp_hwmgr *hwmgr) return result; } -int vega12_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) +static int vega12_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) { struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c index 9817f7a5ed29..195d8539fbb4 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_processpptables.c @@ -263,7 +263,7 @@ static int init_powerplay_table_information( return result; } -int vega12_pp_tables_initialize(struct pp_hwmgr *hwmgr) +static int vega12_pp_tables_initialize(struct pp_hwmgr *hwmgr) { int result = 0; const ATOM_Vega12_POWERPLAYTABLE *powerplay_table; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c index c85806a6f62e..c15b9756025d 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega12_thermal.c @@ -251,7 +251,7 @@ int vega12_thermal_stop_thermal_controller(struct pp_hwmgr *hwmgr) * @param Result the last failure code * @return result from set temperature range routine */ -int vega12_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) +static int vega12_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) { int ret; struct vega12_hwmgr *data = (struct vega12_hwmgr *)(hwmgr->backend); @@ -274,7 +274,7 @@ int vega12_thermal_setup_fan_table(struct pp_hwmgr *hwmgr) * @param Result the last failure code * @return result from set temperature range routine */ -int vega12_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) +static int vega12_thermal_start_smc_fan_control(struct pp_hwmgr *hwmgr) { /* If the fantable setup has failed we could have disabled * PHM_PlatformCaps_MicrocodeFanControl even after diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c index 9ff470f1b826..3b8839641770 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega20_hwmgr.c @@ -1981,7 +1981,7 @@ static int vega20_upload_dpm_max_level(struct pp_hwmgr *hwmgr, uint32_t feature_ return ret; } -int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) +static int vega20_enable_disable_vce_dpm(struct pp_hwmgr *hwmgr, bool enable) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); @@ -2253,7 +2253,7 @@ static int vega20_read_sensor(struct pp_hwmgr *hwmgr, int idx, return ret; } -int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr, +static int vega20_display_clock_voltage_request(struct pp_hwmgr *hwmgr, struct pp_display_clock_request *clock_req) { int result = 0; @@ -3589,7 +3589,7 @@ static int vega20_display_configuration_changed_task(struct pp_hwmgr *hwmgr) return result; } -int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) +static int vega20_enable_disable_uvd_dpm(struct pp_hwmgr *hwmgr, bool enable) { struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend); diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h index 4d1c2a44a8b6..074458eb5407 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h @@ -119,6 +119,7 @@ struct smu_temperature_range { int mem_min; int mem_crit_max; int mem_emergency_max; + int software_shutdown_temp; }; struct smu_state_validation_block { @@ -145,7 +146,6 @@ struct smu_power_state { struct smu_state_pcie_block pcie; struct smu_state_display_block display; struct smu_state_memroy_block memory; - struct smu_temperature_range temperatures; struct smu_state_software_algorithm_block software; struct smu_uvd_clocks uvd_clocks; struct smu_hw_power_state hardware; @@ -259,7 +259,7 @@ struct smu_table_context void *max_sustainable_clocks; struct smu_bios_boot_up_values boot_values; void *driver_pptable; - struct smu_table *tables; + struct smu_table tables[SMU_TABLE_COUNT]; /* * The driver table is just a staging buffer for * uploading/downloading content from the SMU. @@ -292,8 +292,10 @@ struct smu_dpm_context { struct smu_power_gate { bool uvd_gated; bool vce_gated; - bool vcn_gated; - bool jpeg_gated; + atomic_t vcn_gated; + atomic_t jpeg_gated; + struct mutex vcn_gate_lock; + struct mutex jpeg_gate_lock; }; struct smu_power_context { @@ -352,13 +354,44 @@ struct smu_baco_context bool platform_support; }; +struct pstates_clk_freq { + uint32_t min; + uint32_t standard; + uint32_t peak; +}; + +struct smu_umd_pstate_table { + struct pstates_clk_freq gfxclk_pstate; + struct pstates_clk_freq socclk_pstate; + struct pstates_clk_freq uclk_pstate; + struct pstates_clk_freq vclk_pstate; + struct pstates_clk_freq dclk_pstate; +}; + +struct cmn2asic_msg_mapping { + int valid_mapping; + int map_to; + int valid_in_vf; +}; + +struct cmn2asic_mapping { + int valid_mapping; + int map_to; +}; + #define WORKLOAD_POLICY_MAX 7 struct smu_context { struct amdgpu_device *adev; - struct amdgpu_irq_src *irq_source; + struct amdgpu_irq_src irq_source; const struct pptable_funcs *ppt_funcs; + const struct cmn2asic_msg_mapping *message_map; + const struct cmn2asic_mapping *clock_map; + const struct cmn2asic_mapping *feature_map; + const struct cmn2asic_mapping *table_map; + const struct cmn2asic_mapping *pwr_src_map; + const struct cmn2asic_mapping *workload_map; struct mutex mutex; struct mutex sensor_lock; struct mutex metrics_lock; @@ -371,17 +404,19 @@ struct smu_context struct smu_feature smu_feature; struct amd_pp_display_configuration *display_config; struct smu_baco_context smu_baco; + struct smu_temperature_range thermal_range; void *od_settings; #if defined(CONFIG_DEBUG_FS) struct dentry *debugfs_sclk; #endif + struct smu_umd_pstate_table pstate_table; uint32_t pstate_sclk; uint32_t pstate_mclk; bool od_enabled; - uint32_t power_limit; - uint32_t default_power_limit; + uint32_t current_power_limit; + uint32_t max_power_limit; /* soft pptable */ uint32_t ppt_offset_bytes; @@ -411,21 +446,13 @@ struct smu_context bool uploading_custom_pp_table; bool dc_controlled_by_gpio; + + struct work_struct throttling_logging_work; }; struct i2c_adapter; struct pptable_funcs { - int (*alloc_dpm_context)(struct smu_context *smu); - int (*store_powerplay_table)(struct smu_context *smu); - int (*check_powerplay_table)(struct smu_context *smu); - int (*append_powerplay_table)(struct smu_context *smu); - int (*get_smu_msg_index)(struct smu_context *smu, uint32_t index); - int (*get_smu_clk_index)(struct smu_context *smu, uint32_t index); - int (*get_smu_feature_index)(struct smu_context *smu, uint32_t index); - 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_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); @@ -454,8 +481,7 @@ struct pptable_funcs { *clocks); int (*get_power_profile_mode)(struct smu_context *smu, char *buf); 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_vcn_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); @@ -463,41 +489,29 @@ struct pptable_funcs { int (*display_config_changed)(struct smu_context *smu); int (*apply_clocks_adjust_rules)(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, - enum amd_dpm_forced_level level, - uint32_t *sclk_mask, - uint32_t *mclk_mask, - uint32_t *soc_mask); int (*set_cpu_power_state)(struct smu_context *smu); 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); int (*get_fan_speed_percent)(struct smu_context *smu, uint32_t *speed); int (*get_fan_speed_rpm)(struct smu_context *smu, uint32_t *speed); - int (*set_watermarks_table)(struct smu_context *smu, void *watermarks, + int (*set_watermarks_table)(struct smu_context *smu, struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges); - int (*get_current_clk_freq_by_table)(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t *value); int (*get_thermal_temperature_range)(struct smu_context *smu, struct smu_temperature_range *range); 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_default_od_settings)(struct smu_context *smu); int (*set_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level); 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 (*get_power_limit)(struct smu_context *smu); int (*set_df_cstate)(struct smu_context *smu, enum pp_df_cstate state); int (*allow_xgmi_power_down)(struct smu_context *smu, bool en); 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 (*i2c_init)(struct smu_context *smu, struct i2c_adapter *control); + void (*i2c_fini)(struct smu_context *smu, struct i2c_adapter *control); + void (*get_unique_id)(struct smu_context *smu); 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); + void (*fini_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); @@ -505,17 +519,10 @@ struct pptable_funcs { 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_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); @@ -523,16 +530,20 @@ struct pptable_funcs { int (*system_features_control)(struct smu_context *smu, bool en); int (*send_smc_msg_with_param)(struct smu_context *smu, enum smu_message_type msg, uint32_t param, uint32_t *read_arg); + int (*send_smc_msg)(struct smu_context *smu, + enum smu_message_type msg, + uint32_t *read_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 (*feature_is_enabled)(struct smu_context *smu, enum smu_feature_mask mask); + int (*disable_all_features_with_exception)(struct smu_context *smu, enum smu_feature_mask mask); int (*notify_display_change)(struct smu_context *smu); 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 (*stop_thermal_control)(struct smu_context *smu); - int (*set_deep_sleep_dcefclk)(struct smu_context *smu, uint32_t clk); + int (*enable_thermal_alert)(struct smu_context *smu); + int (*disable_thermal_alert)(struct smu_context *smu); + int (*set_min_dcef_deep_sleep)(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, bool cc6_disable, bool pstate_disable, @@ -560,6 +571,7 @@ struct pptable_funcs { int (*set_fan_speed_rpm)(struct smu_context *smu, uint32_t speed); int (*set_xgmi_pstate)(struct smu_context *smu, uint32_t pstate); int (*gfx_off_control)(struct smu_context *smu, bool enable); + uint32_t (*get_gfx_off_status)(struct smu_context *smu); int (*register_irq_handler)(struct smu_context *smu); int (*set_azalia_d3_pme)(struct smu_context *smu); int (*get_max_sustainable_clocks_by_dc)(struct smu_context *smu, struct pp_smu_nv_clock_table *max_clocks); @@ -568,15 +580,82 @@ struct pptable_funcs { int (*baco_set_state)(struct smu_context *smu, enum smu_baco_state state); int (*baco_enter)(struct smu_context *smu); int (*baco_exit)(struct smu_context *smu); + bool (*mode1_reset_is_support)(struct smu_context *smu); + int (*mode1_reset)(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 (*set_power_source)(struct smu_context *smu, enum smu_power_src_type power_src); -}; - + void (*log_thermal_throttling_event)(struct smu_context *smu); + size_t (*get_pp_feature_mask)(struct smu_context *smu, char *buf); + int (*set_pp_feature_mask)(struct smu_context *smu, uint64_t new_mask); +}; + +typedef enum { + METRICS_CURR_GFXCLK, + METRICS_CURR_SOCCLK, + METRICS_CURR_UCLK, + METRICS_CURR_VCLK, + METRICS_CURR_VCLK1, + METRICS_CURR_DCLK, + METRICS_CURR_DCLK1, + METRICS_CURR_FCLK, + METRICS_CURR_DCEFCLK, + METRICS_AVERAGE_GFXCLK, + METRICS_AVERAGE_SOCCLK, + METRICS_AVERAGE_FCLK, + METRICS_AVERAGE_UCLK, + METRICS_AVERAGE_VCLK, + METRICS_AVERAGE_DCLK, + METRICS_AVERAGE_GFXACTIVITY, + METRICS_AVERAGE_MEMACTIVITY, + METRICS_AVERAGE_VCNACTIVITY, + METRICS_AVERAGE_SOCKETPOWER, + METRICS_TEMPERATURE_EDGE, + METRICS_TEMPERATURE_HOTSPOT, + METRICS_TEMPERATURE_MEM, + METRICS_TEMPERATURE_VRGFX, + METRICS_TEMPERATURE_VRSOC, + METRICS_TEMPERATURE_VRMEM, + METRICS_THROTTLER_STATUS, + METRICS_CURR_FANSPEED, +} MetricsMember_t; + +enum smu_cmn2asic_mapping_type { + CMN2ASIC_MAPPING_MSG, + CMN2ASIC_MAPPING_CLK, + CMN2ASIC_MAPPING_FEATURE, + CMN2ASIC_MAPPING_TABLE, + CMN2ASIC_MAPPING_PWR, + CMN2ASIC_MAPPING_WORKLOAD, +}; + +#define MSG_MAP(msg, index, valid_in_vf) \ + [SMU_MSG_##msg] = {1, (index), (valid_in_vf)} + +#define CLK_MAP(clk, index) \ + [SMU_##clk] = {1, (index)} + +#define FEA_MAP(fea) \ + [SMU_FEATURE_##fea##_BIT] = {1, FEATURE_##fea##_BIT} + +#define TAB_MAP(tab) \ + [SMU_TABLE_##tab] = {1, TABLE_##tab} + +#define TAB_MAP_VALID(tab) \ + [SMU_TABLE_##tab] = {1, TABLE_##tab} + +#define TAB_MAP_INVALID(tab) \ + [SMU_TABLE_##tab] = {0, TABLE_##tab} + +#define PWR_MAP(tab) \ + [SMU_POWER_SOURCE_##tab] = {1, POWER_SOURCE_##tab} + +#define WORKLOAD_MAP(profile, workload) \ + [profile] = {1, (workload)} + +#if !defined(SWSMU_CODE_LAYER_L2) && !defined(SWSMU_CODE_LAYER_L3) && !defined(SWSMU_CODE_LAYER_L4) int smu_load_microcode(struct smu_context *smu); int smu_check_fw_status(struct smu_context *smu); @@ -587,8 +666,7 @@ 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); + bool max_setting); 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); @@ -649,36 +727,17 @@ 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); +bool smu_mode1_reset_is_support(struct smu_context *smu); +int smu_mode1_reset(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, - uint8_t **addr); - 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, - enum smu_feature_mask mask); -extern int smu_feature_set_enabled(struct smu_context *smu, - enum smu_feature_mask mask, bool enable); -extern int smu_feature_is_supported(struct smu_context *smu, - enum smu_feature_mask mask); -extern int smu_feature_set_supported(struct smu_context *smu, - enum smu_feature_mask mask, bool enable); - -int smu_update_table(struct smu_context *smu, enum smu_table_id table_index, int argument, - 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); 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); @@ -702,32 +761,19 @@ extern int smu_handle_task(struct smu_context *smu, 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, bool lock_needed); + uint32_t *min, uint32_t *max); int smu_set_soft_freq_range(struct smu_context *smu, enum smu_clk_type clk_type, - uint32_t min, uint32_t max, bool lock_needed); -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); int smu_set_ac_dc(struct smu_context *smu); -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); + uint32_t mask); int smu_set_mp1_state(struct smu_context *smu, enum pp_mp1_state mp1_state); int smu_set_df_cstate(struct smu_context *smu, @@ -744,6 +790,7 @@ int smu_get_uclk_dpm_states(struct smu_context *smu, 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); +int smu_get_status_gfxoff(struct amdgpu_device *adev, uint32_t *value); #endif +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h index e07478b6ac04..79afb132164e 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h +++ b/drivers/gpu/drm/amd/powerplay/inc/arcturus_ppsmc.h @@ -117,6 +117,9 @@ #define PPSMC_MSG_GmiPwrDnControl 0x3D #define PPSMC_Message_Count 0x3E +#define PPSMC_MSG_ReadSerialNumTop32 0x40 +#define PPSMC_MSG_ReadSerialNumBottom32 0x41 + typedef uint32_t PPSMC_Result; typedef uint32_t PPSMC_Msg; #pragma pack(pop) 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 index 8b82059d97e7..43d43d6addc0 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_arcturus.h @@ -200,6 +200,8 @@ #define THROTTLER_PPM_BIT 13 #define THROTTLER_FIT_BIT 14 #define THROTTLER_APCC_BIT 15 +#define THROTTLER_VRHOT0_BIT 16 +#define THROTTLER_VRHOT1_BIT 17 // Table transfer status #define TABLE_TRANSFER_OK 0x0 @@ -742,6 +744,9 @@ typedef struct { uint16_t SocketPowerLpfTau; + uint16_t VcnClkAverageLpfTau; + uint16_t padding16; + // Padding - ignore uint32_t MmHubPadding[8]; // SMU internal use } DriverSmuConfig_t; @@ -767,9 +772,12 @@ typedef struct { uint32_t ThrottlerStatus ; uint16_t CurrFanSpeed ; - uint16_t Padding16; + uint16_t AverageVclkFrequency ; + uint16_t AverageDclkFrequency ; + uint16_t VcnActivityPercentage ; + uint32_t EnergyAccumulator ; - uint32_t Padding[4]; + uint32_t Padding[2]; // Padding - ignore uint32_t MmHubPadding[8]; // SMU internal use diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_sienna_cichlid.h b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_sienna_cichlid.h new file mode 100644 index 000000000000..aa2708fccb6d --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu11_driver_if_sienna_cichlid.h @@ -0,0 +1,1242 @@ +/* + * Copyright 2020 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_SIENNA_CICHLID_H__ +#define __SMU11_DRIVER_IF_SIENNA_CICHLID_H__ + +// *** IMPORTANT *** +// SMU TEAM: Always increment the interface version if +// any structure is changed in this file +#define SMU11_DRIVER_IF_VERSION 0x34 + +#define PPTABLE_Sienna_Cichlid_SMU_VERSION 5 + +#define NUM_GFXCLK_DPM_LEVELS 16 +#define NUM_SMNCLK_DPM_LEVELS 2 +#define NUM_SOCCLK_DPM_LEVELS 8 +#define NUM_MP0CLK_DPM_LEVELS 2 +#define NUM_DCLK_DPM_LEVELS 8 +#define NUM_VCLK_DPM_LEVELS 8 +#define NUM_DCEFCLK_DPM_LEVELS 8 +#define NUM_PHYCLK_DPM_LEVELS 8 +#define NUM_DISPCLK_DPM_LEVELS 8 +#define NUM_PIXCLK_DPM_LEVELS 8 +#define NUM_DTBCLK_DPM_LEVELS 8 +#define NUM_UCLK_DPM_LEVELS 4 +#define NUM_MP1CLK_DPM_LEVELS 2 +#define NUM_LINK_LEVELS 2 +#define NUM_FCLK_DPM_LEVELS 8 +#define NUM_XGMI_LEVELS 2 +#define NUM_XGMI_PSTATE_LEVELS 4 +#define NUM_OD_FAN_MAX_POINTS 6 + +#define MAX_GFXCLK_DPM_LEVEL (NUM_GFXCLK_DPM_LEVELS - 1) +#define MAX_SMNCLK_DPM_LEVEL (NUM_SMNCLK_DPM_LEVELS - 1) +#define MAX_SOCCLK_DPM_LEVEL (NUM_SOCCLK_DPM_LEVELS - 1) +#define MAX_MP0CLK_DPM_LEVEL (NUM_MP0CLK_DPM_LEVELS - 1) +#define MAX_DCLK_DPM_LEVEL (NUM_DCLK_DPM_LEVELS - 1) +#define MAX_VCLK_DPM_LEVEL (NUM_VCLK_DPM_LEVELS - 1) +#define MAX_DCEFCLK_DPM_LEVEL (NUM_DCEFCLK_DPM_LEVELS - 1) +#define MAX_DISPCLK_DPM_LEVEL (NUM_DISPCLK_DPM_LEVELS - 1) +#define MAX_PIXCLK_DPM_LEVEL (NUM_PIXCLK_DPM_LEVELS - 1) +#define MAX_PHYCLK_DPM_LEVEL (NUM_PHYCLK_DPM_LEVELS - 1) +#define MAX_DTBCLK_DPM_LEVEL (NUM_DTBCLK_DPM_LEVELS - 1) +#define MAX_UCLK_DPM_LEVEL (NUM_UCLK_DPM_LEVELS - 1) +#define MAX_MP1CLK_DPM_LEVEL (NUM_MP1CLK_DPM_LEVELS - 1) +#define MAX_LINK_LEVEL (NUM_LINK_LEVELS - 1) +#define MAX_FCLK_DPM_LEVEL (NUM_FCLK_DPM_LEVELS - 1) + +//Gemini Modes +#define PPSMC_GeminiModeNone 0 //Single GPU board +#define PPSMC_GeminiModeMaster 1 //Master GPU on a Gemini board +#define PPSMC_GeminiModeSlave 2 //Slave GPU on a Gemini board + +// Feature Control Defines +// DPM +#define FEATURE_DPM_PREFETCHER_BIT 0 +#define FEATURE_DPM_GFXCLK_BIT 1 +#define FEATURE_DPM_GFX_GPO_BIT 2 +#define FEATURE_DPM_UCLK_BIT 3 +#define FEATURE_DPM_FCLK_BIT 4 +#define FEATURE_DPM_SOCCLK_BIT 5 +#define FEATURE_DPM_MP0CLK_BIT 6 +#define FEATURE_DPM_LINK_BIT 7 +#define FEATURE_DPM_DCEFCLK_BIT 8 +#define FEATURE_DPM_XGMI_BIT 9 +#define FEATURE_MEM_VDDCI_SCALING_BIT 10 +#define FEATURE_MEM_MVDD_SCALING_BIT 11 + +//Idle +#define FEATURE_DS_GFXCLK_BIT 12 +#define FEATURE_DS_SOCCLK_BIT 13 +#define FEATURE_DS_FCLK_BIT 14 +#define FEATURE_DS_LCLK_BIT 15 +#define FEATURE_DS_DCEFCLK_BIT 16 +#define FEATURE_DS_UCLK_BIT 17 +#define FEATURE_GFX_ULV_BIT 18 +#define FEATURE_FW_DSTATE_BIT 19 +#define FEATURE_GFXOFF_BIT 20 +#define FEATURE_BACO_BIT 21 +#define FEATURE_MM_DPM_PG_BIT 22 +#define FEATURE_SPARE_23_BIT 23 +//Throttler/Response +#define FEATURE_PPT_BIT 24 +#define FEATURE_TDC_BIT 25 +#define FEATURE_APCC_PLUS_BIT 26 +#define FEATURE_GTHR_BIT 27 +#define FEATURE_ACDC_BIT 28 +#define FEATURE_VR0HOT_BIT 29 +#define FEATURE_VR1HOT_BIT 30 +#define FEATURE_FW_CTF_BIT 31 +#define FEATURE_FAN_CONTROL_BIT 32 +#define FEATURE_THERMAL_BIT 33 +#define FEATURE_GFX_DCS_BIT 34 +//VF +#define FEATURE_RM_BIT 35 +#define FEATURE_LED_DISPLAY_BIT 36 +//Other +#define FEATURE_GFX_SS_BIT 37 +#define FEATURE_OUT_OF_BAND_MONITOR_BIT 38 +#define FEATURE_TEMP_DEPENDENT_VMIN_BIT 39 + +#define FEATURE_MMHUB_PG_BIT 40 +#define FEATURE_ATHUB_PG_BIT 41 +#define FEATURE_APCC_DFLL_BIT 42 +#define FEATURE_DF_SUPERV_BIT 43 +#define FEATURE_RSMU_SMN_CG_BIT 44 +#define FEATURE_DF_CSTATE_BIT 45 +#define FEATURE_2_STEP_PSTATE_BIT 46 +#define FEATURE_SMNCLK_DPM_BIT 47 +#define FEATURE_SPARE_48_BIT 48 +#define FEATURE_GFX_EDC_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 + +//For use with feature control messages +typedef enum { + FEATURE_PWR_ALL, + FEATURE_PWR_S5, + FEATURE_PWR_BACO, + FEATURE_PWR_SOC, + FEATURE_PWR_GFX, + FEATURE_PWR_DOMAIN_COUNT, +} FEATURE_PWR_DOMAIN_e; + + +// Debug Overrides Bitmask +#define DPM_OVERRIDE_DISABLE_FCLK_PID 0x00000001 +#define DPM_OVERRIDE_DISABLE_UCLK_PID 0x00000002 +#define DPM_OVERRIDE_DISABLE_VOLT_LINK_VCN_FCLK 0x00000004 +#define DPM_OVERRIDE_ENABLE_FREQ_LINK_VCLK_FCLK 0x00000008 +#define DPM_OVERRIDE_ENABLE_FREQ_LINK_DCLK_FCLK 0x00000010 +#define DPM_OVERRIDE_ENABLE_FREQ_LINK_GFXCLK_SOCCLK 0x00000020 +#define DPM_OVERRIDE_ENABLE_FREQ_LINK_GFXCLK_UCLK 0x00000040 +#define DPM_OVERRIDE_DISABLE_VOLT_LINK_DCE_FCLK 0x00000080 +#define DPM_OVERRIDE_DISABLE_VOLT_LINK_MP0_SOCCLK 0x00000100 +#define DPM_OVERRIDE_DISABLE_DFLL_PLL_SHUTDOWN 0x00000200 +#define DPM_OVERRIDE_DISABLE_MEMORY_TEMPERATURE_READ 0x00000400 +#define DPM_OVERRIDE_DISABLE_VOLT_LINK_VCN_DCEFCLK 0x00000800 +#define DPM_OVERRIDE_DISABLE_FAST_FCLK_TIMER 0x00001000 +#define DPM_OVERRIDE_DISABLE_VCN_PG 0x00002000 +#define DPM_OVERRIDE_DISABLE_FMAX_VMAX 0x00004000 + +// 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_MEM0_BIT 5 +#define THROTTLER_TEMP_VR_MEM1_BIT 6 +#define THROTTLER_TEMP_VR_SOC_BIT 7 +#define THROTTLER_TEMP_LIQUID0_BIT 8 +#define THROTTLER_TEMP_LIQUID1_BIT 9 +#define THROTTLER_TEMP_PLX_BIT 10 +#define THROTTLER_TDC_GFX_BIT 11 +#define THROTTLER_TDC_SOC_BIT 12 +#define THROTTLER_PPT0_BIT 13 +#define THROTTLER_PPT1_BIT 14 +#define THROTTLER_PPT2_BIT 15 +#define THROTTLER_PPT3_BIT 16 +#define THROTTLER_FIT_BIT 17 +#define THROTTLER_PPM_BIT 18 +#define THROTTLER_APCC_BIT 19 + +// FW DState Features Control Bits +// FW DState Features Control Bits +#define FW_DSTATE_SOC_ULV_BIT 0 +#define FW_DSTATE_G6_HSR_BIT 1 +#define FW_DSTATE_G6_PHY_VDDCI_OFF_BIT 2 +#define FW_DSTATE_MP0_DS_BIT 3 +#define FW_DSTATE_SMN_DS_BIT 4 +#define FW_DSTATE_MP1_DS_BIT 5 +#define FW_DSTATE_MP1_WHISPER_MODE_BIT 6 +#define FW_DSTATE_SOC_LIV_MIN_BIT 7 +#define FW_DSTATE_SOC_PLL_PWRDN_BIT 8 +#define FW_DSTATE_MEM_PLL_PWRDN_BIT 9 +#define FW_DSTATE_OPTIMIZE_MALL_REFRESH_BIT 10 +#define FW_DSTATE_MEM_PSI_BIT 11 + +#define FW_DSTATE_SOC_ULV_MASK (1 << FW_DSTATE_SOC_ULV_BIT ) +#define FW_DSTATE_G6_HSR_MASK (1 << FW_DSTATE_G6_HSR_BIT ) +#define FW_DSTATE_G6_PHY_VDDCI_OFF_MASK (1 << FW_DSTATE_G6_PHY_VDDCI_OFF_BIT ) +#define FW_DSTATE_MP1_DS_MASK (1 << FW_DSTATE_MP1_DS_BIT ) +#define FW_DSTATE_MP0_DS_MASK (1 << FW_DSTATE_MP0_DS_BIT ) +#define FW_DSTATE_SMN_DS_MASK (1 << FW_DSTATE_SMN_DS_BIT ) +#define FW_DSTATE_MP1_WHISPER_MODE_MASK (1 << FW_DSTATE_MP1_WHISPER_MODE_BIT ) +#define FW_DSTATE_SOC_LIV_MIN_MASK (1 << FW_DSTATE_SOC_LIV_MIN_BIT ) +#define FW_DSTATE_SOC_PLL_PWRDN_MASK (1 << FW_DSTATE_SOC_PLL_PWRDN_BIT ) +#define FW_DSTATE_MEM_PLL_PWRDN_MASK (1 << FW_DSTATE_MEM_PLL_PWRDN_BIT ) +#define FW_DSTATE_OPTIMIZE_MALL_REFRESH_MASK (1 << FW_DSTATE_OPTIMIZE_MALL_REFRESH_BIT ) +#define FW_DSTATE_MEM_PSI_MASK (1 << FW_DSTATE_MEM_PSI_BIT ) + +// GFX GPO Feature Contains PACE and DEM sub features +#define GFX_GPO_PACE_BIT 0 +#define GFX_GPO_DEM_BIT 1 + +#define GFX_GPO_PACE_MASK (1 << GFX_GPO_PACE_BIT) +#define GFX_GPO_DEM_MASK (1 << GFX_GPO_DEM_BIT ) + +#define GPO_UPDATE_REQ_UCLKDPM_MASK 0x1 +#define GPO_UPDATE_REQ_FCLKDPM_MASK 0x2 +#define GPO_UPDATE_REQ_MALLHIT_MASK 0x4 + + +//LED Display Mask & Control Bits +#define LED_DISPLAY_GFX_DPM_BIT 0 +#define LED_DISPLAY_PCIE_BIT 1 +#define LED_DISPLAY_ERROR_BIT 2 + +//RLC Pace Table total number of levels +#define RLC_PACE_TABLE_NUM_LEVELS 16 + +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; + +//I2C Interface +#define NUM_I2C_CONTROLLERS 16 + +#define I2C_CONTROLLER_ENABLED 1 +#define I2C_CONTROLLER_DISABLED 0 + +#define MAX_SW_I2C_COMMANDS 24 + +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_VDDCI, + I2C_CONTROLLER_NAME_VR_MVDD, + I2C_CONTROLLER_NAME_LIQUID0, + I2C_CONTROLLER_NAME_LIQUID1, + I2C_CONTROLLER_NAME_PLX, + I2C_CONTROLLER_NAME_OTHER, + 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_VDDCI, + I2C_CONTROLLER_THROTTLER_VR_MVDD, + I2C_CONTROLLER_THROTTLER_LIQUID0, + I2C_CONTROLLER_THROTTLER_LIQUID1, + I2C_CONTROLLER_THROTTLER_PLX, + I2C_CONTROLLER_THROTTLER_INA3221, + I2C_CONTROLLER_THROTTLER_COUNT, +} I2cControllerThrottler_e; + +typedef enum { + I2C_CONTROLLER_PROTOCOL_VR_XPDE132G5, + I2C_CONTROLLER_PROTOCOL_VR_IR35217, + I2C_CONTROLLER_PROTOCOL_TMP_TMP102A, + I2C_CONTROLLER_PROTOCOL_INA3221, + I2C_CONTROLLER_PROTOCOL_COUNT, +} I2cControllerProtocol_e; + +typedef struct { + uint8_t Enabled; + uint8_t Speed; + uint8_t SlaveAddress; + uint8_t ControllerPort; + uint8_t ControllerName; + uint8_t ThermalThrotter; + uint8_t I2cProtocol; + uint8_t PaddingConfig; +} 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; + +typedef enum { + FAN_MODE_AUTO = 0, + FAN_MODE_MANUAL_LINEAR, +} FanMode_e; + +#define CMDCONFIG_STOP_BIT 0 +#define CMDCONFIG_RESTART_BIT 1 +#define CMDCONFIG_READWRITE_BIT 2 //bit should be 0 for read, 1 for write + +#define CMDCONFIG_STOP_MASK (1 << CMDCONFIG_STOP_BIT) +#define CMDCONFIG_RESTART_MASK (1 << CMDCONFIG_RESTART_BIT) +#define CMDCONFIG_READWRITE_MASK (1 << CMDCONFIG_READWRITE_BIT) + +typedef struct { + uint8_t ReadWriteData; //Return data for read. Data to send for write + uint8_t CmdConfig; //Includes whether associated command should have a stop or restart command, and is a read or write +} SwI2cCmd_t; //SW I2C Command Table + +typedef struct { + uint8_t I2CcontrollerPort; //CKSVII2C0(0) or //CKSVII2C1(1) + uint8_t I2CSpeed; //Use I2cSpeed_e to indicate speed to select + uint8_t SlaveAddress; //Slave address of device + uint8_t NumCmds; //Number of commands + + SwI2cCmd_t SwI2cCmds[MAX_SW_I2C_COMMANDS]; +} SwI2cRequest_t; // SW I2C Request Table + +typedef struct { + SwI2cRequest_t SwI2cRequest; + + uint32_t Spare[8]; + uint32_t MmHubPadding[8]; // SMU internal use +} SwI2cRequestExternal_t; + +//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 a; // store in fixed point, [31:20] signed integer, [19:0] fractional bits + uint32_t b; // store in fixed point, [31:20] signed integer, [19:0] fractional bits + uint32_t c; // store in fixed point, [31:20] signed integer, [19:0] fractional bits +} QuadraticFixedPoint_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; + +//Piecewise linear droop model, Sienna_Cichlid currently used only for GFX DFLL +#define NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS 5 +typedef enum { + PIECEWISE_LINEAR_FUSED_MODEL = 0, + PIECEWISE_LINEAR_PP_MODEL, + QUADRATIC_PP_MODEL, +} DfllDroopModelSelect_e; + +typedef struct { + uint32_t Fset[NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS]; //in GHz, store in IEEE float format + uint32_t Vdroop[NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS]; //in V , store in IEEE float format +}PiecewiseLinearDroopInt_t; + +typedef enum { + GFXCLK_SOURCE_PLL = 0, + GFXCLK_SOURCE_DFLL, + GFXCLK_SOURCE_COUNT, +} GFXCLK_SOURCE_e; + +//Only Clks that have DPM descriptors are listed here +typedef enum { + PPCLK_GFXCLK = 0, + PPCLK_SOCCLK, + PPCLK_UCLK, + PPCLK_FCLK, + PPCLK_DCLK_0, + PPCLK_VCLK_0, + PPCLK_DCLK_1, + PPCLK_VCLK_1, + PPCLK_DCEFCLK, + PPCLK_DISPCLK, + PPCLK_PIXCLK, + PPCLK_PHYCLK, + PPCLK_DTBCLK, + PPCLK_COUNT, +} PPCLK_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 { + UCLK_DIV_BY_1 = 0, + UCLK_DIV_BY_2, + UCLK_DIV_BY_4, + UCLK_DIV_BY_8, +} UCLK_DIV_e; + +typedef enum { + GPIO_INT_POLARITY_ACTIVE_LOW = 0, + GPIO_INT_POLARITY_ACTIVE_HIGH, +} GpioIntPolarity_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 = 0, // x1 + XGMI_LINK_WIDTH_2, // x2 + XGMI_LINK_WIDTH_4, // x4 + XGMI_LINK_WIDTH_8, // x8 + XGMI_LINK_WIDTH_9, // x9 + XGMI_LINK_WIDTH_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 enum { + PPT_THROTTLER_PPT0, + PPT_THROTTLER_PPT1, + PPT_THROTTLER_PPT2, + PPT_THROTTLER_PPT3, + PPT_THROTTLER_COUNT +} PPT_THROTTLER_e; + +typedef enum { + TEMP_EDGE, + TEMP_HOTSPOT, + TEMP_MEM, + TEMP_VR_GFX, + TEMP_VR_MEM0, + TEMP_VR_MEM1, + TEMP_VR_SOC, + TEMP_LIQUID0, + TEMP_LIQUID1, + TEMP_PLX, + TEMP_COUNT, +} TEMP_e; + +typedef enum { + TDC_THROTTLER_GFX, + TDC_THROTTLER_SOC, + TDC_THROTTLER_COUNT +} TDC_THROTTLER_e; + +typedef enum { + CUSTOMER_VARIANT_ROW, + CUSTOMER_VARIANT_FALCON, + CUSTOMER_VARIANT_COUNT, +} CUSTOMER_VARIANT_e; + +// Used for 2-step UCLK DPM change workaround +typedef struct { + uint16_t Fmin; + uint16_t Fmax; +} UclkDpmChangeRange_t; + +typedef struct { + // MAJOR SECTION: SKU PARAMETERS + + uint32_t Version; + + // SECTION: Feature Enablement + uint32_t FeaturesToRun[NUM_FEATURES / 32]; + + // SECTION: Infrastructure Limits + uint16_t SocketPowerLimitAc[PPT_THROTTLER_COUNT]; // Watts + uint16_t SocketPowerLimitAcTau[PPT_THROTTLER_COUNT]; // Time constant of LPF in ms + uint16_t SocketPowerLimitDc[PPT_THROTTLER_COUNT]; // Watts + uint16_t SocketPowerLimitDcTau[PPT_THROTTLER_COUNT]; // Time constant of LPF in ms + + uint16_t TdcLimit[TDC_THROTTLER_COUNT]; // Amps + uint16_t TdcLimitTau[TDC_THROTTLER_COUNT]; // Time constant of LPF in ms + + uint16_t TemperatureLimit[TEMP_COUNT]; // Celcius + + uint32_t FitLimit; // Failures in time (failures per million parts over the defined lifetime) + + // SECTION: Power Configuration + uint8_t TotalPowerConfig; //0-TDP, 1-TGP, 2-TCP Estimated, 3-TCP Measured. Use defines from PwrConfig_e + uint8_t TotalPowerPadding[3]; + + // SECTION: APCC Settings + uint32_t ApccPlusResidencyLimit; + + //SECTION: SMNCLK DPM + uint16_t SmnclkDpmFreq [NUM_SMNCLK_DPM_LEVELS]; // in MHz + uint16_t SmnclkDpmVoltage [NUM_SMNCLK_DPM_LEVELS]; // mV(Q2) + + uint32_t PaddingAPCC[4]; + + // SECTION: Throttler settings + uint32_t ThrottlerControlMask; // See Throtter masks defines + + // SECTION: FW DSTATE Settings + uint32_t FwDStateMask; // See FW DState masks defines + + // SECTION: ULV Settings + uint16_t UlvVoltageOffsetSoc; // In mV(Q2) + uint16_t UlvVoltageOffsetGfx; // In mV(Q2) + + uint16_t MinVoltageUlvGfx; // In mV(Q2) Minimum Voltage ("Vmin") of VDD_GFX in ULV mode + uint16_t MinVoltageUlvSoc; // In mV(Q2) Minimum Voltage ("Vmin") of VDD_SOC in ULV mode + + uint16_t SocLIVmin; // In mV(Q2) Long Idle Vmin (deep ULV), for VDD_SOC + uint16_t PaddingLIVmin; + + uint8_t GceaLinkMgrIdleThreshold; //Set by SMU FW during enablment of GFXOFF. Controls delay for GFX SDP port disconnection during idle events + uint8_t paddingRlcUlvParams[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: 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: 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 FreqTableDcefclk [NUM_DCEFCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableDispclk [NUM_DISPCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTablePixclk [NUM_PIXCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTablePhyclk [NUM_PHYCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableDtbclk [NUM_DTBCLK_DPM_LEVELS ]; // In MHz + uint16_t FreqTableFclk [NUM_FCLK_DPM_LEVELS ]; // In MHz + uint32_t Paddingclks[16]; + + uint32_t DcModeMaxFreq [PPCLK_COUNT ]; // In MHz + + uint8_t FreqTableUclkDiv [NUM_UCLK_DPM_LEVELS ]; // 0:Div-1, 1:Div-1/2, 2:Div-1/4, 3:Div-1/8 + + // Used for MALL performance boost + uint16_t FclkBoostFreq; // In Mhz + uint16_t FclkParamPadding; + + // SECTION: DPM Config 2 + uint16_t Mp0clkFreq [NUM_MP0CLK_DPM_LEVELS]; // in MHz + uint16_t Mp0DpmVoltage [NUM_MP0CLK_DPM_LEVELS]; // mV(Q2) + uint16_t MemVddciVoltage [NUM_UCLK_DPM_LEVELS]; // mV(Q2) + uint16_t MemMvddVoltage [NUM_UCLK_DPM_LEVELS]; // mV(Q2) + // GFXCLK DPM + uint16_t GfxclkFgfxoffEntry; // in Mhz + uint16_t GfxclkFinit; // in Mhz + uint16_t GfxclkFidle; // in MHz + uint8_t GfxclkSource; // 0 = PLL, 1 = DFLL + uint8_t GfxclkPadding; + + // GFX GPO + uint8_t GfxGpoSubFeatureMask; // bit 0 = PACE, bit 1 = DEM + uint8_t GfxGpoEnabledWorkPolicyMask; //Any policy that GPO can be enabled + uint8_t GfxGpoDisabledWorkPolicyMask; //Any policy that GPO can be disabled + uint8_t GfxGpoPadding[1]; + uint32_t GfxGpoVotingAllow; //For indicating which feature changes should result in a GPO table recalculation + + uint32_t GfxGpoPadding32[4]; + + uint16_t GfxDcsFopt; // Optimal GFXCLK for DCS in Mhz + uint16_t GfxDcsFclkFopt; // Optimal FCLK for DCS in Mhz + uint16_t GfxDcsUclkFopt; // Optimal UCLK for DCS in Mhz + + uint16_t DcsGfxOffVoltage; //Voltage in mV(Q2) applied to VDDGFX when entering DCS GFXOFF phase + + uint16_t DcsMinGfxOffTime; //Minimum amount of time PMFW shuts GFX OFF as part of GFX DCS phase + uint16_t DcsMaxGfxOffTime; //Maximum amount of time PMFW can shut GFX OFF as part of GFX DCS phase at a stretch. + + uint32_t DcsMinCreditAccum; //Min amount of positive credit accumulation before waking GFX up as part of DCS. + + uint16_t DcsExitHysteresis; //The min amount of time power credit accumulator should have a value > 0 before SMU exits the DCS throttling phase. + uint16_t DcsTimeout; //This is the amount of time SMU FW waits for RLC to put GFX into GFXOFF before reverting to the fallback mechanism of throttling GFXCLK to Fmin. + + uint32_t DcsParamPadding[5]; + + uint16_t FlopsPerByteTable[RLC_PACE_TABLE_NUM_LEVELS]; // Q8.8 + + // UCLK section + uint8_t LowestUclkReservedForUlv; // Set this to 1 if UCLK DPM0 is reserved for ULV-mode only + uint8_t PaddingMem[3]; + + uint8_t UclkDpmPstates [NUM_UCLK_DPM_LEVELS]; // 4 DPM states, 0-P0, 1-P1, 2-P2, 3-P3. + + // Used for 2-Step UCLK change workaround + UclkDpmChangeRange_t UclkDpmSrcFreqRange; // In Mhz + UclkDpmChangeRange_t UclkDpmTargFreqRange; // In Mhz + uint16_t UclkDpmMidstepFreq; // In Mhz + uint16_t UclkMidstepPadding; + + // Link DPM Settings + uint8_t PcieGenSpeed[NUM_LINK_LEVELS]; ///< 0:PciE-gen1 1:PciE-gen2 2:PciE-gen3 3:PciE-gen4 + uint8_t PcieLaneCount[NUM_LINK_LEVELS]; ///< 1=x1, 2=x2, 3=x4, 4=x8, 5=x12, 6=x16 + uint16_t LclkFreq[NUM_LINK_LEVELS]; + + // SECTION: Fan Control + uint16_t FanStopTemp; //Celcius + uint16_t FanStartTemp; //Celcius + + uint16_t FanGain[TEMP_COUNT]; + + uint16_t FanPwmMin; + uint16_t FanAcousticLimitRpm; + uint16_t FanThrottlingRpm; + uint16_t FanMaximumRpm; + uint16_t MGpuFanBoostLimitRpm; + uint16_t FanTargetTemperature; + uint16_t FanTargetGfxclk; + uint16_t FanPadding16; + uint8_t FanTempInputSelect; + uint8_t FanPadding; + uint8_t FanZeroRpmEnable; + uint8_t FanTachEdgePerRev; + + // 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 dBtcGbGfxDfllModelSelect; //0 -> fused piece-wise model, 1 -> piece-wise linear(PPTable), 2 -> quadratic model(PPTable) + uint8_t Padding8_Avfs; + + QuadraticInt_t qAvfsGb[AVFS_VOLTAGE_COUNT]; // GHz->V Override of fused curve + DroopInt_t dBtcGbGfxPll; // GHz->V BtcGb + DroopInt_t dBtcGbGfxDfll; // GHz->V BtcGb + DroopInt_t dBtcGbSoc; // GHz->V BtcGb + LinearInt_t qAgingGb[AVFS_VOLTAGE_COUNT]; // GHz->V + + PiecewiseLinearDroopInt_t PiecewiseLinearDroopIntGfxDfll; //GHz ->Vstore in IEEE float format + + 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]; + + // SECTION: Advanced Options + uint32_t DebugOverrides; + QuadraticInt_t ReservedEquation0; + QuadraticInt_t ReservedEquation1; + QuadraticInt_t ReservedEquation2; + QuadraticInt_t ReservedEquation3; + + // SECTION: Sku Reserved + uint8_t CustomerVariant; + uint8_t Spare[3]; + uint32_t SkuReserved[14]; + + + // MAJOR SECTION: BOARD PARAMETERS + + //SECTION: Gaming Clocks + uint32_t GamingClk[6]; + + // SECTION: I2C Control + I2cControllerConfig_t I2cControllers[NUM_I2C_CONTROLLERS]; + + uint8_t GpioScl; // GPIO Number for SCL Line, used only for CKSVII2C1 + uint8_t GpioSda; // GPIO Number for SDA Line, used only for CKSVII2C1 + uint8_t FchUsbPdSlaveAddr; //For requesting USB PD controller S-states via FCH I2C when entering PME turn off + uint8_t I2cSpare[1]; + + // SECTION: SVI2 Board Parameters + uint8_t VddGfxVrMapping; // Use VR_MAPPING* bitfields + uint8_t VddSocVrMapping; // Use VR_MAPPING* bitfields + uint8_t VddMem0VrMapping; // Use VR_MAPPING* bitfields + uint8_t VddMem1VrMapping; // Use VR_MAPPING* bitfields + + uint8_t GfxUlvPhaseSheddingMask; // set this to 1 to set PSI0/1 to 1 in ULV mode + uint8_t SocUlvPhaseSheddingMask; // set this to 1 to set PSI0/1 to 1 in ULV mode + uint8_t VddciUlvPhaseSheddingMask; // set this to 1 to set PSI0/1 to 1 in ULV mode + uint8_t MvddUlvPhaseSheddingMask; // set this to 1 to set PSI0/1 to 1 in ULV mode + + // SECTION: 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 Mem0MaxCurrent; // in Amps + int8_t Mem0Offset; // in Amps + uint8_t Padding_TelemetryMem0; + + uint16_t Mem1MaxCurrent; // in Amps + int8_t Mem1Offset; // in Amps + uint8_t Padding_TelemetryMem1; + + uint32_t MvddRatio; // This is used for MVDD Svi2 Div Ratio workaround. It has 16 fractional bits (Q16.16) + + // SECTION: GPIO Settings + uint8_t AcDcGpio; // GPIO pin configured for AC/DC switching + uint8_t AcDcPolarity; // GPIO polarity for AC/DC switching + 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 + uint8_t GthrGpio; // GPIO pin configured for GTHR Event + uint8_t GthrPolarity; // replace GPIO polarity for GTHR + + // LED Display Settings + uint8_t LedPin0; // GPIO number for LedPin[0] + uint8_t LedPin1; // GPIO number for LedPin[1] + uint8_t LedPin2; // GPIO number for LedPin[2] + uint8_t LedEnableMask; + + uint8_t LedPcie; // GPIO number for PCIE results + uint8_t LedError; // GPIO number for Error Cases + uint8_t LedSpare1[2]; + + // SECTION: Clock Spread Spectrum + + // GFXCLK PLL Spread Spectrum + uint8_t PllGfxclkSpreadEnabled; // on or off + uint8_t PllGfxclkSpreadPercent; // Q4.4 + uint16_t PllGfxclkSpreadFreq; // kHz + + // GFXCLK DFLL Spread Spectrum + uint8_t DfllGfxclkSpreadEnabled; // on or off + uint8_t DfllGfxclkSpreadPercent; // Q4.4 + uint16_t DfllGfxclkSpreadFreq; // kHz + + // UCLK Spread Spectrum + uint16_t UclkSpreadPadding; + uint16_t UclkSpreadFreq; // kHz + + // FCLK Spread Spectrum + uint8_t FclkSpreadEnabled; // on or off + uint8_t FclkSpreadPercent; // Q4.4 + uint16_t FclkSpreadFreq; // kHz + + // Section: Memory Config + 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 PaddingMem1[3]; + + // Section: Total Board Power + uint16_t TotalBoardPower; //Only needed for TCP Estimated case, where TCP = TGP+Total Board Power + uint16_t BoardPowerPadding; + + // 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]; + + // SECTION: UMC feature flags + uint8_t HsrEnabled; + uint8_t VddqOffEnabled; + uint8_t PaddingUmcFlags[2]; + + // UCLK Spread Spectrum + uint8_t UclkSpreadPercent[16]; + + // SECTION: Board Reserved + uint32_t BoardReserved[11]; + + // SECTION: Structure Padding + + // 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 FclkAverageLpfTau; + uint16_t UclkAverageLpfTau; + uint16_t GfxActivityLpfTau; + uint16_t UclkActivityLpfTau; + uint16_t SocketPowerLpfTau; + uint16_t VcnClkAverageLpfTau; + uint16_t padding16; +} DriverSmuConfig_t; + +typedef struct { + DriverSmuConfig_t DriverSmuConfig; + + uint32_t Spare[7]; + // Padding - ignore + uint32_t MmHubPadding[8]; // SMU internal use +} DriverSmuConfigExternal_t; + +typedef struct { + uint16_t GfxclkFmin; // MHz + uint16_t GfxclkFmax; // MHz + QuadraticInt_t CustomGfxVfCurve; // a: mV/MHz^2, b: mv/MHz, c: mV + uint16_t CustomCurveFmin; // MHz + uint16_t UclkFmin; // MHz + uint16_t UclkFmax; // MHz + int16_t OverDrivePct; // % + uint16_t FanMaximumRpm; + uint16_t FanMinimumPwm; + uint16_t FanAcousticLimitRpm; + uint16_t FanTargetTemperature; // Degree Celcius + uint8_t FanLinearPwmPoints[NUM_OD_FAN_MAX_POINTS]; + uint8_t FanLinearTempPoints[NUM_OD_FAN_MAX_POINTS]; + uint16_t MaxOpTemp; // Degree Celcius + uint16_t Padding_16[1]; + uint8_t FanZeroRpmEnable; + uint8_t FanZeroRpmStopTemp; + uint8_t FanMode; + uint8_t Padding[1]; +} OverDriveTable_t; + +typedef struct { + OverDriveTable_t OverDriveTable; + uint32_t Spare[8]; + + uint32_t MmHubPadding[8]; // SMU internal use +} OverDriveTableExternal_t; + +typedef struct { + uint32_t CurrClock[PPCLK_COUNT]; + + uint16_t AverageGfxclkFrequencyPreDs; + uint16_t AverageGfxclkFrequencyPostDs; + uint16_t AverageFclkFrequencyPreDs; + uint16_t AverageFclkFrequencyPostDs; + uint16_t AverageUclkFrequencyPreDs ; + uint16_t AverageUclkFrequencyPostDs ; + + + 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 TemperatureMem ; + uint16_t TemperatureVrGfx ; + uint16_t TemperatureVrMem0 ; + uint16_t TemperatureVrMem1 ; + uint16_t TemperatureVrSoc ; + uint16_t TemperatureLiquid0 ; + uint16_t TemperatureLiquid1 ; + uint16_t TemperaturePlx ; + uint16_t Padding16 ; + uint32_t ThrottlerStatus ; + + uint8_t LinkDpmLevel; + uint8_t CurrFanPwm; + uint16_t CurrFanSpeed; + + //BACO metrics, PMFW-1721 + //metrics for D3hot entry/exit and driver ARM msgs + uint8_t D3HotEntryCountPerMode[D3HOT_SEQUENCE_COUNT]; + uint8_t D3HotExitCountPerMode[D3HOT_SEQUENCE_COUNT]; + uint8_t ArmMsgReceivedCountPerMode[D3HOT_SEQUENCE_COUNT]; + + //PMFW-4362 + uint32_t EnergyAccumulator; + uint16_t AverageVclk0Frequency ; + uint16_t AverageDclk0Frequency ; + uint16_t AverageVclk1Frequency ; + uint16_t AverageDclk1Frequency ; + uint16_t VcnActivityPercentage ; //place holder, David N. to provide full sequence + uint8_t PcieRate ; + uint8_t PcieWidth ; + +} SmuMetrics_t; + +typedef struct { + SmuMetrics_t SmuMetrics; + uint32_t Spare[1]; + + // Padding - ignore + uint32_t MmHubPadding[8]; // SMU internal use +} SmuMetricsExternal_t; + +typedef struct { + uint16_t MinClock; // This is either DCEFCLK or SOCCLK (in MHz) + uint16_t MaxClock; // This is either DCEFCLK or SOCCLK (in MHz) + uint16_t MinUclk; + uint16_t MaxUclk; + + uint8_t WmSetting; + uint8_t Flags; + uint8_t Padding[2]; + +} WatermarkRowGeneric_t; + +#define NUM_WM_RANGES 4 + +typedef enum { + WM_SOCCLK = 0, + WM_DCEFCLK, + WM_COUNT, +} WM_CLOCK_e; + +typedef enum { + WATERMARKS_CLOCK_RANGE = 0, + WATERMARKS_DUMMY_PSTATE, + WATERMARKS_MALL, + WATERMARKS_COUNT, +} WATERMARKS_FLAGS_e; + +typedef struct { + // Watermarks + WatermarkRowGeneric_t WatermarkRow[WM_COUNT][NUM_WM_RANGES]; +} Watermarks_t; + +typedef struct { + Watermarks_t Watermarks; + + uint32_t MmHubPadding[8]; // SMU internal use +} WatermarksExternal_t; + +typedef struct { + uint16_t avgPsmCount[67]; + uint16_t minPsmCount[67]; + float avgPsmVoltage[67]; + float minPsmVoltage[67]; +} AvfsDebugTable_t; + +typedef struct { + AvfsDebugTable_t AvfsDebugTable; + + uint32_t MmHubPadding[8]; // SMU internal use +} AvfsDebugTableExternal_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]; //Sienna_Cichlid - 67 AVFS modules +} AvfsFuseOverride_t; + +typedef struct { + AvfsFuseOverride_t AvfsFuseOverride; + + uint32_t MmHubPadding[8]; // SMU internal use +} AvfsFuseOverrideExternal_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. + 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 Fclk_ActiveHystLimit; + uint8_t Fclk_IdleHystLimit; + uint8_t Fclk_FPS; + uint8_t Fclk_MinActiveFreqType; + uint8_t Fclk_BoosterFreqType; + uint8_t Fclk_MinFreqStep; // Minimum delta between current and target frequeny in order for FW to change clock. + uint16_t Fclk_MinActiveFreq; // MHz + uint16_t Fclk_BoosterFreq; // MHz + uint16_t Fclk_PD_Data_time_constant; // Time constant of PD controller in ms + uint32_t Fclk_PD_Data_limit_a; // Q16 + uint32_t Fclk_PD_Data_limit_b; // Q16 + uint32_t Fclk_PD_Data_limit_c; // Q16 + uint32_t Fclk_PD_Data_error_coeff; // Q16 + uint32_t Fclk_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. + 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; + +} DpmActivityMonitorCoeffInt_t; + + +typedef struct { + DpmActivityMonitorCoeffInt_t DpmActivityMonitorCoeffInt; + uint32_t MmHubPadding[8]; // SMU internal use +} DpmActivityMonitorCoeffIntExternal_t; + +// Workload bits +#define WORKLOAD_PPLIB_DEFAULT_BIT 0 +#define WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT 1 +#define WORKLOAD_PPLIB_POWER_SAVING_BIT 2 +#define WORKLOAD_PPLIB_VIDEO_BIT 3 +#define WORKLOAD_PPLIB_VR_BIT 4 +#define WORKLOAD_PPLIB_COMPUTE_BIT 5 +#define WORKLOAD_PPLIB_CUSTOM_BIT 6 +#define WORKLOAD_PPLIB_COUNT 7 + + +// These defines are used with the following messages: +// SMC_MSG_TransferTableDram2Smu +// SMC_MSG_TransferTableSmu2Dram + +// Table transfer status +#define TABLE_TRANSFER_OK 0x0 +#define TABLE_TRANSFER_FAILED 0xFF + +// Table types +#define TABLE_PPTABLE 0 +#define TABLE_WATERMARKS 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_ACTIVITY_MONITOR_COEFF 7 +#define TABLE_OVERDRIVE 8 +#define TABLE_I2C_COMMANDS 9 +#define TABLE_PACE 10 +#define TABLE_COUNT 11 + +typedef struct { + float FlopsPerByteTable[RLC_PACE_TABLE_NUM_LEVELS]; +} RlcPaceFlopsPerByteOverride_t; + +typedef struct { + RlcPaceFlopsPerByteOverride_t RlcPaceFlopsPerByteOverride; + + uint32_t MmHubPadding[8]; // SMU internal use +} RlcPaceFlopsPerByteOverrideExternal_t; + +// These defines are used with the SMC_MSG_SetUclkFastSwitch message. +#define UCLK_SWITCH_SLOW 0 +#define UCLK_SWITCH_FAST 1 +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_types.h b/drivers/gpu/drm/amd/powerplay/inc/smu_types.h index ee7dac4693d4..7b585e205a5a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_types.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_types.h @@ -173,6 +173,7 @@ __SMU_DUMMY_MAP(GmiPwrDnControl), \ __SMU_DUMMY_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE), \ __SMU_DUMMY_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE), \ + __SMU_DUMMY_MAP(Mode1Reset), \ #undef __SMU_DUMMY_MAP #define __SMU_DUMMY_MAP(type) SMU_MSG_##type @@ -185,6 +186,8 @@ enum smu_clk_type { SMU_GFXCLK, SMU_VCLK, SMU_DCLK, + SMU_VCLK1, + SMU_DCLK1, SMU_ECLK, SMU_SOCCLK, SMU_UCLK, @@ -245,6 +248,7 @@ enum smu_clk_type { __SMU_DUMMY_MAP(FW_DSTATE), \ __SMU_DUMMY_MAP(BACO), \ __SMU_DUMMY_MAP(VCN_PG), \ + __SMU_DUMMY_MAP(MM_DPM_PG), \ __SMU_DUMMY_MAP(JPEG_PG), \ __SMU_DUMMY_MAP(USB_PG), \ __SMU_DUMMY_MAP(RSMU_SMN_CG), \ @@ -257,6 +261,7 @@ enum smu_clk_type { __SMU_DUMMY_MAP(MMHUB_PG), \ __SMU_DUMMY_MAP(ATHUB_PG), \ __SMU_DUMMY_MAP(APCC_DFLL), \ + __SMU_DUMMY_MAP(DPM_GFX_GPO), \ __SMU_DUMMY_MAP(WAFL_CG), #undef __SMU_DUMMY_MAP 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 6b3b451a8018..6a42331aba8a 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0.h @@ -26,11 +26,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 0x14 +#define SMU11_DRIVER_IF_VERSION_ARCT 0x17 #define SMU11_DRIVER_IF_VERSION_NV10 0x36 #define SMU11_DRIVER_IF_VERSION_NV12 0x33 #define SMU11_DRIVER_IF_VERSION_NV14 0x36 +#define SMU11_DRIVER_IF_VERSION_Sienna_Cichlid 0x34 +#define SMU11_DRIVER_IF_VERSION_Navy_Flounder 0x3 /* MP Apertures */ #define MP0_Public 0x03800000 @@ -48,22 +49,12 @@ #define SMU11_TOOL_SIZE 0x19000 +#define MAX_DPM_LEVELS 16 #define MAX_PCIE_CONF 2 -#define CLK_MAP(clk, index) \ - [SMU_##clk] = {1, (index)} - -#define FEA_MAP(fea) \ - [SMU_FEATURE_##fea##_BIT] = {1, FEATURE_##fea##_BIT} - -#define TAB_MAP(tab) \ - [SMU_TABLE_##tab] = {1, TABLE_##tab} - -#define PWR_MAP(tab) \ - [SMU_POWER_SOURCE_##tab] = {1, POWER_SOURCE_##tab} - -#define WORKLOAD_MAP(profile, workload) \ - [profile] = {1, (workload)} +#define CTF_OFFSET_EDGE 5 +#define CTF_OFFSET_HOTSPOT 5 +#define CTF_OFFSET_MEM 5 static const struct smu_temperature_range smu11_thermal_policy[] = { @@ -71,11 +62,6 @@ static const struct smu_temperature_range smu11_thermal_policy[] = { 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; uint32_t phy_clock; @@ -85,9 +71,17 @@ struct smu_11_0_max_sustainable_clocks { uint32_t soc_clock; }; +struct smu_11_0_dpm_clk_level { + bool enabled; + uint32_t value; +}; + struct smu_11_0_dpm_table { - uint32_t min; /* MHz */ - uint32_t max; /* MHz */ + uint32_t min; /* MHz */ + uint32_t max; /* MHz */ + uint32_t count; + bool is_fine_grained; + struct smu_11_0_dpm_clk_level dpm_levels[MAX_DPM_LEVELS]; }; struct smu_11_0_pcie_table { @@ -101,7 +95,9 @@ struct smu_11_0_dpm_tables { struct smu_11_0_dpm_table uclk_table; struct smu_11_0_dpm_table eclk_table; struct smu_11_0_dpm_table vclk_table; + struct smu_11_0_dpm_table vclk1_table; struct smu_11_0_dpm_table dclk_table; + struct smu_11_0_dpm_table dclk1_table; struct smu_11_0_dpm_table dcef_table; struct smu_11_0_dpm_table pixel_table; struct smu_11_0_dpm_table display_table; @@ -138,8 +134,12 @@ enum smu_v11_0_baco_seq { BACO_SEQ_COUNT, }; +#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) + int smu_v11_0_init_microcode(struct smu_context *smu); +void smu_v11_0_fini_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); @@ -156,20 +156,8 @@ 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); @@ -179,38 +167,26 @@ 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, - uint32_t *read_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_power_limit(struct smu_context *smu, + uint32_t *power_limit); -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_set_power_limit(struct smu_context *smu, uint32_t n); 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_enable_thermal_alert(struct smu_context *smu); -int smu_v11_0_stop_thermal_control(struct smu_context *smu); +int smu_v11_0_disable_thermal_alert(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_get_gfx_vdd(struct smu_context *smu, uint32_t *value); -int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk); +int smu_v11_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk); int smu_v11_0_display_clock_voltage_request(struct smu_context *smu, @@ -251,17 +227,18 @@ 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_mode1_reset(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_hard_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max); int smu_v11_0_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level); @@ -269,4 +246,23 @@ int smu_v11_0_set_performance_level(struct smu_context *smu, int smu_v11_0_set_power_source(struct smu_context *smu, enum smu_power_src_type power_src); +int smu_v11_0_get_dpm_freq_by_index(struct smu_context *smu, + enum smu_clk_type clk_type, + uint16_t level, + uint32_t *value); + +int smu_v11_0_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value); + +int smu_v11_0_set_single_dpm_table(struct smu_context *smu, + enum smu_clk_type clk_type, + struct smu_11_0_dpm_table *single_dpm_table); + +int smu_v11_0_get_dpm_level_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min_value, + uint32_t *max_value); + +#endif #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_ppsmc.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_ppsmc.h new file mode 100644 index 000000000000..35dd6072cc45 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_ppsmc.h @@ -0,0 +1,139 @@ +/* + * Copyright 2020 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_V11_0_7_PPSMC_H +#define SMU_V11_0_7_PPSMC_H + +#define PPSMC_VERSION 0x1 + +// 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_GetRunningSmuFeaturesLow 0xC +#define PPSMC_MSG_GetRunningSmuFeaturesHigh 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 + +//BACO/BAMACO/BOMACO +#define PPSMC_MSG_EnterBaco 0x15 +#define PPSMC_MSG_ExitBaco 0x16 +#define PPSMC_MSG_ArmD3 0x17 +#define PPSMC_MSG_BacoAudioD3PME 0x18 + +//DPM +#define PPSMC_MSG_SetSoftMinByFreq 0x19 +#define PPSMC_MSG_SetSoftMaxByFreq 0x1A +#define PPSMC_MSG_SetHardMinByFreq 0x1B +#define PPSMC_MSG_SetHardMaxByFreq 0x1C +#define PPSMC_MSG_GetMinDpmFreq 0x1D +#define PPSMC_MSG_GetMaxDpmFreq 0x1E +#define PPSMC_MSG_GetDpmFreqByIndex 0x1F +#define PPSMC_MSG_OverridePcieParameters 0x20 + +//DramLog Set DramAddrHigh +#define PPSMC_MSG_DramLogSetDramAddrHigh 0x21 + +#define PPSMC_MSG_SetWorkloadMask 0x22 +#define PPSMC_MSG_SetUclkFastSwitch 0x23 +#define PPSMC_MSG_GetVoltageByDpm 0x24 +#define PPSMC_MSG_SetVideoFps 0x25 +#define PPSMC_MSG_GetDcModeMaxDpmFreq 0x26 + +//DramLog Set DramAddrLow +#define PPSMC_MSG_DramLogSetDramAddrLow 0x27 + +//Power Gating +#define PPSMC_MSG_AllowGfxOff 0x28 +#define PPSMC_MSG_DisallowGfxOff 0x29 +#define PPSMC_MSG_PowerUpVcn 0x2A +#define PPSMC_MSG_PowerDownVcn 0x2B +#define PPSMC_MSG_PowerUpJpeg 0x2C +#define PPSMC_MSG_PowerDownJpeg 0x2D + +//Resets +#define PPSMC_MSG_PrepareMp1ForUnload 0x2E + +//DramLog Set DramLog SetDramSize +#define PPSMC_MSG_DramLogSetDramSize 0x2F + +#define PPSMC_MSG_Mode1Reset 0x30 + +//Set SystemVirtual DramAddrHigh +#define PPSMC_MSG_SetSystemVirtualDramAddrHigh 0x31 + +//ACDC Power Source +#define PPSMC_MSG_SetPptLimit 0x32 +#define PPSMC_MSG_GetPptLimit 0x33 +#define PPSMC_MSG_ReenableAcDcInterrupt 0x34 +#define PPSMC_MSG_NotifyPowerSource 0x35 + +//BTC +#define PPSMC_MSG_RunDcBtc 0x36 + +//Set SystemVirtual DramAddrLow +#define PPSMC_MSG_SetSystemVirtualDramAddrLow 0x38 + +//Others +#define PPSMC_MSG_SetMemoryChannelEnable 0x39 +#define PPSMC_MSG_SetDramBitWidth 0x3A +#define PPSMC_MSG_SetGeminiMode 0x3B +#define PPSMC_MSG_SetGeminiApertureHigh 0x3C +#define PPSMC_MSG_SetGeminiApertureLow 0x3D + +#define PPSMC_MSG_SetTemperatureInputSelect 0x3E +#define PPSMC_MSG_SetFwDstatesMask 0x3F +#define PPSMC_MSG_SetThrottlerMask 0x40 + +#define PPSMC_MSG_SetExternalClientDfCstateAllow 0x41 +#define PPSMC_MSG_EnableOutOfBandMonTesting 0x42 +#define PPSMC_MSG_SetMGpuFanBoostLimitRpm 0x43 + +#define PPSMC_MSG_SetNumBadHbmPagesRetired 0x44 +#define PPSMC_MSG_SetGpoFeaturePMask 0x45 +#define PPSMC_MSG_SetSMBUSInterrupt 0x46 + +#define PPSMC_Message_Count 0x47 + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_pptable.h b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_pptable.h new file mode 100644 index 000000000000..247c6e9632ba --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v11_0_7_pptable.h @@ -0,0 +1,196 @@ +/* + * Copyright 2020 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_11_0_7_PPTABLE_H +#define SMU_11_0_7_PPTABLE_H + + +#define SMU_11_0_7_TABLE_FORMAT_REVISION 15 + +//// POWERPLAYTABLE::ulPlatformCaps +#define SMU_11_0_7_PP_PLATFORM_CAP_POWERPLAY 0x1 // This cap indicates whether CCC need to show Powerplay page. +#define SMU_11_0_7_PP_PLATFORM_CAP_SBIOSPOWERSOURCE 0x2 // This cap indicates whether power source notificaiton is done by SBIOS instead of OS. +#define SMU_11_0_7_PP_PLATFORM_CAP_HARDWAREDC 0x4 // This cap indicates whether DC mode notificaiton is done by GPIO pin directly. +#define SMU_11_0_7_PP_PLATFORM_CAP_BACO 0x8 // This cap indicates whether board supports the BACO circuitry. +#define SMU_11_0_7_PP_PLATFORM_CAP_MACO 0x10 // This cap indicates whether board supports the MACO circuitry. +#define SMU_11_0_7_PP_PLATFORM_CAP_SHADOWPSTATE 0x20 // This cap indicates whether board supports the Shadow Pstate. + +// SMU_11_0_7_PP_THERMALCONTROLLER - Thermal Controller Type +#define SMU_11_0_7_PP_THERMALCONTROLLER_NONE 0 +#define SMU_11_0_7_PP_THERMALCONTROLLER_SIENNA_CICHLID 28 + +#define SMU_11_0_7_PP_OVERDRIVE_VERSION 0x81 // OverDrive 8 Table Version 0.2 +#define SMU_11_0_7_PP_POWERSAVINGCLOCK_VERSION 0x01 // Power Saving Clock Table Version 1.00 + +enum SMU_11_0_7_ODFEATURE_CAP { + SMU_11_0_7_ODCAP_GFXCLK_LIMITS = 0, + SMU_11_0_7_ODCAP_GFXCLK_CURVE, + SMU_11_0_7_ODCAP_UCLK_LIMITS, + SMU_11_0_7_ODCAP_POWER_LIMIT, + SMU_11_0_7_ODCAP_FAN_ACOUSTIC_LIMIT, + SMU_11_0_7_ODCAP_FAN_SPEED_MIN, + SMU_11_0_7_ODCAP_TEMPERATURE_FAN, + SMU_11_0_7_ODCAP_TEMPERATURE_SYSTEM, + SMU_11_0_7_ODCAP_MEMORY_TIMING_TUNE, + SMU_11_0_7_ODCAP_FAN_ZERO_RPM_CONTROL, + SMU_11_0_7_ODCAP_AUTO_UV_ENGINE, + SMU_11_0_7_ODCAP_AUTO_OC_ENGINE, + SMU_11_0_7_ODCAP_AUTO_OC_MEMORY, + SMU_11_0_7_ODCAP_FAN_CURVE, + SMU_11_0_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT, + SMU_11_0_7_ODCAP_POWER_MODE, + SMU_11_0_7_ODCAP_COUNT, +}; + +enum SMU_11_0_7_ODFEATURE_ID { + SMU_11_0_7_ODFEATURE_GFXCLK_LIMITS = 1 << SMU_11_0_7_ODCAP_GFXCLK_LIMITS, //GFXCLK Limit feature + SMU_11_0_7_ODFEATURE_GFXCLK_CURVE = 1 << SMU_11_0_7_ODCAP_GFXCLK_CURVE, //GFXCLK Curve feature + SMU_11_0_7_ODFEATURE_UCLK_LIMITS = 1 << SMU_11_0_7_ODCAP_UCLK_LIMITS, //UCLK Limit feature + SMU_11_0_7_ODFEATURE_POWER_LIMIT = 1 << SMU_11_0_7_ODCAP_POWER_LIMIT, //Power Limit feature + SMU_11_0_7_ODFEATURE_FAN_ACOUSTIC_LIMIT = 1 << SMU_11_0_7_ODCAP_FAN_ACOUSTIC_LIMIT, //Fan Acoustic RPM feature + SMU_11_0_7_ODFEATURE_FAN_SPEED_MIN = 1 << SMU_11_0_7_ODCAP_FAN_SPEED_MIN, //Minimum Fan Speed feature + SMU_11_0_7_ODFEATURE_TEMPERATURE_FAN = 1 << SMU_11_0_7_ODCAP_TEMPERATURE_FAN, //Fan Target Temperature Limit feature + SMU_11_0_7_ODFEATURE_TEMPERATURE_SYSTEM = 1 << SMU_11_0_7_ODCAP_TEMPERATURE_SYSTEM, //Operating Temperature Limit feature + SMU_11_0_7_ODFEATURE_MEMORY_TIMING_TUNE = 1 << SMU_11_0_7_ODCAP_MEMORY_TIMING_TUNE, //AC Timing Tuning feature + SMU_11_0_7_ODFEATURE_FAN_ZERO_RPM_CONTROL = 1 << SMU_11_0_7_ODCAP_FAN_ZERO_RPM_CONTROL, //Zero RPM feature + SMU_11_0_7_ODFEATURE_AUTO_UV_ENGINE = 1 << SMU_11_0_7_ODCAP_AUTO_UV_ENGINE, //Auto Under Volt GFXCLK feature + SMU_11_0_7_ODFEATURE_AUTO_OC_ENGINE = 1 << SMU_11_0_7_ODCAP_AUTO_OC_ENGINE, //Auto Over Clock GFXCLK feature + SMU_11_0_7_ODFEATURE_AUTO_OC_MEMORY = 1 << SMU_11_0_7_ODCAP_AUTO_OC_MEMORY, //Auto Over Clock MCLK feature + SMU_11_0_7_ODFEATURE_FAN_CURVE = 1 << SMU_11_0_7_ODCAP_FAN_CURVE, //Fan Curve feature + SMU_11_0_ODFEATURE_AUTO_FAN_ACOUSTIC_LIMIT = 1 << SMU_11_0_ODCAP_AUTO_FAN_ACOUSTIC_LIMIT, //Auto Fan Acoustic RPM feature + SMU_11_0_7_ODFEATURE_POWER_MODE = 1 << SMU_11_0_7_ODCAP_POWER_MODE, //Optimized GPU Power Mode feature + SMU_11_0_7_ODFEATURE_COUNT = 16, +}; + +#define SMU_11_0_7_MAX_ODFEATURE 32 //Maximum Number of OD Features + +enum SMU_11_0_7_ODSETTING_ID { + SMU_11_0_7_ODSETTING_GFXCLKFMAX = 0, + SMU_11_0_7_ODSETTING_GFXCLKFMIN, + SMU_11_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_A, + SMU_11_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_B, + SMU_11_0_7_ODSETTING_CUSTOM_GFX_VF_CURVE_C, + SMU_11_0_7_ODSETTING_CUSTOM_CURVE_VFT_FMIN, + SMU_11_0_7_ODSETTING_UCLKFMIN, + SMU_11_0_7_ODSETTING_UCLKFMAX, + SMU_11_0_7_ODSETTING_POWERPERCENTAGE, + SMU_11_0_7_ODSETTING_FANRPMMIN, + SMU_11_0_7_ODSETTING_FANRPMACOUSTICLIMIT, + SMU_11_0_7_ODSETTING_FANTARGETTEMPERATURE, + SMU_11_0_7_ODSETTING_OPERATINGTEMPMAX, + SMU_11_0_7_ODSETTING_ACTIMING, + SMU_11_0_7_ODSETTING_FAN_ZERO_RPM_CONTROL, + SMU_11_0_7_ODSETTING_AUTOUVENGINE, + SMU_11_0_7_ODSETTING_AUTOOCENGINE, + SMU_11_0_7_ODSETTING_AUTOOCMEMORY, + SMU_11_0_7_ODSETTING_FAN_CURVE_TEMPERATURE_1, + SMU_11_0_7_ODSETTING_FAN_CURVE_SPEED_1, + SMU_11_0_7_ODSETTING_FAN_CURVE_TEMPERATURE_2, + SMU_11_0_7_ODSETTING_FAN_CURVE_SPEED_2, + SMU_11_0_7_ODSETTING_FAN_CURVE_TEMPERATURE_3, + SMU_11_0_7_ODSETTING_FAN_CURVE_SPEED_3, + SMU_11_0_7_ODSETTING_FAN_CURVE_TEMPERATURE_4, + SMU_11_0_7_ODSETTING_FAN_CURVE_SPEED_4, + SMU_11_0_7_ODSETTING_FAN_CURVE_TEMPERATURE_5, + SMU_11_0_7_ODSETTING_FAN_CURVE_SPEED_5, + SMU_11_0_7_ODSETTING_AUTO_FAN_ACOUSTIC_LIMIT, + SMU_11_0_7_ODSETTING_POWER_MODE, + SMU_11_0_7_ODSETTING_COUNT, +}; +#define SMU_11_0_7_MAX_ODSETTING 64 //Maximum Number of ODSettings + +enum SMU_11_0_7_PWRMODE_SETTING { + SMU_11_0_7_PMSETTING_POWER_LIMIT_QUIET = 0, + SMU_11_0_7_PMSETTING_POWER_LIMIT_BALANCE, + SMU_11_0_7_PMSETTING_POWER_LIMIT_TURBO, + SMU_11_0_7_PMSETTING_POWER_LIMIT_RAGE, + SMU_11_0_7_PMSETTING_ACOUSTIC_TEMP_QUIET, + SMU_11_0_7_PMSETTING_ACOUSTIC_TEMP_BALANCE, + SMU_11_0_7_PMSETTING_ACOUSTIC_TEMP_TURBO, + SMU_11_0_7_PMSETTING_ACOUSTIC_TEMP_RAGE, +}; +#define SMU_11_0_7_MAX_PMSETTING 32 //Maximum Number of PowerMode Settings + +struct smu_11_0_7_overdrive_table +{ + uint8_t revision; //Revision = SMU_11_0_7_PP_OVERDRIVE_VERSION + uint8_t reserve[3]; //Zero filled field reserved for future use + uint32_t feature_count; //Total number of supported features + uint32_t setting_count; //Total number of supported settings + uint8_t cap[SMU_11_0_7_MAX_ODFEATURE]; //OD feature support flags + uint32_t max[SMU_11_0_7_MAX_ODSETTING]; //default maximum settings + uint32_t min[SMU_11_0_7_MAX_ODSETTING]; //default minimum settings + int16_t pm_setting[SMU_11_0_7_MAX_PMSETTING]; //Optimized power mode feature settings +} __attribute__((packed)); + +enum SMU_11_0_7_PPCLOCK_ID { + SMU_11_0_7_PPCLOCK_GFXCLK = 0, + SMU_11_0_7_PPCLOCK_SOCCLK, + SMU_11_0_7_PPCLOCK_UCLK, + SMU_11_0_7_PPCLOCK_FCLK, + SMU_11_0_7_PPCLOCK_DCLK_0, + SMU_11_0_7_PPCLOCK_VCLK_0, + SMU_11_0_7_PPCLOCK_DCLK_1, + SMU_11_0_7_PPCLOCK_VCLK_1, + SMU_11_0_7_PPCLOCK_DCEFCLK, + SMU_11_0_7_PPCLOCK_DISPCLK, + SMU_11_0_7_PPCLOCK_PIXCLK, + SMU_11_0_7_PPCLOCK_PHYCLK, + SMU_11_0_7_PPCLOCK_DTBCLK, + SMU_11_0_7_PPCLOCK_COUNT, +}; +#define SMU_11_0_7_MAX_PPCLOCK 16 //Maximum Number of PP Clocks + +struct smu_11_0_7_power_saving_clock_table +{ + uint8_t revision; //Revision = SMU_11_0_7_PP_POWERSAVINGCLOCK_VERSION + uint8_t reserve[3]; //Zero filled field reserved for future use + uint32_t count; //power_saving_clock_count = SMU_11_0_7_PPCLOCK_COUNT + uint32_t max[SMU_11_0_7_MAX_PPCLOCK]; //PowerSavingClock Mode Clock Maximum array In MHz + uint32_t min[SMU_11_0_7_MAX_PPCLOCK]; //PowerSavingClock Mode Clock Minimum array In MHz +} __attribute__((packed)); + +struct smu_11_0_7_powerplay_table +{ + struct atom_common_table_header header; //For sienna_cichlid, header.format_revision = 15, header.content_revision = 0 + uint8_t table_revision; //For sienna_cichlid, table_revision = 2 + uint16_t table_size; //Driver portion table size. The offset to smc_pptable including header size + uint32_t golden_pp_id; //PPGen use only: PP Table ID on the Golden Data Base + uint32_t golden_revision; //PPGen use only: PP Table Revision on the Golden Data Base + uint16_t format_id; //PPGen use only: PPTable for different ASICs. For sienna_cichlid this should be 0x80 + uint32_t platform_caps; //POWERPLAYABLE::ulPlatformCaps + + uint8_t thermal_controller_type; //one of SMU_11_0_7_PP_THERMALCONTROLLER + + uint16_t small_power_limit1; + uint16_t small_power_limit2; + uint16_t boost_power_limit; //For Gemini Board, when the slave adapter is in BACO mode, the master adapter will use this boost power limit instead of the default power limit to boost the power limit. + uint16_t software_shutdown_temp; + + uint16_t reserve[8]; //Zero filled field reserved for future use + + struct smu_11_0_7_power_saving_clock_table power_saving_clock; + struct smu_11_0_7_overdrive_table overdrive_table; + + PPTable_t smc_pptable; //PPTable_t in smu11_driver_if.h +} __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 index 7fbebc1979cf..02de3b6199e5 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h +++ b/drivers/gpu/drm/amd/powerplay/inc/smu_v12_0.h @@ -31,22 +31,7 @@ #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_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, - uint32_t *read_arg); +#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) int smu_v12_0_check_fw_status(struct smu_context *smu); @@ -60,29 +45,13 @@ 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_set_default_dpm_tables(struct smu_context *smu); int smu_v12_0_mode2_reset(struct smu_context *smu); @@ -92,3 +61,4 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_ int smu_v12_0_set_driver_table_location(struct smu_context *smu); #endif +#endif diff --git a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c index 0c9be864d072..9f62af9abd23 100644 --- a/drivers/gpu/drm/amd/powerplay/navi10_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/navi10_ppt.c @@ -21,13 +21,16 @@ * */ +#define SWSMU_CODE_LAYER_L2 + #include <linux/firmware.h> #include <linux/pci.h> +#include <linux/i2c.h> #include "amdgpu.h" #include "amdgpu_smu.h" -#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" #include "soc15_common.h" #include "smu_v11_0.h" #include "smu11_driver_if_navi10.h" @@ -37,8 +40,23 @@ #include "smu_v11_0_ppsmc.h" #include "nbio/nbio_2_3_offset.h" #include "nbio/nbio_2_3_sh_mask.h" +#include "thm/thm_11_0_2_offset.h" +#include "thm/thm_11_0_2_sh_mask.h" #include "asic_reg/mp/mp_11_0_sh_mask.h" +#include "smu_cmn.h" + +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) #define FEATURE_MASK(feature) (1ULL << feature) #define SMC_DPM_FEATURE ( \ @@ -51,81 +69,78 @@ FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) -#define MSG_MAP(msg, index) \ - [SMU_MSG_##msg] = {1, (index)} - -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), - 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(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask), - MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit), - 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(RunBtc, PPSMC_MSG_RunBtc), - MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco), - 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(SetMemoryChannelConfig, PPSMC_MSG_SetMemoryChannelConfig), - MSG_MAP(SetGeminiMode, PPSMC_MSG_SetGeminiMode), - MSG_MAP(SetGeminiApertureHigh, PPSMC_MSG_SetGeminiApertureHigh), - MSG_MAP(SetGeminiApertureLow, PPSMC_MSG_SetGeminiApertureLow), - MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters), - MSG_MAP(SetMinDeepSleepDcefclk, PPSMC_MSG_SetMinDeepSleepDcefclk), - MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt), - MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource), - MSG_MAP(SetUclkFastSwitch, PPSMC_MSG_SetUclkFastSwitch), - MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps), - MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload), - MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh), - MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow), - MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize), - MSG_MAP(ConfigureGfxDidt, PPSMC_MSG_ConfigureGfxDidt), - MSG_MAP(NumOfDisplays, PPSMC_MSG_NumOfDisplays), - MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh), - MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow), - MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff), - MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff), - MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit), - MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq), - MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData), - MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco), - MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset), - MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown), - MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn), - MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn), - MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg), - 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 struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow, 0), + MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh, 0), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), + MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow, 1), + MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh, 1), + MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow, 1), + MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 1), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetEnabledSmuFeaturesLow, 1), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetEnabledSmuFeaturesHigh, 1), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 0), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 0), + MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), + MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 0), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), + MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), + MSG_MAP(UseBackupPPTable, PPSMC_MSG_UseBackupPPTable, 0), + MSG_MAP(RunBtc, PPSMC_MSG_RunBtc, 0), + MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1), + MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), + MSG_MAP(SetMemoryChannelConfig, PPSMC_MSG_SetMemoryChannelConfig, 0), + MSG_MAP(SetGeminiMode, PPSMC_MSG_SetGeminiMode, 0), + MSG_MAP(SetGeminiApertureHigh, PPSMC_MSG_SetGeminiApertureHigh, 0), + MSG_MAP(SetGeminiApertureLow, PPSMC_MSG_SetGeminiApertureLow, 0), + MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters, 0), + MSG_MAP(SetMinDeepSleepDcefclk, PPSMC_MSG_SetMinDeepSleepDcefclk, 0), + MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0), + MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), + MSG_MAP(SetUclkFastSwitch, PPSMC_MSG_SetUclkFastSwitch, 0), + MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps, 0), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), + MSG_MAP(DramLogSetDramAddrHigh, PPSMC_MSG_DramLogSetDramAddrHigh, 0), + MSG_MAP(DramLogSetDramAddrLow, PPSMC_MSG_DramLogSetDramAddrLow, 0), + MSG_MAP(DramLogSetDramSize, PPSMC_MSG_DramLogSetDramSize, 0), + MSG_MAP(ConfigureGfxDidt, PPSMC_MSG_ConfigureGfxDidt, 0), + MSG_MAP(NumOfDisplays, PPSMC_MSG_NumOfDisplays, 0), + MSG_MAP(SetSystemVirtualDramAddrHigh, PPSMC_MSG_SetSystemVirtualDramAddrHigh, 0), + MSG_MAP(SetSystemVirtualDramAddrLow, PPSMC_MSG_SetSystemVirtualDramAddrLow, 0), + MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 0), + MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), + MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 1), + MSG_MAP(GetDebugData, PPSMC_MSG_GetDebugData, 0), + MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0), + MSG_MAP(PrepareMp1ForReset, PPSMC_MSG_PrepareMp1ForReset, 0), + MSG_MAP(PrepareMp1ForShutdown, PPSMC_MSG_PrepareMp1ForShutdown, 0), + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 0), + MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 0), + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 0), + MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0), + MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME, 0), + MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), + MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange, 0), + MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange, 0), + MSG_MAP(GetVoltageByDpm, PPSMC_MSG_GetVoltageByDpm, 0), + MSG_MAP(GetVoltageByDpmOverdrive, PPSMC_MSG_GetVoltageByDpmOverdrive, 0), }; -static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = { +static struct cmn2asic_mapping navi10_clk_map[SMU_CLK_COUNT] = { CLK_MAP(GFXCLK, PPCLK_GFXCLK), CLK_MAP(SCLK, PPCLK_GFXCLK), CLK_MAP(SOCCLK, PPCLK_SOCCLK), @@ -140,7 +155,7 @@ static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = { CLK_MAP(PHYCLK, PPCLK_PHYCLK), }; -static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = { +static struct cmn2asic_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = { FEA_MAP(DPM_PREFETCHER), FEA_MAP(DPM_GFXCLK), FEA_MAP(DPM_GFX_PACE), @@ -186,7 +201,7 @@ static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUN FEA_MAP(APCC_DFLL), }; -static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = { +static struct cmn2asic_mapping navi10_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PPTABLE), TAB_MAP(WATERMARKS), TAB_MAP(AVFS), @@ -201,12 +216,12 @@ static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = { TAB_MAP(PACE), }; -static struct smu_11_0_cmn2aisc_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { +static struct cmn2asic_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { PWR_MAP(AC), PWR_MAP(DC), }; -static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { +static struct cmn2asic_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), @@ -216,97 +231,6 @@ static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE 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) -{ - struct smu_11_0_cmn2aisc_mapping mapping; - - if (index >= SMU_MSG_MAX_COUNT) - return -EINVAL; - - mapping = navi10_message_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int navi10_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 = navi10_clk_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int navi10_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 = navi10_feature_mask_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int navi10_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 = navi10_table_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int navi10_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 = navi10_pwr_src_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - - -static int navi10_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 = navi10_workload_map[profile]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - static bool is_asic_secure(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -414,6 +338,29 @@ navi10_get_allowed_feature_mask(struct smu_context *smu, static int navi10_check_powerplay_table(struct smu_context *smu) { + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_powerplay_table *powerplay_table = + table_context->power_play_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; + + if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC) + smu->dc_controlled_by_gpio = true; + + 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); + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; + + /* + * Instead of having its own buffer space and get overdrive_table copied, + * smu->od_settings just points to the actual overdrive_table + */ + smu->od_settings = &powerplay_table->overdrive_table; + return 0; } @@ -429,17 +376,17 @@ static int navi10_append_powerplay_table(struct smu_context *smu) 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, + ret = amdgpu_atombios_get_data_table(adev, 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", + dev_info(adev->dev, "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) { - pr_err("smc_dpm_info table format revision is not 4!\n"); + dev_err(adev->dev, "smc_dpm_info table format revision is not 4!\n"); return -EINVAL; } @@ -449,7 +396,7 @@ static int navi10_append_powerplay_table(struct smu_context *smu) sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header)); break; case 7: /* nv12 */ - ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL, + ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL, (uint8_t **)&smc_dpm_table_v4_7); if (ret) return ret; @@ -457,7 +404,7 @@ static int navi10_append_powerplay_table(struct smu_context *smu) sizeof(*smc_dpm_table_v4_7) - sizeof(smc_dpm_table_v4_7->table_header)); break; default: - pr_err("smc_dpm_info with unsupported content revision %d!\n", + dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n", smc_dpm_table->table_header.content_revision); return -EINVAL; } @@ -472,35 +419,43 @@ static int navi10_append_powerplay_table(struct smu_context *smu) static int navi10_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; - - if (!table_context->power_play_table) - return -EINVAL; - - powerplay_table = table_context->power_play_table; + struct smu_11_0_powerplay_table *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; + return 0; +} - if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC) - smu->dc_controlled_by_gpio = true; +static int navi10_setup_pptable(struct smu_context *smu) +{ + int ret = 0; - 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); + ret = smu_v11_0_setup_pptable(smu); + if (ret) + return ret; - return 0; + ret = navi10_store_powerplay_table(smu); + if (ret) + return ret; + + ret = navi10_append_powerplay_table(smu); + if (ret) + return ret; + + ret = navi10_check_powerplay_table(smu); + if (ret) + return ret; + + return ret; } -static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables) +static int navi10_tables_init(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -508,6 +463,8 @@ static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables) 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_OVERDRIVE, sizeof(OverDriveTable_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); SMU_TABLE_INIT(tables, SMU_TABLE_PMSTATUSLOG, SMU11_TOOL_SIZE, @@ -528,25 +485,98 @@ static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables) return 0; } -static int navi10_get_metrics_table(struct smu_context *smu, - SmuMetrics_t *metrics_table) +static int navi10_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) { struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_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 (!smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { + ret = smu_cmn_update_table(smu, + SMU_TABLE_SMU_METRICS, + 0, + smu_table->metrics_table, + false); if (ret) { - pr_info("Failed to export SMU metrics table!\n"); + dev_info(smu->adev->dev, "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)); + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK]; + break; + case METRICS_CURR_DCEFCLK: + *value = metrics->CurrClock[PPCLK_DCEFCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + *value = metrics->AverageGfxclkFrequency; + break; + case METRICS_AVERAGE_SOCCLK: + *value = metrics->AverageSocclkFrequency; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequency; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + mutex_unlock(&smu->metrics_lock); return ret; @@ -556,9 +586,6 @@ static int navi10_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 smu_11_0_dpm_context), GFP_KERNEL); if (!smu_dpm->dpm_context) @@ -569,72 +596,210 @@ static int navi10_allocate_dpm_context(struct smu_context *smu) return 0; } -static int navi10_set_default_dpm_table(struct smu_context *smu) +static int navi10_init_smc_tables(struct smu_context *smu) { - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - 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; + int ret = 0; - driver_ppt = table_context->driver_pptable; + ret = navi10_tables_init(smu); + if (ret) + return ret; + + ret = navi10_allocate_dpm_context(smu); + if (ret) + return ret; - dpm_context->dpm_tables.soc_table.min = driver_ppt->FreqTableSocclk[0]; - dpm_context->dpm_tables.soc_table.max = driver_ppt->FreqTableSocclk[NUM_SOCCLK_DPM_LEVELS - 1]; + return smu_v11_0_init_smc_tables(smu); +} - dpm_context->dpm_tables.gfx_table.min = driver_ppt->FreqTableGfx[0]; - dpm_context->dpm_tables.gfx_table.max = driver_ppt->FreqTableGfx[NUM_GFXCLK_DPM_LEVELS - 1]; +static int navi10_set_default_dpm_table(struct smu_context *smu) +{ + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + PPTable_t *driver_ppt = smu->smu_table.driver_pptable; + struct smu_11_0_dpm_table *dpm_table; + int ret = 0; - dpm_context->dpm_tables.uclk_table.min = driver_ppt->FreqTableUclk[0]; - dpm_context->dpm_tables.uclk_table.max = driver_ppt->FreqTableUclk[NUM_UCLK_DPM_LEVELS - 1]; + /* socclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.soc_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_SOCCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - dpm_context->dpm_tables.vclk_table.min = driver_ppt->FreqTableVclk[0]; - dpm_context->dpm_tables.vclk_table.max = driver_ppt->FreqTableVclk[NUM_VCLK_DPM_LEVELS - 1]; + /* gfxclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_GFXCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - dpm_context->dpm_tables.dclk_table.min = driver_ppt->FreqTableDclk[0]; - dpm_context->dpm_tables.dclk_table.max = driver_ppt->FreqTableDclk[NUM_DCLK_DPM_LEVELS - 1]; + /* uclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_UCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - dpm_context->dpm_tables.dcef_table.min = driver_ppt->FreqTableDcefclk[0]; - dpm_context->dpm_tables.dcef_table.max = driver_ppt->FreqTableDcefclk[NUM_DCEFCLK_DPM_LEVELS - 1]; + /* vclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_VCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - dpm_context->dpm_tables.pixel_table.min = driver_ppt->FreqTablePixclk[0]; - dpm_context->dpm_tables.pixel_table.max = driver_ppt->FreqTablePixclk[NUM_PIXCLK_DPM_LEVELS - 1]; + /* dclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - dpm_context->dpm_tables.display_table.min = driver_ppt->FreqTableDispclk[0]; - dpm_context->dpm_tables.display_table.max = driver_ppt->FreqTableDispclk[NUM_DISPCLK_DPM_LEVELS - 1]; + /* dcefclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.dcef_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DCEFCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - 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]; + /* pixelclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.pixel_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_PIXCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } - 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]; + /* displayclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.display_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DISPCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* phyclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.phy_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_PHYCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; } return 0; } -static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable) +static int navi10_dpm_set_vcn_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, 1, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1, NULL); 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL); if (ret) return ret; } - power_gate->vcn_gated = true; } return ret; @@ -642,24 +807,20 @@ static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable) 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpJpeg, NULL); 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownJpeg, NULL); if (ret) return ret; } - power_gate->jpeg_gated = true; } return ret; @@ -669,20 +830,41 @@ static int navi10_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 = navi10_get_metrics_table(smu, &metrics); - if (ret) - return ret; + MetricsMember_t member_type; + int clk_id = 0; - clk_id = smu_clk_get_index(smu, clk_type); + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); if (clk_id < 0) return clk_id; - *value = metrics.CurrClock[clk_id]; + switch (clk_id) { + case PPCLK_GFXCLK: + member_type = METRICS_CURR_GFXCLK; + break; + case PPCLK_UCLK: + member_type = METRICS_CURR_UCLK; + break; + case PPCLK_SOCCLK: + member_type = METRICS_CURR_SOCCLK; + break; + case PPCLK_VCLK: + member_type = METRICS_CURR_VCLK; + break; + case PPCLK_DCLK: + member_type = METRICS_CURR_DCLK; + break; + case PPCLK_DCEFCLK: + member_type = METRICS_CURR_DCEFCLK; + break; + default: + return -EINVAL; + } - return ret; + return navi10_get_smu_metrics_data(smu, + member_type, + value); } static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) @@ -691,7 +873,9 @@ static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu DpmDescriptor_t *dpm_desc = NULL; uint32_t clk_index = 0; - clk_index = smu_clk_get_index(smu, clk_type); + clk_index = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); dpm_desc = &pptable->DpmDescriptor[clk_index]; /* 0 - Fine grained DPM, 1 - Discrete DPM */ @@ -740,20 +924,17 @@ static int navi10_print_clk_levels(struct smu_context *smu, case SMU_UCLK: case SMU_FCLK: case SMU_DCEFCLK: - ret = smu_get_current_clk_freq(smu, clk_type, &cur_value); + ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value); if (ret) return size; - /* 10KHz -> MHz */ - cur_value = cur_value / 100; - - ret = smu_get_dpm_level_count(smu, clk_type, &count); + ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); if (ret) return size; if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) { for (i = 0; i < count; i++) { - ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &value); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); if (ret) return size; @@ -761,10 +942,10 @@ static int navi10_print_clk_levels(struct smu_context *smu, cur_value == value ? "*" : ""); } } else { - ret = smu_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); if (ret) return size; - ret = smu_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); if (ret) return size; @@ -841,7 +1022,7 @@ static int navi10_print_clk_levels(struct smu_context *smu, default: break; } - size += sprintf(buf + size, "%d: %uMHz @ %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE); + size += sprintf(buf + size, "%d: %uMHz %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE); } break; case SMU_OD_RANGE: @@ -924,15 +1105,15 @@ static int navi10_force_clk_levels(struct smu_context *smu, soft_min_level = (soft_min_level >= 1 ? 1 : 0); } - ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); if (ret) return size; - ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); if (ret) return size; - ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false); + ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); if (ret) return size; break; @@ -945,22 +1126,93 @@ static int navi10_force_clk_levels(struct smu_context *smu, 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, 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, false); - if (ret) - return ret; + struct smu_11_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_11_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_11_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_11_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + struct amdgpu_device *adev = smu->adev; + uint32_t sclk_freq; - smu->pstate_mclk = min_mclk_freq * 100; + pstate_table->gfxclk_pstate.min = gfx_table->min; + 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 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; + case CHIP_NAVI12: + sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK; + break; + default: + sclk_freq = gfx_table->dpm_levels[gfx_table->count - 1].value; + break; + } + pstate_table->gfxclk_pstate.peak = sclk_freq; + + pstate_table->uclk_pstate.min = mem_table->min; + pstate_table->uclk_pstate.peak = mem_table->max; + + pstate_table->socclk_pstate.min = soc_table->min; + pstate_table->socclk_pstate.peak = soc_table->max; + + if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK && + mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK && + soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) { + pstate_table->gfxclk_pstate.standard = + NAVI10_UMD_PSTATE_PROFILING_GFXCLK; + pstate_table->uclk_pstate.standard = + NAVI10_UMD_PSTATE_PROFILING_MEMCLK; + pstate_table->socclk_pstate.standard = + NAVI10_UMD_PSTATE_PROFILING_SOCCLK; + } else { + pstate_table->gfxclk_pstate.standard = + pstate_table->gfxclk_pstate.min; + pstate_table->uclk_pstate.standard = + pstate_table->uclk_pstate.min; + pstate_table->socclk_pstate.standard = + pstate_table->socclk_pstate.min; + } - return ret; + return 0; } static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, @@ -976,7 +1228,7 @@ static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, case SMU_SOCCLK: case SMU_MCLK: case SMU_UCLK: - ret = smu_get_dpm_level_count(smu, clk_type, &level_count); + ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &level_count); if (ret) return ret; @@ -984,7 +1236,7 @@ static int navi10_get_clock_by_type_with_latency(struct smu_context *smu, clocks->num_levels = level_count; for (i = 0; i < level_count; i++) { - ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &freq); + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &freq); if (ret) return ret; @@ -1004,15 +1256,15 @@ static int navi10_pre_display_config_changed(struct smu_context *smu) int ret = 0; uint32_t max_freq = 0; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL); if (ret) 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, false); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &max_freq); if (ret) return ret; - ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, max_freq); + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, max_freq); if (ret) return ret; } @@ -1025,9 +1277,9 @@ static int navi10_display_config_changed(struct smu_context *smu) int ret = 0; if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && - smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && - smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, + smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && + smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, smu->display_config->num_display, NULL); if (ret) @@ -1037,74 +1289,14 @@ static int navi10_display_config_changed(struct smu_context *smu) return ret; } -static int navi10_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, false); - if (ret) - return ret; - } - - return ret; -} - -static int navi10_unforce_dpm_levels(struct smu_context *smu) -{ - int ret = 0, i = 0; - uint32_t min_freq, max_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; - - ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false); - if (ret) - return ret; - } - - return ret; -} - static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value) { - int ret = 0; - SmuMetrics_t metrics; - if (!value) return -EINVAL; - ret = navi10_get_metrics_table(smu, &metrics); - if (ret) - return ret; - - *value = metrics.AverageSocketPower << 8; - - return 0; + return navi10_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, + value); } static int navi10_get_current_activity_percent(struct smu_context *smu, @@ -1112,28 +1304,27 @@ static int navi10_get_current_activity_percent(struct smu_context *smu, uint32_t *value) { int ret = 0; - SmuMetrics_t metrics; if (!value) return -EINVAL; - ret = navi10_get_metrics_table(smu, &metrics); - if (ret) - return ret; - switch (sensor) { case AMDGPU_PP_SENSOR_GPU_LOAD: - *value = metrics.AverageGfxActivity; + ret = navi10_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, + value); break; case AMDGPU_PP_SENSOR_MEM_LOAD: - *value = metrics.AverageUclkActivity; + ret = navi10_get_smu_metrics_data(smu, + METRICS_AVERAGE_MEMACTIVITY, + value); break; default: - pr_err("Invalid sensor for retrieving clock activity\n"); + dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n"); return -EINVAL; } - return 0; + return ret; } static bool navi10_is_dpm_running(struct smu_context *smu) @@ -1141,7 +1332,7 @@ static bool navi10_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); + ret = smu_cmn_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); @@ -1150,19 +1341,12 @@ static bool navi10_is_dpm_running(struct smu_context *smu) static int navi10_get_fan_speed_rpm(struct smu_context *smu, uint32_t *speed) { - SmuMetrics_t metrics; - int ret = 0; - if (!speed) return -EINVAL; - ret = navi10_get_metrics_table(smu, &metrics); - if (ret) - return ret; - - *speed = metrics.CurrFanSpeed; - - return ret; + return navi10_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); } static int navi10_get_fan_speed_percent(struct smu_context *smu, @@ -1219,15 +1403,17 @@ 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); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + i); if (workload_type < 0) return -EINVAL; - result = smu_update_table(smu, + result = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); return result; } @@ -1288,17 +1474,17 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u smu->power_profile_mode = input[size]; if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - pr_err("Invalid power profile mode %d\n", smu->power_profile_mode); + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); return -EINVAL; } if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - ret = smu_update_table(smu, + ret = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); return ret; } @@ -1338,66 +1524,27 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u break; } - ret = smu_update_table(smu, + ret = smu_cmn_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__); + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); return ret; } } /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_workload_get_type(smu, smu->power_profile_mode); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + smu->power_profile_mode); if (workload_type < 0) return -EINVAL; - smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, + smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, 1 << workload_type, NULL); return ret; } -static int navi10_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) -{ - int ret = 0; - uint32_t level_count = 0; - - 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) { - ret = smu_get_dpm_level_count(smu, SMU_SCLK, &level_count); - if (ret) - return ret; - *sclk_mask = level_count - 1; - } - - if(mclk_mask) { - ret = smu_get_dpm_level_count(smu, SMU_MCLK, &level_count); - if (ret) - return ret; - *mclk_mask = level_count - 1; - } - - if(soc_mask) { - ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, &level_count); - if (ret) - return ret; - *soc_mask = level_count - 1; - } - } - - return ret; -} - static int navi10_notify_smc_display_config(struct smu_context *smu) { struct smu_clocks min_clocks = {0}; @@ -1408,31 +1555,31 @@ static int navi10_notify_smc_display_config(struct smu_context *smu) min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk; min_clocks.memory_clock = smu->display_config->min_mem_set_clock; - if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + if (smu_cmn_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; 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, + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetMinDeepSleepDcefclk, min_clocks.dcef_clock_in_sr/100, NULL); if (ret) { - pr_err("Attempt to set divider for DCEFCLK Failed!"); + dev_err(smu->adev->dev, "Attempt to set divider for DCEFCLK Failed!"); return ret; } } } else { - pr_info("Attempt to set Hard Min for DCEFCLK Failed!"); + dev_info(smu->adev->dev, "Attempt to set Hard Min for DCEFCLK Failed!"); } } - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { - ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0); if (ret) { - pr_err("[%s] Set hard min uclk failed!", __func__); + dev_err(smu->adev->dev, "[%s] Set hard min uclk failed!", __func__); return ret; } } @@ -1441,70 +1588,68 @@ static int navi10_notify_smc_display_config(struct smu_context *smu) } static int navi10_set_watermarks_table(struct smu_context *smu, - void *watermarks, struct - dm_pp_wm_sets_with_clock_ranges_soc15 - *clock_ranges) + struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges) { - int i; + Watermarks_t *table = smu->smu_table.watermarks_table; int ret = 0; - Watermarks_t *table = watermarks; + int i; - if (!table || !clock_ranges) - return -EINVAL; + if (clock_ranges) { + if (clock_ranges->num_wm_dmif_sets > 4 || + clock_ranges->num_wm_mcif_sets > 4) + return -EINVAL; - if (clock_ranges->num_wm_dmif_sets > 4 || - clock_ranges->num_wm_mcif_sets > 4) - return -EINVAL; + for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { + table->WatermarkRow[1][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MinUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MaxUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].WmSetting = (uint8_t) + clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id; + } - for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { - table->WatermarkRow[1][i].MinClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MaxClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MinUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MaxUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / - 1000)); - table->WatermarkRow[1][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[0][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MinUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MaxUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].WmSetting = (uint8_t) + clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; + } - for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) { - table->WatermarkRow[0][i].MinClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MaxClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MinUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MaxUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].WmSetting = (uint8_t) - clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; + smu->watermarks_bitmap |= WATERMARKS_EXIST; } - smu->watermarks_bitmap |= WATERMARKS_EXIST; - /* pass data to smu controller */ - if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) { - ret = smu_write_watermarks_table(smu); + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_cmn_write_watermarks_table(smu); if (ret) { - pr_err("Failed to update WMTABLE!"); + dev_err(smu->adev->dev, "Failed to update WMTABLE!"); return ret; } smu->watermarks_bitmap |= WATERMARKS_LOADED; @@ -1517,35 +1662,33 @@ static int navi10_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 = navi10_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; + ret = navi10_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, + value); break; case AMDGPU_PP_SENSOR_EDGE_TEMP: - *value = metrics.TemperatureEdge * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + ret = navi10_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_EDGE, + value); break; case AMDGPU_PP_SENSOR_MEM_TEMP: - *value = metrics.TemperatureMem * - SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + ret = navi10_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_MEM, + value); break; default: - pr_err("Invalid sensor for retrieving temp\n"); + dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n"); return -EINVAL; } - return 0; + return ret; } static int navi10_read_sensor(struct smu_context *smu, @@ -1580,8 +1723,23 @@ static int navi10_read_sensor(struct smu_context *smu, ret = navi10_thermal_get_temperature(smu, sensor, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = navi10_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = navi10_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data); + *size = 4; + break; default: - ret = smu_v11_0_read_sensor(smu, sensor, data, size); + ret = -EOPNOTSUPP; + break; } mutex_unlock(&smu->sensor_lock); @@ -1617,160 +1775,32 @@ static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_ return 0; } -static int navi10_set_performance_level(struct smu_context *smu, - enum amd_dpm_forced_level level); - -static int navi10_set_standard_performance_level(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - int ret = 0; - uint32_t sclk_freq = 0, uclk_freq = 0; - - 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_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false); - if (ret) - return ret; - ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false); - if (ret) - return ret; - - return ret; -} - -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; - - 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 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; - 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_range(smu, SMU_UCLK, NULL, &uclk_freq); - if (ret) - return ret; - - ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false); - if (ret) - return ret; - ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false); - if (ret) - return ret; - - return ret; -} - -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_performance_level(smu); - break; - case AMD_DPM_FORCED_LEVEL_MANUAL: - case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: - default: - break; - } - return ret; -} - static int navi10_get_thermal_temperature_range(struct smu_context *smu, struct smu_temperature_range *range) { struct smu_table_context *table_context = &smu->smu_table; - struct smu_11_0_powerplay_table *powerplay_table = table_context->power_play_table; + struct smu_11_0_powerplay_table *powerplay_table = + table_context->power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; - if (!range || !powerplay_table) + if (!range) return -EINVAL; - range->max = powerplay_table->software_shutdown_temp * + memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range)); + + 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_MEM)* SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->software_shutdown_temp = powerplay_table->software_shutdown_temp; return 0; } @@ -1789,9 +1819,9 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu, return 0; if(disable_memory_clock_switch) - ret = smu_set_hard_freq_range(smu, SMU_UCLK, max_memory_clock, 0); + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0); else - ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_memory_clock, 0); + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0); if(!ret) smu->disable_uclk_switch = disable_memory_clock_switch; @@ -1799,51 +1829,35 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu, return ret; } -static uint32_t navi10_get_pptable_power_limit(struct smu_context *smu) +static int navi10_get_power_limit(struct smu_context *smu) { + struct smu_11_0_powerplay_table *powerplay_table = + (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table; + struct smu_11_0_overdrive_table *od_settings = smu->od_settings; PPTable_t *pptable = smu->smu_table.driver_pptable; - return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; -} + uint32_t power_limit, od_percent; -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_v11_0_get_current_power_limit(smu, &power_limit)) { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + power_limit = + pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; + } + smu->current_power_limit = power_limit; - if (!smu->power_limit) { - if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT) && - !amdgpu_sriov_vf(smu->adev)) { - power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC); - if (power_src < 0) - return -EINVAL; + if (smu->od_enabled && + navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) { + od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit, - power_src << 16, &asic_default_power_limit); - if (ret) { - pr_err("[%s] get PPT limit failed!", __func__); - return ret; - } - } 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]; - } + dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit); - smu->power_limit = asic_default_power_limit; + power_limit *= (100 + od_percent); + power_limit /= 100; } - - if (cap) - *limit = smu_v11_0_get_max_power_limit(smu); - else - *limit = smu->power_limit; + smu->max_power_limit = power_limit; return 0; } @@ -1852,19 +1866,23 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, uint32_t pcie_gen_cap, uint32_t pcie_width_cap) { + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; PPTable_t *pptable = smu->smu_table.driver_pptable; - int ret, i; uint32_t smu_pcie_arg; + int ret, i; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; + /* lclk dpm table setup */ + for (i = 0; i < MAX_PCIE_CONF; i++) { + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i]; + } 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, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_OverridePcieParameters, smu_pcie_arg, NULL); @@ -1881,23 +1899,28 @@ static int navi10_update_pcie_parameters(struct smu_context *smu, 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 inline void navi10_dump_od_table(struct smu_context *smu, + OverDriveTable_t *od_table) +{ + dev_dbg(smu->adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax); + dev_dbg(smu->adev->dev, "OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1); + dev_dbg(smu->adev->dev, "OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2); + dev_dbg(smu->adev->dev, "OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3); + dev_dbg(smu->adev->dev, "OD: UclkFmax: %d\n", od_table->UclkFmax); + dev_dbg(smu->adev->dev, "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) +static int navi10_od_setting_check_range(struct smu_context *smu, + 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]); + dev_warn(smu->adev->dev, "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]); + dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]); return -EINVAL; } return 0; @@ -1911,12 +1934,12 @@ static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu, uint32_t value = 0; int ret; - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetVoltageByDpm, param, &value); if (ret) { - pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!"); + dev_err(smu->adev->dev, "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!"); return ret; } @@ -1925,93 +1948,61 @@ static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu, 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 bool navi10_is_baco_supported(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; uint32_t val; - if (!smu_v11_0_baco_is_support(smu)) + if (amdgpu_sriov_vf(adev) || (!smu_v11_0_baco_is_support(smu))) return false; val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false; } -static int navi10_set_default_od_settings(struct smu_context *smu, bool initialize) { - OverDriveTable_t *od_table, *boot_od_table; +static int navi10_set_default_od_settings(struct smu_context *smu) +{ + OverDriveTable_t *od_table = + (OverDriveTable_t *)smu->smu_table.overdrive_table; + OverDriveTable_t *boot_od_table = + (OverDriveTable_t *)smu->smu_table.boot_overdrive_table; int ret = 0; - if (amdgpu_sriov_vf(smu->adev)) - return 0; - - ret = smu_v11_0_set_default_od_settings(smu, initialize, sizeof(OverDriveTable_t)); - if (ret) + ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, false); + if (ret) { + dev_err(smu->adev->dev, "Failed to get overdrive table!\n"); 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"); + if (!od_table->GfxclkVolt1) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt1, + od_table->GfxclkFreq1); + if (ret) 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->GfxclkVolt2) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt2, + od_table->GfxclkFreq2); + if (ret) + return ret; } - if (od_table) { - navi10_dump_od_table(od_table); + if (!od_table->GfxclkVolt3) { + ret = navi10_overdrive_get_gfx_clk_base_voltage(smu, + &od_table->GfxclkVolt3, + od_table->GfxclkFreq3); + if (ret) + return ret; } - return ret; + memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t)); + + navi10_dump_od_table(smu, od_table); + + return 0; } static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) { @@ -2025,12 +2016,12 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL od_table = (OverDriveTable_t *)table_context->overdrive_table; if (!smu->od_enabled) { - pr_warn("OverDrive is not enabled!\n"); + dev_warn(smu->adev->dev, "OverDrive is not enabled!\n"); return -EINVAL; } if (!smu->od_settings) { - pr_err("OD board limits are not set!\n"); + dev_err(smu->adev->dev, "OD board limits are not set!\n"); return -ENOENT; } @@ -2039,16 +2030,16 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL 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"); + dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n"); return -ENOTSUPP; } if (!table_context->overdrive_table) { - pr_err("Overdrive is not initialized\n"); + dev_err(smu->adev->dev, "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); + dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size); return -EINVAL; } switch (input[i]) { @@ -2056,7 +2047,7 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL 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", + dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n", input[i + 1], od_table->GfxclkFmin); return -EINVAL; @@ -2066,18 +2057,18 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL 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", + dev_info(smu->adev->dev, "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"); + dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]); + dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n"); return -EINVAL; } - ret = navi10_od_setting_check_range(od_settings, freq_setting, input[i + 1]); + ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[i + 1]); if (ret) return ret; *freq_ptr = input[i + 1]; @@ -2085,56 +2076,49 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL 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"); + dev_warn(smu->adev->dev, "UCLK_MAX not supported!\n"); return -ENOTSUPP; } if (size < 2) { - pr_info("invalid number of parameters: %d\n", size); + dev_info(smu->adev->dev, "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"); + dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]); + dev_info(smu->adev->dev, "Supported indices: [1:max]\n"); return -EINVAL; } - ret = navi10_od_setting_check_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]); + ret = navi10_od_setting_check_range(smu, 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"); + dev_err(smu->adev->dev, "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); + navi10_dump_od_table(smu, od_table); + ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true); if (ret) { + dev_err(smu->adev->dev, "Failed to import overdrive table!\n"); 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"); + dev_warn(smu->adev->dev, "GFXCLK_CURVE not supported!\n"); return -ENOTSUPP; } if (size < 3) { - pr_info("invalid number of parameters: %d\n", size); + dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size); return -EINVAL; } if (!od_table) { - pr_info("Overdrive is not initialized\n"); + dev_info(smu->adev->dev, "Overdrive is not initialized\n"); return -EINVAL; } @@ -2158,28 +2142,28 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL 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"); + dev_info(smu->adev->dev, "Invalid VDDC_CURVE index: %ld\n", input[0]); + dev_info(smu->adev->dev, "Supported indices: [0, 1, 2]\n"); return -EINVAL; } - ret = navi10_od_setting_check_range(od_settings, freq_setting, input[1]); + ret = navi10_od_setting_check_range(smu, 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]); + ret = navi10_od_setting_check_range(smu, 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); + dev_dbg(smu->adev->dev, "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); + navi10_dump_od_table(smu, od_table); break; default: return -ENOSYS; @@ -2191,9 +2175,9 @@ static int navi10_run_btc(struct smu_context *smu) { int ret = 0; - ret = smu_send_smc_msg(smu, SMU_MSG_RunBtc, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunBtc, NULL); if (ret) - pr_err("RunBtc failed!\n"); + dev_err(smu->adev->dev, "RunBtc failed!\n"); return ret; } @@ -2203,20 +2187,38 @@ 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, NULL); + result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_DISABLE_DUMMY_PSTATE_CHANGE, NULL); else - result = smu_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL); + result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL); return result; } +static inline bool navi10_need_umc_cdr_12gbps_workaround(struct amdgpu_device *adev) +{ + if (adev->asic_type != CHIP_NAVI10) + return false; + + if (adev->pdev->device == 0x731f && + (adev->pdev->revision == 0xc2 || + adev->pdev->revision == 0xc3 || + adev->pdev->revision == 0xca || + adev->pdev->revision == 0xcb)) + return true; + else + return false; +} + 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 (!navi10_need_umc_cdr_12gbps_workaround(smu->adev)) + return 0; + + ret = smu_cmn_get_smc_version(smu, NULL, &smu_version); if (ret) return ret; @@ -2224,25 +2226,25 @@ static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu) if (smu_version < 0x2A3200) return 0; - ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_count); + ret = smu_v11_0_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); + ret = smu_v11_0_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); + ret = smu_v11_0_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); + ret = smu_v11_0_set_hard_freq_limited_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); + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_max); if (ret) return ret; @@ -2253,23 +2255,231 @@ static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu) return navi10_dummy_pstate_control(smu, true); } +static void navi10_fill_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 navi10_i2c_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)); + navi10_fill_i2c_req(&req, false, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + /* Now read data starting with that address */ + ret = smu_cmn_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; + + dev_dbg(adev->dev, "navi10_i2c_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 + dev_err(adev->dev, "navi10_i2c_read_data - error occurred :%x", ret); + + return ret; +} + +static int navi10_i2c_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)); + navi10_fill_i2c_req(&req, true, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + dev_dbg(adev->dev, "navi10_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 + dev_err(adev->dev, "navi10_i2c_write- error occurred :%x", ret); + + return ret; +} + +static int navi10_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 = navi10_i2c_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 = navi10_i2c_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 = navi10_i2c_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 = navi10_i2c_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 navi10_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm navi10_i2c_algo = { + .master_xfer = navi10_i2c_xfer, + .functionality = navi10_i2c_func, +}; + +static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + int res; + + control->owner = THIS_MODULE; + control->class = I2C_CLASS_SPD; + control->dev.parent = &adev->pdev->dev; + control->algo = &navi10_i2c_algo; + snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + + res = i2c_add_adapter(control); + if (res) + DRM_ERROR("Failed to register hw i2c, err: %d\n", res); + + return res; +} + +static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control) +{ + i2c_del_adapter(control); +} + + static const struct pptable_funcs navi10_ppt_funcs = { - .tables_init = navi10_tables_init, - .alloc_dpm_context = navi10_allocate_dpm_context, - .store_powerplay_table = navi10_store_powerplay_table, - .check_powerplay_table = navi10_check_powerplay_table, - .append_powerplay_table = navi10_append_powerplay_table, - .get_smu_msg_index = navi10_get_smu_msg_index, - .get_smu_clk_index = navi10_get_smu_clk_index, - .get_smu_feature_index = navi10_get_smu_feature_index, - .get_smu_table_index = navi10_get_smu_table_index, - .get_smu_power_index = navi10_get_pwr_src_index, - .get_workload_type = navi10_get_workload_type, .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_vcn_enable = navi10_dpm_set_vcn_enable, .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable, - .get_current_clk_freq_by_table = navi10_get_current_clk_freq_by_table, + .i2c_init = navi10_i2c_control_init, + .i2c_fini = navi10_i2c_control_fini, .print_clk_levels = navi10_print_clk_levels, .force_clk_levels = navi10_force_clk_levels, .populate_umd_state_clk = navi10_populate_umd_state_clk, @@ -2277,53 +2487,48 @@ static const struct pptable_funcs navi10_ppt_funcs = { .pre_display_config_changed = navi10_pre_display_config_changed, .display_config_changed = navi10_display_config_changed, .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, .get_fan_speed_percent = navi10_get_fan_speed_percent, .get_fan_speed_rpm = navi10_get_fan_speed_rpm, .get_power_profile_mode = navi10_get_power_profile_mode, .set_power_profile_mode = navi10_set_power_profile_mode, - .get_profiling_clk_mask = navi10_get_profiling_clk_mask, .set_watermarks_table = navi10_set_watermarks_table, .read_sensor = navi10_read_sensor, .get_uclk_dpm_states = navi10_get_uclk_dpm_states, - .set_performance_level = navi10_set_performance_level, + .set_performance_level = smu_v11_0_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_microcode = smu_v11_0_fini_microcode, + .init_smc_tables = navi10_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, + .setup_pptable = navi10_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, + .write_pptable = smu_cmn_write_pptable, .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, + .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, + .send_smc_msg = smu_cmn_send_smc_msg, .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, + .get_enabled_mask = smu_cmn_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, .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, + .enable_thermal_alert = smu_v11_0_enable_thermal_alert, + .disable_thermal_alert = smu_v11_0_disable_thermal_alert, + .set_min_dcef_deep_sleep = smu_v11_0_set_min_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, @@ -2341,16 +2546,22 @@ static const struct pptable_funcs navi10_ppt_funcs = { .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, .set_power_source = smu_v11_0_set_power_source, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, }; void navi10_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &navi10_ppt_funcs; + smu->message_map = navi10_message_map; + smu->clock_map = navi10_clk_map; + smu->feature_map = navi10_feature_mask_map; + smu->table_map = navi10_table_map; + smu->pwr_src_map = navi10_pwr_src_map; + smu->workload_map = navi10_workload_map; } diff --git a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c index 67476047c067..dbb676c482fd 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.c @@ -21,92 +21,91 @@ * */ +#define SWSMU_CODE_LAYER_L2 + #include "amdgpu.h" #include "amdgpu_smu.h" -#include "smu_internal.h" #include "smu_v12_0_ppsmc.h" #include "smu12_driver_if.h" #include "smu_v12_0.h" #include "renoir_ppt.h" +#include "smu_cmn.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), +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +static struct cmn2asic_msg_mapping renoir_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(PowerUpGfx, PPSMC_MSG_PowerUpGfx, 1), + MSG_MAP(AllowGfxOff, PPSMC_MSG_EnableGfxOff, 1), + MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisableGfxOff, 1), + MSG_MAP(PowerDownIspByTile, PPSMC_MSG_PowerDownIspByTile, 1), + MSG_MAP(PowerUpIspByTile, PPSMC_MSG_PowerUpIspByTile, 1), + MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 1), + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 1), + MSG_MAP(PowerDownSdma, PPSMC_MSG_PowerDownSdma, 1), + MSG_MAP(PowerUpSdma, PPSMC_MSG_PowerUpSdma, 1), + MSG_MAP(SetHardMinIspclkByFreq, PPSMC_MSG_SetHardMinIspclkByFreq, 1), + MSG_MAP(SetHardMinVcn, PPSMC_MSG_SetHardMinVcn, 1), + MSG_MAP(Spare1, PPSMC_MSG_spare1, 1), + MSG_MAP(Spare2, PPSMC_MSG_spare2, 1), + MSG_MAP(SetAllowFclkSwitch, PPSMC_MSG_SetAllowFclkSwitch, 1), + MSG_MAP(SetMinVideoGfxclkFreq, PPSMC_MSG_SetMinVideoGfxclkFreq, 1), + MSG_MAP(ActiveProcessNotify, PPSMC_MSG_ActiveProcessNotify, 1), + MSG_MAP(SetCustomPolicy, PPSMC_MSG_SetCustomPolicy, 1), + MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps, 1), + MSG_MAP(NumOfDisplays, PPSMC_MSG_SetDisplayCount, 1), + MSG_MAP(QueryPowerLimit, PPSMC_MSG_QueryPowerLimit, 1), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 1), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 1), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 1), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 1), + MSG_MAP(GfxDeviceDriverReset, PPSMC_MSG_GfxDeviceDriverReset, 1), + MSG_MAP(SetGfxclkOverdriveByFreqVid, PPSMC_MSG_SetGfxclkOverdriveByFreqVid, 1), + MSG_MAP(SetHardMinDcfclkByFreq, PPSMC_MSG_SetHardMinDcfclkByFreq, 1), + MSG_MAP(SetHardMinSocclkByFreq, PPSMC_MSG_SetHardMinSocclkByFreq, 1), + MSG_MAP(ControlIgpuATS, PPSMC_MSG_ControlIgpuATS, 1), + MSG_MAP(SetMinVideoFclkFreq, PPSMC_MSG_SetMinVideoFclkFreq, 1), + MSG_MAP(SetMinDeepSleepDcfclk, PPSMC_MSG_SetMinDeepSleepDcfclk, 1), + MSG_MAP(ForcePowerDownGfx, PPSMC_MSG_ForcePowerDownGfx, 1), + MSG_MAP(SetPhyclkVoltageByFreq, PPSMC_MSG_SetPhyclkVoltageByFreq, 1), + MSG_MAP(SetDppclkVoltageByFreq, PPSMC_MSG_SetDppclkVoltageByFreq, 1), + MSG_MAP(SetSoftMinVcn, PPSMC_MSG_SetSoftMinVcn, 1), + MSG_MAP(EnablePostCode, PPSMC_MSG_EnablePostCode, 1), + MSG_MAP(GetGfxclkFrequency, PPSMC_MSG_GetGfxclkFrequency, 1), + MSG_MAP(GetFclkFrequency, PPSMC_MSG_GetFclkFrequency, 1), + MSG_MAP(GetMinGfxclkFrequency, PPSMC_MSG_GetMinGfxclkFrequency, 1), + MSG_MAP(GetMaxGfxclkFrequency, PPSMC_MSG_GetMaxGfxclkFrequency, 1), + MSG_MAP(SoftReset, PPSMC_MSG_SoftReset, 1), + MSG_MAP(SetGfxCGPG, PPSMC_MSG_SetGfxCGPG, 1), + MSG_MAP(SetSoftMaxGfxClk, PPSMC_MSG_SetSoftMaxGfxClk, 1), + MSG_MAP(SetHardMinGfxClk, PPSMC_MSG_SetHardMinGfxClk, 1), + MSG_MAP(SetSoftMaxSocclkByFreq, PPSMC_MSG_SetSoftMaxSocclkByFreq, 1), + MSG_MAP(SetSoftMaxFclkByFreq, PPSMC_MSG_SetSoftMaxFclkByFreq, 1), + MSG_MAP(SetSoftMaxVcn, PPSMC_MSG_SetSoftMaxVcn, 1), + MSG_MAP(PowerGateMmHub, PPSMC_MSG_PowerGateMmHub, 1), + MSG_MAP(UpdatePmeRestore, PPSMC_MSG_UpdatePmeRestore, 1), + MSG_MAP(GpuChangeState, PPSMC_MSG_GpuChangeState, 1), + MSG_MAP(SetPowerLimitPercentage, PPSMC_MSG_SetPowerLimitPercentage, 1), + MSG_MAP(ForceGfxContentSave, PPSMC_MSG_ForceGfxContentSave, 1), + MSG_MAP(EnableTmdp48MHzRefclkPwrDown, PPSMC_MSG_EnableTmdp48MHzRefclkPwrDown, 1), + MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 1), + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 1), + MSG_MAP(PowerGateAtHub, PPSMC_MSG_PowerGateAtHub, 1), + MSG_MAP(SetSoftMinJpeg, PPSMC_MSG_SetSoftMinJpeg, 1), + MSG_MAP(SetHardMinFclkByFreq, PPSMC_MSG_SetHardMinFclkByFreq, 1), }; -static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = { +static struct cmn2asic_mapping renoir_clk_map[SMU_CLK_COUNT] = { CLK_MAP(GFXCLK, CLOCK_GFXCLK), CLK_MAP(SCLK, CLOCK_GFXCLK), CLK_MAP(SOCCLK, CLOCK_SOCCLK), @@ -114,55 +113,20 @@ static struct smu_12_0_cmn2aisc_mapping renoir_clk_map[SMU_CLK_COUNT] = { CLK_MAP(MCLK, CLOCK_FCLK), }; -static struct smu_12_0_cmn2aisc_mapping renoir_table_map[SMU_TABLE_COUNT] = { +static struct cmn2asic_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 struct cmn2asic_mapping renoir_workload_map[PP_SMC_POWER_PROFILE_COUNT] = { + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D, WORKLOAD_PPLIB_FULL_SCREEN_3D_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_COMPUTE_BIT), + WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), +}; static int renoir_get_metrics_table(struct smu_context *smu, SmuMetrics_t *metrics_table) @@ -172,10 +136,10 @@ static int renoir_get_metrics_table(struct smu_context *smu, 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, + ret = smu_cmn_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"); + dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); mutex_unlock(&smu->metrics_lock); return ret; } @@ -188,9 +152,10 @@ static int renoir_get_metrics_table(struct smu_context *smu, return ret; } -static int renoir_tables_init(struct smu_context *smu, struct smu_table *tables) +static int renoir_init_smc_tables(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t), PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); @@ -227,23 +192,173 @@ static int renoir_get_dpm_clk_limited(struct smu_context *smu, enum smu_clk_type if (!clk_table || clk_type >= SMU_CLK_COUNT) return -EINVAL; - GET_DPM_CUR_FREQ(clk_table, clk_type, dpm_level, *freq); + switch (clk_type) { + case SMU_SOCCLK: + if (dpm_level >= NUM_SOCCLK_DPM_LEVELS) + return -EINVAL; + *freq = clk_table->SocClocks[dpm_level].Freq; + break; + case SMU_MCLK: + if (dpm_level >= NUM_FCLK_DPM_LEVELS) + return -EINVAL; + *freq = clk_table->FClocks[dpm_level].Freq; + break; + case SMU_DCEFCLK: + if (dpm_level >= NUM_DCFCLK_DPM_LEVELS) + return -EINVAL; + *freq = clk_table->DcfClocks[dpm_level].Freq; + break; + case SMU_FCLK: + if (dpm_level >= NUM_FCLK_DPM_LEVELS) + return -EINVAL; + *freq = clk_table->FClocks[dpm_level].Freq; + break; + default: + return -EINVAL; + } + + return 0; +} + +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; } +static int renoir_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; + uint32_t clock_limit; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + clock_limit = smu->smu_table.boot_values.uclk; + break; + case SMU_GFXCLK: + case SMU_SCLK: + clock_limit = smu->smu_table.boot_values.gfxclk; + break; + case SMU_SOCCLK: + clock_limit = smu->smu_table.boot_values.socclk; + break; + default: + clock_limit = 0; + break; + } + + /* clock in Mhz unit */ + if (min) + *min = clock_limit / 100; + if (max) + *max = clock_limit / 100; + + return 0; + } + + if (max) { + ret = renoir_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_cmn_send_smc_msg(smu, SMU_MSG_GetMaxGfxclkFrequency, max); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get max GX frequency from SMC Failed !\n"); + goto failed; + } + break; + case SMU_UCLK: + case SMU_FCLK: + case SMU_MCLK: + ret = renoir_get_dpm_clk_limited(smu, clk_type, mclk_mask, max); + if (ret) + goto failed; + break; + case SMU_SOCCLK: + ret = renoir_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_cmn_send_smc_msg(smu, SMU_MSG_GetMinGfxclkFrequency, min); + if (ret) { + dev_err(smu->adev->dev, "Attempt to get min GX frequency from SMC Failed !\n"); + goto failed; + } + break; + case SMU_UCLK: + case SMU_FCLK: + case SMU_MCLK: + ret = renoir_get_dpm_clk_limited(smu, clk_type, 0, min); + if (ret) + goto failed; + break; + case SMU_SOCCLK: + ret = renoir_get_dpm_clk_limited(smu, clk_type, 0, min); + if (ret) + goto failed; + break; + default: + ret = -EINVAL; + goto failed; + } + } +failed: + return ret; +} + 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; bool cur_value_match_level = false; - if (!clk_table || clk_type >= SMU_CLK_COUNT) - return -EINVAL; - memset(&metrics, 0, sizeof(metrics)); ret = renoir_get_metrics_table(smu, &metrics); @@ -255,7 +370,7 @@ static int renoir_print_clk_levels(struct smu_context *smu, 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); + ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min, &max); if (!ret) { /* driver only know min/max gfx_clk, Add level 1 for all other gfx clks */ if (cur_value == max) @@ -295,7 +410,9 @@ static int renoir_print_clk_levels(struct smu_context *smu, } for (i = 0; i < count; i++) { - GET_DPM_CUR_FREQ(clk_table, clk_type, i, value); + ret = renoir_get_dpm_clk_limited(smu, clk_type, i, &value); + if (ret) + return ret; if (!value) continue; size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, @@ -340,27 +457,23 @@ static enum amd_pm_state_type renoir_get_current_power_state(struct smu_context return pm_type; } -static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable) +static int renoir_dpm_set_vcn_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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL); 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL); if (ret) return ret; } - power_gate->vcn_gated = true; } return ret; @@ -368,24 +481,20 @@ static int renoir_dpm_set_uvd_enable(struct smu_context *smu, bool enable) 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL); 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, NULL); + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL); if (ret) return ret; } - power_gate->jpeg_gated = true; } return ret; @@ -402,7 +511,9 @@ static int renoir_get_current_clk_freq_by_table(struct smu_context *smu, if (ret) return ret; - clk_id = smu_clk_get_index(smu, clk_type); + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); if (clk_id < 0) return clk_id; @@ -425,12 +536,12 @@ static int renoir_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, false); + ret = renoir_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq); if (ret) return ret; force_freq = highest ? max_freq : min_freq; - ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq, false); + ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, force_freq, force_freq); if (ret) return ret; } @@ -454,16 +565,16 @@ static int renoir_unforce_dpm_levels(struct smu_context *smu) { }; for (i = 0; i < ARRAY_SIZE(clk_feature_map); i++) { - if (!smu_feature_is_enabled(smu, clk_feature_map[i].feature)) + if (!smu_cmn_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); + ret = renoir_get_dpm_ultimate_freq(smu, clk_type, &min_freq, &max_freq); if (ret) return ret; - ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false); + ret = smu_v12_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); if (ret) return ret; } @@ -508,69 +619,13 @@ static int renoir_get_current_activity_percent(struct smu_context *smu, *value = metrics.AverageGfxActivity / 100; break; default: - pr_err("Invalid sensor for retrieving clock activity\n"); + dev_err(smu->adev->dev, "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 */ @@ -611,7 +666,6 @@ static int renoir_force_clk_levels(struct smu_context *smu, 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; @@ -620,20 +674,20 @@ static int renoir_force_clk_levels(struct smu_context *smu, 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"); + dev_info(smu->adev->dev, "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); + ret = renoir_get_dpm_ultimate_freq(smu, SMU_GFXCLK, &min_freq, &max_freq); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, + ret = smu_cmn_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, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, + ret = smu_cmn_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, NULL); @@ -641,23 +695,31 @@ static int renoir_force_clk_levels(struct smu_context *smu, 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, NULL); + ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_min_level, &min_freq); + if (ret) + return ret; + ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_max_level, &max_freq); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max_freq, NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min_freq, NULL); 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, NULL); + ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_min_level, &min_freq); + if (ret) + return ret; + ret = renoir_get_dpm_clk_limited(smu, clk_type, soft_max_level, &max_freq); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max_freq, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min_freq, NULL); if (ret) return ret; break; @@ -674,26 +736,28 @@ static int renoir_set_power_profile_mode(struct smu_context *smu, long *input, u 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); + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", profile_mode); return -EINVAL; } /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ - workload_type = smu_workload_get_type(smu, smu->power_profile_mode); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + profile_mode); if (workload_type < 0) { /* * TODO: If some case need switch to powersave/default power mode * then can consider enter WORKLOAD_COMPUTE/WORKLOAD_CUSTOM for power saving. */ - pr_err_once("Unsupported power profile mode %d on RENOIR\n",smu->power_profile_mode); + dev_err_once(smu->adev->dev, "Unsupported power profile mode %d on RENOIR\n", profile_mode); return -EINVAL; } - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ActiveProcessNotify, 1 << workload_type, NULL); if (ret) { - pr_err_once("Fail to set workload type %d\n", workload_type); + dev_err_once(smu->adev->dev, "Fail to set workload type %d\n", workload_type); return ret; } @@ -707,19 +771,19 @@ 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); + ret = renoir_get_dpm_ultimate_freq(smu, SMU_SCLK, NULL, &sclk_freq); if (ret) return ret; - ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false); + ret = smu_v12_0_set_soft_freq_limited_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); + ret = renoir_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &uclk_freq); if (ret) return ret; - ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false); + ret = smu_v12_0_set_soft_freq_limited_range(smu, SMU_UCLK, uclk_freq, uclk_freq); if (ret) return ret; @@ -734,26 +798,26 @@ static int renoir_set_performance_level(struct smu_context *smu, switch (level) { case AMD_DPM_FORCED_LEVEL_HIGH: - ret = smu_force_dpm_limit_value(smu, true); + ret = renoir_force_dpm_limit_value(smu, true); break; case AMD_DPM_FORCED_LEVEL_LOW: - ret = smu_force_dpm_limit_value(smu, false); + ret = renoir_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); + ret = renoir_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); + ret = renoir_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); + renoir_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask); + renoir_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask); + renoir_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask); break; case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: ret = renoir_set_peak_clock_by_device(smu); @@ -771,62 +835,61 @@ static int renoir_set_performance_level(struct smu_context *smu, */ 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; + Watermarks_t *table = smu->smu_table.watermarks_table; int ret = 0; - Watermarks_t *table = watermarks; + int i; - if (!table || !clock_ranges) - return -EINVAL; + if (clock_ranges) { + if (clock_ranges->num_wm_dmif_sets > 4 || + clock_ranges->num_wm_mcif_sets > 4) + 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; + } - /* 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; + } - 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; + smu->watermarks_bitmap |= WATERMARKS_EXIST; } - smu->watermarks_bitmap |= WATERMARKS_EXIST; - /* pass data to smu controller */ - if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) { - ret = smu_write_watermarks_table(smu); + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_cmn_write_watermarks_table(smu); if (ret) { - pr_err("Failed to update WMTABLE!"); + dev_err(smu->adev->dev, "Failed to update WMTABLE!"); return ret; } smu->watermarks_bitmap |= WATERMARKS_LOADED; @@ -857,7 +920,9 @@ static int renoir_get_power_profile_mode(struct smu_context *smu, * 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); + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + i); if (workload_type < 0) continue; @@ -887,8 +952,19 @@ static int renoir_read_sensor(struct smu_context *smu, ret = renoir_get_gpu_temperature(smu, (uint32_t *)data); *size = 4; break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = renoir_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = renoir_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; default: - ret = smu_v12_0_read_sensor(smu, sensor, data, size); + ret = -EOPNOTSUPP; + break; } mutex_unlock(&smu->sensor_lock); @@ -912,21 +988,11 @@ static bool renoir_is_dpm_running(struct smu_context *smu) } 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_vcn_enable = renoir_dpm_set_vcn_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, @@ -937,26 +1003,33 @@ static const struct pptable_funcs renoir_ppt_funcs = { .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, + .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param, + .send_smc_msg = smu_cmn_send_smc_msg, .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, + .get_gfx_off_status = smu_v12_0_get_gfxoff_status, + .init_smc_tables = renoir_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, + .set_default_dpm_table = smu_v12_0_set_default_dpm_tables, + .get_enabled_mask = smu_cmn_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, + .get_dpm_ultimate_freq = renoir_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, .is_dpm_running = renoir_is_dpm_running, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, }; void renoir_set_ppt_funcs(struct smu_context *smu) { smu->ppt_funcs = &renoir_ppt_funcs; + smu->message_map = renoir_message_map; + smu->clock_map = renoir_clk_map; + smu->table_map = renoir_table_map; + smu->workload_map = renoir_workload_map; smu->smc_driver_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 index 89cd6da118a3..8c3f004cdf8d 100644 --- a/drivers/gpu/drm/amd/powerplay/renoir_ppt.h +++ b/drivers/gpu/drm/amd/powerplay/renoir_ppt.h @@ -30,24 +30,4 @@ extern void renoir_set_ppt_funcs(struct smu_context *smu); #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->FClocks[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/sienna_cichlid_ppt.c b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c new file mode 100644 index 000000000000..3865dbed5f93 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.c @@ -0,0 +1,2735 @@ +/* + * 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. + * + */ + +#define SWSMU_CODE_LAYER_L2 + +#include <linux/firmware.h> +#include <linux/pci.h> +#include <linux/i2c.h> +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "atomfirmware.h" +#include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" +#include "smu_v11_0.h" +#include "smu11_driver_if_sienna_cichlid.h" +#include "soc15_common.h" +#include "atom.h" +#include "sienna_cichlid_ppt.h" +#include "smu_v11_0_7_pptable.h" +#include "smu_v11_0_7_ppsmc.h" +#include "nbio/nbio_2_3_offset.h" +#include "nbio/nbio_2_3_sh_mask.h" +#include "thm/thm_11_0_2_offset.h" +#include "thm/thm_11_0_2_sh_mask.h" +#include "mp/mp_11_0_offset.h" +#include "mp/mp_11_0_sh_mask.h" + +#include "asic_reg/mp/mp_11_0_sh_mask.h" +#include "smu_cmn.h" + +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c)) + +#define FEATURE_MASK(feature) (1ULL << feature) +#define SMC_DPM_FEATURE ( \ + FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) | \ + FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_UCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_LINK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_FCLK_BIT) | \ + FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT)) + +#define SMU_11_0_7_GFX_BUSY_THRESHOLD 15 + +static struct cmn2asic_msg_mapping sienna_cichlid_message_map[SMU_MSG_MAX_COUNT] = { + MSG_MAP(TestMessage, PPSMC_MSG_TestMessage, 1), + MSG_MAP(GetSmuVersion, PPSMC_MSG_GetSmuVersion, 1), + MSG_MAP(GetDriverIfVersion, PPSMC_MSG_GetDriverIfVersion, 1), + MSG_MAP(SetAllowedFeaturesMaskLow, PPSMC_MSG_SetAllowedFeaturesMaskLow, 0), + MSG_MAP(SetAllowedFeaturesMaskHigh, PPSMC_MSG_SetAllowedFeaturesMaskHigh, 0), + MSG_MAP(EnableAllSmuFeatures, PPSMC_MSG_EnableAllSmuFeatures, 0), + MSG_MAP(DisableAllSmuFeatures, PPSMC_MSG_DisableAllSmuFeatures, 0), + MSG_MAP(EnableSmuFeaturesLow, PPSMC_MSG_EnableSmuFeaturesLow, 1), + MSG_MAP(EnableSmuFeaturesHigh, PPSMC_MSG_EnableSmuFeaturesHigh, 1), + MSG_MAP(DisableSmuFeaturesLow, PPSMC_MSG_DisableSmuFeaturesLow, 1), + MSG_MAP(DisableSmuFeaturesHigh, PPSMC_MSG_DisableSmuFeaturesHigh, 1), + MSG_MAP(GetEnabledSmuFeaturesLow, PPSMC_MSG_GetRunningSmuFeaturesLow, 1), + MSG_MAP(GetEnabledSmuFeaturesHigh, PPSMC_MSG_GetRunningSmuFeaturesHigh, 1), + MSG_MAP(SetWorkloadMask, PPSMC_MSG_SetWorkloadMask, 1), + MSG_MAP(SetPptLimit, PPSMC_MSG_SetPptLimit, 0), + MSG_MAP(SetDriverDramAddrHigh, PPSMC_MSG_SetDriverDramAddrHigh, 0), + MSG_MAP(SetDriverDramAddrLow, PPSMC_MSG_SetDriverDramAddrLow, 0), + MSG_MAP(SetToolsDramAddrHigh, PPSMC_MSG_SetToolsDramAddrHigh, 0), + MSG_MAP(SetToolsDramAddrLow, PPSMC_MSG_SetToolsDramAddrLow, 0), + MSG_MAP(TransferTableSmu2Dram, PPSMC_MSG_TransferTableSmu2Dram, 0), + MSG_MAP(TransferTableDram2Smu, PPSMC_MSG_TransferTableDram2Smu, 0), + MSG_MAP(UseDefaultPPTable, PPSMC_MSG_UseDefaultPPTable, 0), + MSG_MAP(EnterBaco, PPSMC_MSG_EnterBaco, 0), + MSG_MAP(SetSoftMinByFreq, PPSMC_MSG_SetSoftMinByFreq, 0), + MSG_MAP(SetSoftMaxByFreq, PPSMC_MSG_SetSoftMaxByFreq, 0), + MSG_MAP(SetHardMinByFreq, PPSMC_MSG_SetHardMinByFreq, 1), + MSG_MAP(SetHardMaxByFreq, PPSMC_MSG_SetHardMaxByFreq, 0), + MSG_MAP(GetMinDpmFreq, PPSMC_MSG_GetMinDpmFreq, 1), + MSG_MAP(GetMaxDpmFreq, PPSMC_MSG_GetMaxDpmFreq, 1), + MSG_MAP(GetDpmFreqByIndex, PPSMC_MSG_GetDpmFreqByIndex, 1), + MSG_MAP(SetGeminiMode, PPSMC_MSG_SetGeminiMode, 0), + MSG_MAP(SetGeminiApertureHigh, PPSMC_MSG_SetGeminiApertureHigh, 0), + MSG_MAP(SetGeminiApertureLow, PPSMC_MSG_SetGeminiApertureLow, 0), + MSG_MAP(OverridePcieParameters, PPSMC_MSG_OverridePcieParameters, 0), + MSG_MAP(ReenableAcDcInterrupt, PPSMC_MSG_ReenableAcDcInterrupt, 0), + MSG_MAP(NotifyPowerSource, PPSMC_MSG_NotifyPowerSource, 0), + MSG_MAP(SetUclkFastSwitch, PPSMC_MSG_SetUclkFastSwitch, 0), + MSG_MAP(SetVideoFps, PPSMC_MSG_SetVideoFps, 0), + MSG_MAP(PrepareMp1ForUnload, PPSMC_MSG_PrepareMp1ForUnload, 1), + MSG_MAP(AllowGfxOff, PPSMC_MSG_AllowGfxOff, 0), + MSG_MAP(DisallowGfxOff, PPSMC_MSG_DisallowGfxOff, 0), + MSG_MAP(GetPptLimit, PPSMC_MSG_GetPptLimit, 0), + MSG_MAP(GetDcModeMaxDpmFreq, PPSMC_MSG_GetDcModeMaxDpmFreq, 1), + MSG_MAP(ExitBaco, PPSMC_MSG_ExitBaco, 0), + MSG_MAP(PowerUpVcn, PPSMC_MSG_PowerUpVcn, 0), + MSG_MAP(PowerDownVcn, PPSMC_MSG_PowerDownVcn, 0), + MSG_MAP(PowerUpJpeg, PPSMC_MSG_PowerUpJpeg, 0), + MSG_MAP(PowerDownJpeg, PPSMC_MSG_PowerDownJpeg, 0), + MSG_MAP(BacoAudioD3PME, PPSMC_MSG_BacoAudioD3PME, 0), + MSG_MAP(ArmD3, PPSMC_MSG_ArmD3, 0), + MSG_MAP(Mode1Reset, PPSMC_MSG_Mode1Reset, 0), +}; + +static struct cmn2asic_mapping sienna_cichlid_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_0), + CLK_MAP(DCLK1, PPCLK_DCLK_1), + CLK_MAP(VCLK, PPCLK_VCLK_0), + CLK_MAP(VCLK1, PPCLK_VCLK_1), + CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), + CLK_MAP(DISPCLK, PPCLK_DISPCLK), + CLK_MAP(PIXCLK, PPCLK_PIXCLK), + CLK_MAP(PHYCLK, PPCLK_PHYCLK), +}; + +static struct cmn2asic_mapping sienna_cichlid_feature_mask_map[SMU_FEATURE_COUNT] = { + FEA_MAP(DPM_PREFETCHER), + FEA_MAP(DPM_GFXCLK), + FEA_MAP(DPM_GFX_GPO), + FEA_MAP(DPM_UCLK), + FEA_MAP(DPM_SOCCLK), + FEA_MAP(DPM_MP0CLK), + FEA_MAP(DPM_LINK), + FEA_MAP(DPM_DCEFCLK), + FEA_MAP(MEM_VDDCI_SCALING), + FEA_MAP(MEM_MVDD_SCALING), + FEA_MAP(DS_GFXCLK), + FEA_MAP(DS_SOCCLK), + FEA_MAP(DS_LCLK), + FEA_MAP(DS_DCEFCLK), + FEA_MAP(DS_UCLK), + FEA_MAP(GFX_ULV), + FEA_MAP(FW_DSTATE), + FEA_MAP(GFXOFF), + FEA_MAP(BACO), + FEA_MAP(MM_DPM_PG), + FEA_MAP(RSMU_SMN_CG), + FEA_MAP(PPT), + FEA_MAP(TDC), + FEA_MAP(APCC_PLUS), + FEA_MAP(GTHR), + FEA_MAP(ACDC), + FEA_MAP(VR0HOT), + FEA_MAP(VR1HOT), + FEA_MAP(FW_CTF), + FEA_MAP(FAN_CONTROL), + FEA_MAP(THERMAL), + FEA_MAP(GFX_DCS), + FEA_MAP(RM), + FEA_MAP(LED_DISPLAY), + FEA_MAP(GFX_SS), + FEA_MAP(OUT_OF_BAND_MONITOR), + FEA_MAP(TEMP_DEPENDENT_VMIN), + FEA_MAP(MMHUB_PG), + FEA_MAP(ATHUB_PG), + FEA_MAP(APCC_DFLL), +}; + +static struct cmn2asic_mapping sienna_cichlid_table_map[SMU_TABLE_COUNT] = { + TAB_MAP(PPTABLE), + TAB_MAP(WATERMARKS), + TAB_MAP(AVFS_PSM_DEBUG), + TAB_MAP(AVFS_FUSE_OVERRIDE), + TAB_MAP(PMSTATUSLOG), + TAB_MAP(SMU_METRICS), + TAB_MAP(DRIVER_SMU_CONFIG), + TAB_MAP(ACTIVITY_MONITOR_COEFF), + TAB_MAP(OVERDRIVE), + TAB_MAP(I2C_COMMANDS), + TAB_MAP(PACE), +}; + +static struct cmn2asic_mapping sienna_cichlid_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { + PWR_MAP(AC), + PWR_MAP(DC), +}; + +static struct cmn2asic_mapping sienna_cichlid_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_CUSTOM, WORKLOAD_PPLIB_CUSTOM_BIT), +}; + +static int +sienna_cichlid_get_allowed_feature_mask(struct smu_context *smu, + uint32_t *feature_mask, uint32_t num) +{ + struct amdgpu_device *adev = smu->adev; + + if (num > 2) + return -EINVAL; + + memset(feature_mask, 0, sizeof(uint32_t) * num); + + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_PREFETCHER_BIT) + | FEATURE_MASK(FEATURE_DPM_FCLK_BIT) + | FEATURE_MASK(FEATURE_DS_SOCCLK_BIT) + | FEATURE_MASK(FEATURE_DS_DCEFCLK_BIT) + | FEATURE_MASK(FEATURE_DS_FCLK_BIT) + | FEATURE_MASK(FEATURE_DS_UCLK_BIT) + | FEATURE_MASK(FEATURE_FW_DSTATE_BIT) + | FEATURE_MASK(FEATURE_DF_CSTATE_BIT) + | FEATURE_MASK(FEATURE_RSMU_SMN_CG_BIT) + | FEATURE_MASK(FEATURE_GFX_SS_BIT) + | FEATURE_MASK(FEATURE_VR0HOT_BIT) + | FEATURE_MASK(FEATURE_PPT_BIT) + | FEATURE_MASK(FEATURE_TDC_BIT) + | FEATURE_MASK(FEATURE_BACO_BIT) + | FEATURE_MASK(FEATURE_APCC_DFLL_BIT) + | FEATURE_MASK(FEATURE_FW_CTF_BIT) + | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) + | FEATURE_MASK(FEATURE_THERMAL_BIT) + | FEATURE_MASK(FEATURE_OUT_OF_BAND_MONITOR_BIT); + + if (adev->pm.pp_feature & PP_SCLK_DPM_MASK) { + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFXCLK_BIT); + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_GFX_GPO_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_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_SOCCLK_DPM_MASK) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT); + + 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); + + if (smu->adev->pg_flags & AMD_PG_SUPPORT_ATHUB) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_ATHUB_PG_BIT); + + if (smu->adev->pg_flags & AMD_PG_SUPPORT_MMHUB) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MMHUB_PG_BIT); + + if (smu->adev->pg_flags & AMD_PG_SUPPORT_VCN || + smu->adev->pg_flags & AMD_PG_SUPPORT_JPEG) + *(uint64_t *)feature_mask |= FEATURE_MASK(FEATURE_MM_DPM_PG_BIT); + + return 0; +} + +static int sienna_cichlid_check_powerplay_table(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_7_powerplay_table *powerplay_table = + table_context->power_play_table; + struct smu_baco_context *smu_baco = &smu->smu_baco; + + mutex_lock(&smu_baco->mutex); + if (powerplay_table->platform_caps & SMU_11_0_7_PP_PLATFORM_CAP_BACO || + powerplay_table->platform_caps & SMU_11_0_7_PP_PLATFORM_CAP_MACO) + smu_baco->platform_support = true; + mutex_unlock(&smu_baco->mutex); + + table_context->thermal_controller_type = + powerplay_table->thermal_controller_type; + + return 0; +} + +static int sienna_cichlid_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_9 *smc_dpm_table; + int index, ret; + + index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, + smc_dpm_info); + + ret = amdgpu_atombios_get_data_table(smu->adev, index, NULL, NULL, NULL, + (uint8_t **)&smc_dpm_table); + if (ret) + return ret; + + memcpy(smc_pptable->I2cControllers, smc_dpm_table->I2cControllers, + sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header)); + + return 0; +} + +static int sienna_cichlid_store_powerplay_table(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_7_powerplay_table *powerplay_table = + table_context->power_play_table; + + memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable, + sizeof(PPTable_t)); + + return 0; +} + +static int sienna_cichlid_setup_pptable(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_v11_0_setup_pptable(smu); + if (ret) + return ret; + + ret = sienna_cichlid_store_powerplay_table(smu); + if (ret) + return ret; + + ret = sienna_cichlid_append_powerplay_table(smu); + if (ret) + return ret; + + ret = sienna_cichlid_check_powerplay_table(smu); + if (ret) + return ret; + + return ret; +} + +static int sienna_cichlid_tables_init(struct smu_context *smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct smu_table *tables = smu_table->tables; + + SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_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_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t), + PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM); + SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_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_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; + + smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); + if (!smu_table->watermarks_table) + return -ENOMEM; + + return 0; +} + +static int sienna_cichlid_get_smu_metrics_data(struct smu_context *smu, + MetricsMember_t member, + uint32_t *value) +{ + struct smu_table_context *smu_table= &smu->smu_table; + SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table; + int ret = 0; + + mutex_lock(&smu->metrics_lock); + if (!smu_table->metrics_time || + time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) { + ret = smu_cmn_update_table(smu, + SMU_TABLE_SMU_METRICS, + 0, + smu_table->metrics_table, + false); + if (ret) { + dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n"); + mutex_unlock(&smu->metrics_lock); + return ret; + } + smu_table->metrics_time = jiffies; + } + + switch (member) { + case METRICS_CURR_GFXCLK: + *value = metrics->CurrClock[PPCLK_GFXCLK]; + break; + case METRICS_CURR_SOCCLK: + *value = metrics->CurrClock[PPCLK_SOCCLK]; + break; + case METRICS_CURR_UCLK: + *value = metrics->CurrClock[PPCLK_UCLK]; + break; + case METRICS_CURR_VCLK: + *value = metrics->CurrClock[PPCLK_VCLK_0]; + break; + case METRICS_CURR_VCLK1: + *value = metrics->CurrClock[PPCLK_VCLK_1]; + break; + case METRICS_CURR_DCLK: + *value = metrics->CurrClock[PPCLK_DCLK_0]; + break; + case METRICS_CURR_DCLK1: + *value = metrics->CurrClock[PPCLK_DCLK_1]; + break; + case METRICS_CURR_DCEFCLK: + *value = metrics->CurrClock[PPCLK_DCEFCLK]; + break; + case METRICS_AVERAGE_GFXCLK: + if (metrics->AverageGfxActivity <= SMU_11_0_7_GFX_BUSY_THRESHOLD) + *value = metrics->AverageGfxclkFrequencyPostDs; + else + *value = metrics->AverageGfxclkFrequencyPreDs; + break; + case METRICS_AVERAGE_FCLK: + *value = metrics->AverageFclkFrequencyPostDs; + break; + case METRICS_AVERAGE_UCLK: + *value = metrics->AverageUclkFrequencyPostDs; + break; + case METRICS_AVERAGE_GFXACTIVITY: + *value = metrics->AverageGfxActivity; + break; + case METRICS_AVERAGE_MEMACTIVITY: + *value = metrics->AverageUclkActivity; + break; + case METRICS_AVERAGE_SOCKETPOWER: + *value = metrics->AverageSocketPower << 8; + break; + case METRICS_TEMPERATURE_EDGE: + *value = metrics->TemperatureEdge * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_HOTSPOT: + *value = metrics->TemperatureHotspot * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_MEM: + *value = metrics->TemperatureMem * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRGFX: + *value = metrics->TemperatureVrGfx * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_TEMPERATURE_VRSOC: + *value = metrics->TemperatureVrSoc * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + break; + case METRICS_THROTTLER_STATUS: + *value = metrics->ThrottlerStatus; + break; + case METRICS_CURR_FANSPEED: + *value = metrics->CurrFanSpeed; + break; + default: + *value = UINT_MAX; + break; + } + + mutex_unlock(&smu->metrics_lock); + + return ret; + +} + +static int sienna_cichlid_allocate_dpm_context(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + + smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context), + GFP_KERNEL); + if (!smu_dpm->dpm_context) + return -ENOMEM; + + smu_dpm->dpm_context_size = sizeof(struct smu_11_0_dpm_context); + + return 0; +} + +static int sienna_cichlid_init_smc_tables(struct smu_context *smu) +{ + int ret = 0; + + ret = sienna_cichlid_tables_init(smu); + if (ret) + return ret; + + ret = sienna_cichlid_allocate_dpm_context(smu); + if (ret) + return ret; + + return smu_v11_0_init_smc_tables(smu); +} + +static int sienna_cichlid_set_default_dpm_table(struct smu_context *smu) +{ + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + PPTable_t *driver_ppt = smu->smu_table.driver_pptable; + struct smu_11_0_dpm_table *dpm_table; + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + /* socclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.soc_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_SOCCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* gfxclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.gfx_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_GFXCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* uclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.uclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_UCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* fclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.fclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_FCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_FCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.fclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* vclk0 dpm table setup */ + dpm_table = &dpm_context->dpm_tables.vclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_VCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_VCLK_0].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* vclk1 dpm table setup */ + if (adev->vcn.num_vcn_inst > 1) { + dpm_table = &dpm_context->dpm_tables.vclk1_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_VCLK1, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_VCLK_1].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = + smu->smu_table.boot_values.vclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + } + + /* dclk0 dpm table setup */ + dpm_table = &dpm_context->dpm_tables.dclk_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DCLK_0].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* dclk1 dpm table setup */ + if (adev->vcn.num_vcn_inst > 1) { + dpm_table = &dpm_context->dpm_tables.dclk1_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DCLK1, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DCLK_1].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = + smu->smu_table.boot_values.dclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + } + + /* dcefclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.dcef_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DCEFCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* pixelclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.pixel_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_PIXCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* displayclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.display_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_DISPCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + /* phyclk dpm table setup */ + dpm_table = &dpm_context->dpm_tables.phy_table; + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + ret = smu_v11_0_set_single_dpm_table(smu, + SMU_PHYCLK, + dpm_table); + if (ret) + return ret; + dpm_table->is_fine_grained = + !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete; + } else { + dpm_table->count = 1; + dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; + dpm_table->dpm_levels[0].enabled = true; + dpm_table->min = dpm_table->dpm_levels[0].value; + dpm_table->max = dpm_table->dpm_levels[0].value; + } + + return 0; +} + +static int sienna_cichlid_dpm_set_vcn_enable(struct smu_context *smu, bool enable) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0; + + if (enable) { + /* vcn dpm on is a prerequisite for vcn power gate messages */ + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 0, NULL); + if (ret) + return ret; + if (adev->asic_type == CHIP_SIENNA_CICHLID) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, + 0x10000, NULL); + if (ret) + return ret; + } + } + } else { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, 0, NULL); + if (ret) + return ret; + if (adev->asic_type == CHIP_SIENNA_CICHLID) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownVcn, + 0x10000, NULL); + if (ret) + return ret; + } + } + } + + return ret; +} + +static int sienna_cichlid_dpm_set_jpeg_enable(struct smu_context *smu, bool enable) +{ + int ret = 0; + + if (enable) { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL); + if (ret) + return ret; + } + } else { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_MM_DPM_PG_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerDownJpeg, 0, NULL); + if (ret) + return ret; + } + } + + return ret; +} + +static int sienna_cichlid_get_current_clk_freq_by_table(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + MetricsMember_t member_type; + int clk_id = 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; + + switch (clk_id) { + case PPCLK_GFXCLK: + member_type = METRICS_CURR_GFXCLK; + break; + case PPCLK_UCLK: + member_type = METRICS_CURR_UCLK; + break; + case PPCLK_SOCCLK: + member_type = METRICS_CURR_SOCCLK; + break; + case PPCLK_FCLK: + member_type = METRICS_CURR_FCLK; + break; + case PPCLK_VCLK_0: + member_type = METRICS_CURR_VCLK; + break; + case PPCLK_VCLK_1: + member_type = METRICS_CURR_VCLK1; + break; + case PPCLK_DCLK_0: + member_type = METRICS_CURR_DCLK; + break; + case PPCLK_DCLK_1: + member_type = METRICS_CURR_DCLK1; + break; + case PPCLK_DCEFCLK: + member_type = METRICS_CURR_DCEFCLK; + break; + default: + return -EINVAL; + } + + return sienna_cichlid_get_smu_metrics_data(smu, + member_type, + value); + +} + +static bool sienna_cichlid_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type) +{ + PPTable_t *pptable = smu->smu_table.driver_pptable; + DpmDescriptor_t *dpm_desc = NULL; + uint32_t clk_index = 0; + + clk_index = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + dpm_desc = &pptable->DpmDescriptor[clk_index]; + + /* 0 - Fine grained DPM, 1 - Discrete DPM */ + return dpm_desc->SnapToDiscrete == 0 ? true : false; +} + +static int sienna_cichlid_print_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, char *buf) +{ + struct amdgpu_device *adev = smu->adev; + struct smu_table_context *table_context = &smu->smu_table; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; + struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context; + PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; + 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; + uint32_t gen_speed, lane_width; + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + case SMU_SOCCLK: + case SMU_MCLK: + case SMU_UCLK: + case SMU_FCLK: + case SMU_DCEFCLK: + ret = sienna_cichlid_get_current_clk_freq_by_table(smu, clk_type, &cur_value); + if (ret) + goto print_clk_out; + + /* no need to disable gfxoff when retrieving the current gfxclk */ + if ((clk_type == SMU_GFXCLK) || (clk_type == SMU_SCLK)) + amdgpu_gfx_off_ctrl(adev, false); + + ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count); + if (ret) + goto print_clk_out; + + if (!sienna_cichlid_is_support_fine_grained_dpm(smu, clk_type)) { + for (i = 0; i < count; i++) { + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value); + if (ret) + goto print_clk_out; + + size += sprintf(buf + size, "%d: %uMhz %s\n", i, value, + cur_value == value ? "*" : ""); + } + } else { + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]); + if (ret) + goto print_clk_out; + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]); + if (ret) + goto print_clk_out; + + freq_values[1] = cur_value; + mark_index = cur_value == freq_values[0] ? 0 : + cur_value == freq_values[2] ? 2 : 1; + if (mark_index != 1) + freq_values[1] = (freq_values[0] + freq_values[2]) / 2; + + for (i = 0; i < 3; i++) { + size += sprintf(buf + size, "%d: %uMhz %s\n", i, freq_values[i], + i == mark_index ? "*" : ""); + } + + } + 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; + default: + break; + } + +print_clk_out: + if ((clk_type == SMU_GFXCLK) || (clk_type == SMU_SCLK)) + amdgpu_gfx_off_ctrl(adev, true); + + return size; +} + +static int sienna_cichlid_force_clk_levels(struct smu_context *smu, + enum smu_clk_type clk_type, uint32_t mask) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0, size = 0; + uint32_t soft_min_level = 0, soft_max_level = 0, min_freq = 0, max_freq = 0; + + soft_min_level = mask ? (ffs(mask) - 1) : 0; + soft_max_level = mask ? (fls(mask) - 1) : 0; + + if ((clk_type == SMU_GFXCLK) || (clk_type == SMU_SCLK)) + amdgpu_gfx_off_ctrl(adev, false); + + switch (clk_type) { + case SMU_GFXCLK: + case SMU_SCLK: + case SMU_SOCCLK: + case SMU_MCLK: + case SMU_UCLK: + case SMU_DCEFCLK: + case SMU_FCLK: + /* There is only 2 levels for fine grained DPM */ + if (sienna_cichlid_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_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq); + if (ret) + goto forec_level_out; + + ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq); + if (ret) + goto forec_level_out; + + ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq); + if (ret) + goto forec_level_out; + break; + default: + break; + } + +forec_level_out: + if ((clk_type == SMU_GFXCLK) || (clk_type == SMU_SCLK)) + amdgpu_gfx_off_ctrl(adev, true); + + return size; +} + +static int sienna_cichlid_populate_umd_state_clk(struct smu_context *smu) +{ + struct smu_11_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_11_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_11_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_11_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + + pstate_table->gfxclk_pstate.min = gfx_table->min; + pstate_table->gfxclk_pstate.peak = gfx_table->max; + + pstate_table->uclk_pstate.min = mem_table->min; + pstate_table->uclk_pstate.peak = mem_table->max; + + pstate_table->socclk_pstate.min = soc_table->min; + pstate_table->socclk_pstate.peak = soc_table->max; + + return 0; +} + +static int sienna_cichlid_pre_display_config_changed(struct smu_context *smu) +{ + int ret = 0; + uint32_t max_freq = 0; + + /* Sienna_Cichlid do not support to change display num currently */ + return 0; +#if 0 + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL); + if (ret) + return ret; +#endif + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &max_freq); + if (ret) + return ret; + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, max_freq); + if (ret) + return ret; + } + + return ret; +} + +static int sienna_cichlid_display_config_changed(struct smu_context *smu) +{ + int ret = 0; + + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && + smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { +#if 0 + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, + smu->display_config->num_display, + NULL); +#endif + if (ret) + return ret; + } + + return ret; +} + +static int sienna_cichlid_get_gpu_power(struct smu_context *smu, uint32_t *value) +{ + if (!value) + return -EINVAL; + + return sienna_cichlid_get_smu_metrics_data(smu, + METRICS_AVERAGE_SOCKETPOWER, + value); +} + +static int sienna_cichlid_get_current_activity_percent(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = sienna_cichlid_get_smu_metrics_data(smu, + METRICS_AVERAGE_GFXACTIVITY, + value); + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + ret = sienna_cichlid_get_smu_metrics_data(smu, + METRICS_AVERAGE_MEMACTIVITY, + value); + break; + default: + dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n"); + return -EINVAL; + } + + return ret; +} + +static bool sienna_cichlid_is_dpm_running(struct smu_context *smu) +{ + int ret = 0; + uint32_t feature_mask[2]; + unsigned long feature_enabled; + ret = smu_cmn_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 sienna_cichlid_get_fan_speed_rpm(struct smu_context *smu, + uint32_t *speed) +{ + if (!speed) + return -EINVAL; + + return sienna_cichlid_get_smu_metrics_data(smu, + METRICS_CURR_FANSPEED, + speed); +} + +static int sienna_cichlid_get_fan_speed_percent(struct smu_context *smu, + uint32_t *speed) +{ + int ret = 0; + uint32_t percent = 0; + uint32_t current_rpm; + PPTable_t *pptable = smu->smu_table.driver_pptable; + + ret = sienna_cichlid_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 sienna_cichlid_get_power_profile_mode(struct smu_context *smu, char *buf) +{ + DpmActivityMonitorCoeffInt_t activity_monitor; + uint32_t i, size = 0; + int16_t workload_type = 0; + 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", + "MinFreqType", + "MinActiveFreqType", + "MinActiveFreq", + "BoosterFreqType", + "BoosterFreq", + "PD_Data_limit_c", + "PD_Data_error_coeff", + "PD_Data_error_rate_coeff"}; + int result = 0; + + if (!buf) + return -EINVAL; + + 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]); + + for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) { + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + i); + if (workload_type < 0) + return -EINVAL; + + result = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type, + (void *)(&activity_monitor), false); + if (result) { + dev_err(smu->adev->dev, "[%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) ? "*" : " "); + + 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_MinFreqStep, + 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, + "SOCCLK", + activity_monitor.Fclk_FPS, + activity_monitor.Fclk_MinFreqStep, + activity_monitor.Fclk_MinActiveFreqType, + activity_monitor.Fclk_MinActiveFreq, + activity_monitor.Fclk_BoosterFreqType, + activity_monitor.Fclk_BoosterFreq, + activity_monitor.Fclk_PD_Data_limit_c, + activity_monitor.Fclk_PD_Data_error_coeff, + activity_monitor.Fclk_PD_Data_error_rate_coeff); + + size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", + " ", + 2, + "MEMLK", + activity_monitor.Mem_FPS, + activity_monitor.Mem_MinFreqStep, + 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 sienna_cichlid_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) +{ + DpmActivityMonitorCoeffInt_t activity_monitor; + int workload_type, ret = 0; + + smu->power_profile_mode = input[size]; + + if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { + dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode); + return -EINVAL; + } + + if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { + + ret = smu_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), false); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__); + return ret; + } + + switch (input[0]) { + case 0: /* Gfxclk */ + activity_monitor.Gfx_FPS = input[1]; + activity_monitor.Gfx_MinFreqStep = 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: /* Socclk */ + activity_monitor.Fclk_FPS = input[1]; + activity_monitor.Fclk_MinFreqStep = input[2]; + activity_monitor.Fclk_MinActiveFreqType = input[3]; + activity_monitor.Fclk_MinActiveFreq = input[4]; + activity_monitor.Fclk_BoosterFreqType = input[5]; + activity_monitor.Fclk_BoosterFreq = input[6]; + activity_monitor.Fclk_PD_Data_limit_c = input[7]; + activity_monitor.Fclk_PD_Data_error_coeff = input[8]; + activity_monitor.Fclk_PD_Data_error_rate_coeff = input[9]; + break; + case 2: /* Memlk */ + activity_monitor.Mem_FPS = input[1]; + activity_monitor.Mem_MinFreqStep = 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_cmn_update_table(smu, + SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT, + (void *)(&activity_monitor), true); + if (ret) { + dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__); + return ret; + } + } + + /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */ + workload_type = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_WORKLOAD, + smu->power_profile_mode); + if (workload_type < 0) + return -EINVAL; + smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask, + 1 << workload_type, NULL); + + return ret; +} + +static int sienna_cichlid_notify_smc_display_config(struct smu_context *smu) +{ + struct smu_clocks min_clocks = {0}; + struct pp_display_clock_request clock_req; + int ret = 0; + + min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; + min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk; + min_clocks.memory_clock = smu->display_config->min_mem_set_clock; + + if (smu_cmn_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; + + ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req); + if (!ret) { + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_SetMinDeepSleepDcefclk, + min_clocks.dcef_clock_in_sr/100, + NULL); + if (ret) { + dev_err(smu->adev->dev, "Attempt to set divider for DCEFCLK Failed!"); + return ret; + } + } + } else { + dev_info(smu->adev->dev, "Attempt to set Hard Min for DCEFCLK Failed!"); + } + } + + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0); + if (ret) { + dev_err(smu->adev->dev, "[%s] Set hard min uclk failed!", __func__); + return ret; + } + } + + return 0; +} + +static int sienna_cichlid_set_watermarks_table(struct smu_context *smu, + struct dm_pp_wm_sets_with_clock_ranges_soc15 + *clock_ranges) +{ + Watermarks_t *table = smu->smu_table.watermarks_table; + int ret = 0; + int i; + + if (clock_ranges) { + if (clock_ranges->num_wm_dmif_sets > 4 || + clock_ranges->num_wm_mcif_sets > 4) + return -EINVAL; + + for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { + table->WatermarkRow[1][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MinUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / + 1000)); + table->WatermarkRow[1][i].MaxUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / + 1000)); + table->WatermarkRow[1][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[0][i].MinClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MaxClock = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MinUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].MaxUclk = + cpu_to_le16((uint16_t) + (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / + 1000)); + table->WatermarkRow[0][i].WmSetting = (uint8_t) + clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; + } + + smu->watermarks_bitmap |= WATERMARKS_EXIST; + } + + if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && + !(smu->watermarks_bitmap & WATERMARKS_LOADED)) { + ret = smu_cmn_write_watermarks_table(smu); + if (ret) { + dev_err(smu->adev->dev, "Failed to update WMTABLE!"); + return ret; + } + smu->watermarks_bitmap |= WATERMARKS_LOADED; + } + + return 0; +} + +static int sienna_cichlid_thermal_get_temperature(struct smu_context *smu, + enum amd_pp_sensors sensor, + uint32_t *value) +{ + int ret = 0; + + if (!value) + return -EINVAL; + + switch (sensor) { + case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: + ret = sienna_cichlid_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_HOTSPOT, + value); + break; + case AMDGPU_PP_SENSOR_EDGE_TEMP: + ret = sienna_cichlid_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_EDGE, + value); + break; + case AMDGPU_PP_SENSOR_MEM_TEMP: + ret = sienna_cichlid_get_smu_metrics_data(smu, + METRICS_TEMPERATURE_MEM, + value); + break; + default: + dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n"); + return -EINVAL; + } + + return ret; +} + +static int sienna_cichlid_read_sensor(struct smu_context *smu, + enum amd_pp_sensors sensor, + void *data, uint32_t *size) +{ + int ret = 0; + 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; + *size = 4; + break; + case AMDGPU_PP_SENSOR_MEM_LOAD: + case AMDGPU_PP_SENSOR_GPU_LOAD: + ret = sienna_cichlid_get_current_activity_percent(smu, sensor, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GPU_POWER: + ret = sienna_cichlid_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 = sienna_cichlid_thermal_get_temperature(smu, sensor, (uint32_t *)data); + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_MCLK: + ret = sienna_cichlid_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_GFX_SCLK: + ret = sienna_cichlid_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data); + *(uint32_t *)data *= 100; + *size = 4; + break; + case AMDGPU_PP_SENSOR_VDDGFX: + ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data); + *size = 4; + break; + default: + ret = -EOPNOTSUPP; + break; + } + mutex_unlock(&smu->sensor_lock); + + return ret; +} + +static int sienna_cichlid_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_in_khz, uint32_t *num_states) +{ + uint32_t num_discrete_levels = 0; + uint16_t *dpm_levels = NULL; + uint16_t i = 0; + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *driver_ppt = NULL; + + if (!clocks_in_khz || !num_states || !table_context->driver_pptable) + return -EINVAL; + + driver_ppt = table_context->driver_pptable; + num_discrete_levels = driver_ppt->DpmDescriptor[PPCLK_UCLK].NumDiscreteLevels; + dpm_levels = driver_ppt->FreqTableUclk; + + if (num_discrete_levels == 0 || dpm_levels == NULL) + return -EINVAL; + + *num_states = num_discrete_levels; + for (i = 0; i < num_discrete_levels; i++) { + /* convert to khz */ + *clocks_in_khz = (*dpm_levels) * 1000; + clocks_in_khz++; + dpm_levels++; + } + + return 0; +} + +static int sienna_cichlid_get_thermal_temperature_range(struct smu_context *smu, + struct smu_temperature_range *range) +{ + struct smu_table_context *table_context = &smu->smu_table; + struct smu_11_0_7_powerplay_table *powerplay_table = + table_context->power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; + + if (!range) + return -EINVAL; + + memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range)); + + range->max = pptable->TemperatureLimit[TEMP_EDGE] * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->edge_emergency_max = (pptable->TemperatureLimit[TEMP_EDGE] + CTF_OFFSET_EDGE) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_crit_max = pptable->TemperatureLimit[TEMP_HOTSPOT] * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->hotspot_emergency_max = (pptable->TemperatureLimit[TEMP_HOTSPOT] + CTF_OFFSET_HOTSPOT) * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_crit_max = pptable->TemperatureLimit[TEMP_MEM] * + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->mem_emergency_max = (pptable->TemperatureLimit[TEMP_MEM] + CTF_OFFSET_MEM)* + SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; + range->software_shutdown_temp = powerplay_table->software_shutdown_temp; + + return 0; +} + +static int sienna_cichlid_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_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0); + else + ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0); + + if(!ret) + smu->disable_uclk_switch = disable_memory_clock_switch; + + return ret; +} + +static int sienna_cichlid_get_power_limit(struct smu_context *smu) +{ + struct smu_11_0_7_powerplay_table *powerplay_table = + (struct smu_11_0_7_powerplay_table *)smu->smu_table.power_play_table; + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t power_limit, od_percent; + + if (smu_v11_0_get_current_power_limit(smu, &power_limit)) { + /* the last hope to figure out the ppt limit */ + if (!pptable) { + dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!"); + return -EINVAL; + } + power_limit = + pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0]; + } + smu->current_power_limit = power_limit; + + if (smu->od_enabled) { + od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_7_ODSETTING_POWERPERCENTAGE]); + + dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit); + + power_limit *= (100 + od_percent); + power_limit /= 100; + } + smu->max_power_limit = power_limit; + + return 0; +} + +static int sienna_cichlid_update_pcie_parameters(struct smu_context *smu, + uint32_t pcie_gen_cap, + uint32_t pcie_width_cap) +{ + struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context; + PPTable_t *pptable = smu->smu_table.driver_pptable; + uint32_t smu_pcie_arg; + int ret, i; + + /* lclk dpm table setup */ + for (i = 0; i < MAX_PCIE_CONF; i++) { + dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i]; + dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i]; + } + + 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_cmn_send_smc_msg_with_param(smu, + SMU_MSG_OverridePcieParameters, + smu_pcie_arg, + NULL); + + 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 int sienna_cichlid_get_dpm_ultimate_freq(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min, uint32_t *max) +{ + struct amdgpu_device *adev = smu->adev; + int ret; + + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, false); + ret = smu_v11_0_get_dpm_ultimate_freq(smu, clk_type, min, max); + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, true); + + return ret; +} + +static bool sienna_cichlid_is_baco_supported(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t val; + + if (amdgpu_sriov_vf(adev) || (!smu_v11_0_baco_is_support(smu))) + return false; + + val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); + return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false; +} + +static bool sienna_cichlid_is_mode1_reset_supported(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t val; + u32 smu_version; + + /** + * SRIOV env will not support SMU mode1 reset + * PM FW support mode1 reset from 58.26 + */ + smu_cmn_get_smc_version(smu, NULL, &smu_version); + if (amdgpu_sriov_vf(adev) || (smu_version < 0x003a1a00)) + return false; + + /** + * mode1 reset relies on PSP, so we should check if + * PSP is alive. + */ + val = RREG32_SOC15(MP0, 0, mmMP0_SMN_C2PMSG_81); + return val != 0x0; +} + +static void sienna_cichlid_dump_pptable(struct smu_context *smu) +{ + struct smu_table_context *table_context = &smu->smu_table; + PPTable_t *pptable = table_context->driver_pptable; + int i; + + dev_info(smu->adev->dev, "Dumped PPTable:\n"); + + dev_info(smu->adev->dev, "Version = 0x%08x\n", pptable->Version); + dev_info(smu->adev->dev, "FeaturesToRun[0] = 0x%08x\n", pptable->FeaturesToRun[0]); + dev_info(smu->adev->dev, "FeaturesToRun[1] = 0x%08x\n", pptable->FeaturesToRun[1]); + + for (i = 0; i < PPT_THROTTLER_COUNT; i++) { + dev_info(smu->adev->dev, "SocketPowerLimitAc[%d] = 0x%x\n", i, pptable->SocketPowerLimitAc[i]); + dev_info(smu->adev->dev, "SocketPowerLimitAcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitAcTau[i]); + dev_info(smu->adev->dev, "SocketPowerLimitDc[%d] = 0x%x\n", i, pptable->SocketPowerLimitDc[i]); + dev_info(smu->adev->dev, "SocketPowerLimitDcTau[%d] = 0x%x\n", i, pptable->SocketPowerLimitDcTau[i]); + } + + for (i = 0; i < TDC_THROTTLER_COUNT; i++) { + dev_info(smu->adev->dev, "TdcLimit[%d] = 0x%x\n", i, pptable->TdcLimit[i]); + dev_info(smu->adev->dev, "TdcLimitTau[%d] = 0x%x\n", i, pptable->TdcLimitTau[i]); + } + + for (i = 0; i < TEMP_COUNT; i++) { + dev_info(smu->adev->dev, "TemperatureLimit[%d] = 0x%x\n", i, pptable->TemperatureLimit[i]); + } + + dev_info(smu->adev->dev, "FitLimit = 0x%x\n", pptable->FitLimit); + dev_info(smu->adev->dev, "TotalPowerConfig = 0x%x\n", pptable->TotalPowerConfig); + dev_info(smu->adev->dev, "TotalPowerPadding[0] = 0x%x\n", pptable->TotalPowerPadding[0]); + dev_info(smu->adev->dev, "TotalPowerPadding[1] = 0x%x\n", pptable->TotalPowerPadding[1]); + dev_info(smu->adev->dev, "TotalPowerPadding[2] = 0x%x\n", pptable->TotalPowerPadding[2]); + + dev_info(smu->adev->dev, "ApccPlusResidencyLimit = 0x%x\n", pptable->ApccPlusResidencyLimit); + for (i = 0; i < NUM_SMNCLK_DPM_LEVELS; i++) { + dev_info(smu->adev->dev, "SmnclkDpmFreq[%d] = 0x%x\n", i, pptable->SmnclkDpmFreq[i]); + dev_info(smu->adev->dev, "SmnclkDpmVoltage[%d] = 0x%x\n", i, pptable->SmnclkDpmVoltage[i]); + } + dev_info(smu->adev->dev, "PaddingAPCC[0] = 0x%x\n", pptable->PaddingAPCC[0]); + dev_info(smu->adev->dev, "PaddingAPCC[1] = 0x%x\n", pptable->PaddingAPCC[1]); + dev_info(smu->adev->dev, "PaddingAPCC[2] = 0x%x\n", pptable->PaddingAPCC[2]); + dev_info(smu->adev->dev, "PaddingAPCC[3] = 0x%x\n", pptable->PaddingAPCC[3]); + + dev_info(smu->adev->dev, "ThrottlerControlMask = 0x%x\n", pptable->ThrottlerControlMask); + + dev_info(smu->adev->dev, "FwDStateMask = 0x%x\n", pptable->FwDStateMask); + + dev_info(smu->adev->dev, "UlvVoltageOffsetSoc = 0x%x\n", pptable->UlvVoltageOffsetSoc); + dev_info(smu->adev->dev, "UlvVoltageOffsetGfx = 0x%x\n", pptable->UlvVoltageOffsetGfx); + dev_info(smu->adev->dev, "MinVoltageUlvGfx = 0x%x\n", pptable->MinVoltageUlvGfx); + dev_info(smu->adev->dev, "MinVoltageUlvSoc = 0x%x\n", pptable->MinVoltageUlvSoc); + + dev_info(smu->adev->dev, "SocLIVmin = 0x%x\n", pptable->SocLIVmin); + dev_info(smu->adev->dev, "PaddingLIVmin = 0x%x\n", pptable->PaddingLIVmin); + + dev_info(smu->adev->dev, "GceaLinkMgrIdleThreshold = 0x%x\n", pptable->GceaLinkMgrIdleThreshold); + dev_info(smu->adev->dev, "paddingRlcUlvParams[0] = 0x%x\n", pptable->paddingRlcUlvParams[0]); + dev_info(smu->adev->dev, "paddingRlcUlvParams[1] = 0x%x\n", pptable->paddingRlcUlvParams[1]); + dev_info(smu->adev->dev, "paddingRlcUlvParams[2] = 0x%x\n", pptable->paddingRlcUlvParams[2]); + + dev_info(smu->adev->dev, "MinVoltageGfx = 0x%x\n", pptable->MinVoltageGfx); + dev_info(smu->adev->dev, "MinVoltageSoc = 0x%x\n", pptable->MinVoltageSoc); + dev_info(smu->adev->dev, "MaxVoltageGfx = 0x%x\n", pptable->MaxVoltageGfx); + dev_info(smu->adev->dev, "MaxVoltageSoc = 0x%x\n", pptable->MaxVoltageSoc); + + dev_info(smu->adev->dev, "LoadLineResistanceGfx = 0x%x\n", pptable->LoadLineResistanceGfx); + dev_info(smu->adev->dev, "LoadLineResistanceSoc = 0x%x\n", pptable->LoadLineResistanceSoc); + + dev_info(smu->adev->dev, "VDDGFX_TVmin = 0x%x\n", pptable->VDDGFX_TVmin); + dev_info(smu->adev->dev, "VDDSOC_TVmin = 0x%x\n", pptable->VDDSOC_TVmin); + dev_info(smu->adev->dev, "VDDGFX_Vmin_HiTemp = 0x%x\n", pptable->VDDGFX_Vmin_HiTemp); + dev_info(smu->adev->dev, "VDDGFX_Vmin_LoTemp = 0x%x\n", pptable->VDDGFX_Vmin_LoTemp); + dev_info(smu->adev->dev, "VDDSOC_Vmin_HiTemp = 0x%x\n", pptable->VDDSOC_Vmin_HiTemp); + dev_info(smu->adev->dev, "VDDSOC_Vmin_LoTemp = 0x%x\n", pptable->VDDSOC_Vmin_LoTemp); + dev_info(smu->adev->dev, "VDDGFX_TVminHystersis = 0x%x\n", pptable->VDDGFX_TVminHystersis); + dev_info(smu->adev->dev, "VDDSOC_TVminHystersis = 0x%x\n", pptable->VDDSOC_TVminHystersis); + + dev_info(smu->adev->dev, "[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); + + dev_info(smu->adev->dev, "[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); + + dev_info(smu->adev->dev, "[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); + + dev_info(smu->adev->dev, "[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); + + dev_info(smu->adev->dev, "[PPCLK_DCLK_0]\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_0].VoltageMode, + pptable->DpmDescriptor[PPCLK_DCLK_0].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_DCLK_0].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_DCLK_0].Padding, + pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_DCLK_0].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.a, + pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.b, + pptable->DpmDescriptor[PPCLK_DCLK_0].SsCurve.c, + pptable->DpmDescriptor[PPCLK_DCLK_0].SsFmin, + pptable->DpmDescriptor[PPCLK_DCLK_0].Padding16); + + dev_info(smu->adev->dev, "[PPCLK_VCLK_0]\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_0].VoltageMode, + pptable->DpmDescriptor[PPCLK_VCLK_0].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_VCLK_0].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_VCLK_0].Padding, + pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_VCLK_0].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.a, + pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.b, + pptable->DpmDescriptor[PPCLK_VCLK_0].SsCurve.c, + pptable->DpmDescriptor[PPCLK_VCLK_0].SsFmin, + pptable->DpmDescriptor[PPCLK_VCLK_0].Padding16); + + dev_info(smu->adev->dev, "[PPCLK_DCLK_1]\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_1].VoltageMode, + pptable->DpmDescriptor[PPCLK_DCLK_1].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_DCLK_1].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_DCLK_1].Padding, + pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_DCLK_1].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.a, + pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.b, + pptable->DpmDescriptor[PPCLK_DCLK_1].SsCurve.c, + pptable->DpmDescriptor[PPCLK_DCLK_1].SsFmin, + pptable->DpmDescriptor[PPCLK_DCLK_1].Padding16); + + dev_info(smu->adev->dev, "[PPCLK_VCLK_1]\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_1].VoltageMode, + pptable->DpmDescriptor[PPCLK_VCLK_1].SnapToDiscrete, + pptable->DpmDescriptor[PPCLK_VCLK_1].NumDiscreteLevels, + pptable->DpmDescriptor[PPCLK_VCLK_1].Padding, + pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.m, + pptable->DpmDescriptor[PPCLK_VCLK_1].ConversionToAvfsClk.b, + pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.a, + pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.b, + pptable->DpmDescriptor[PPCLK_VCLK_1].SsCurve.c, + pptable->DpmDescriptor[PPCLK_VCLK_1].SsFmin, + pptable->DpmDescriptor[PPCLK_VCLK_1].Padding16); + + dev_info(smu->adev->dev, "FreqTableGfx\n"); + for (i = 0; i < NUM_GFXCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableGfx[i]); + + dev_info(smu->adev->dev, "FreqTableVclk\n"); + for (i = 0; i < NUM_VCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableVclk[i]); + + dev_info(smu->adev->dev, "FreqTableDclk\n"); + for (i = 0; i < NUM_DCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableDclk[i]); + + dev_info(smu->adev->dev, "FreqTableSocclk\n"); + for (i = 0; i < NUM_SOCCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableSocclk[i]); + + dev_info(smu->adev->dev, "FreqTableUclk\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableUclk[i]); + + dev_info(smu->adev->dev, "FreqTableFclk\n"); + for (i = 0; i < NUM_FCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%02d] = 0x%x\n", i, pptable->FreqTableFclk[i]); + + dev_info(smu->adev->dev, "Paddingclks[0] = 0x%x\n", pptable->Paddingclks[0]); + dev_info(smu->adev->dev, "Paddingclks[1] = 0x%x\n", pptable->Paddingclks[1]); + dev_info(smu->adev->dev, "Paddingclks[2] = 0x%x\n", pptable->Paddingclks[2]); + dev_info(smu->adev->dev, "Paddingclks[3] = 0x%x\n", pptable->Paddingclks[3]); + dev_info(smu->adev->dev, "Paddingclks[4] = 0x%x\n", pptable->Paddingclks[4]); + dev_info(smu->adev->dev, "Paddingclks[5] = 0x%x\n", pptable->Paddingclks[5]); + dev_info(smu->adev->dev, "Paddingclks[6] = 0x%x\n", pptable->Paddingclks[6]); + dev_info(smu->adev->dev, "Paddingclks[7] = 0x%x\n", pptable->Paddingclks[7]); + dev_info(smu->adev->dev, "Paddingclks[8] = 0x%x\n", pptable->Paddingclks[8]); + dev_info(smu->adev->dev, "Paddingclks[9] = 0x%x\n", pptable->Paddingclks[9]); + dev_info(smu->adev->dev, "Paddingclks[10] = 0x%x\n", pptable->Paddingclks[10]); + dev_info(smu->adev->dev, "Paddingclks[11] = 0x%x\n", pptable->Paddingclks[11]); + dev_info(smu->adev->dev, "Paddingclks[12] = 0x%x\n", pptable->Paddingclks[12]); + dev_info(smu->adev->dev, "Paddingclks[13] = 0x%x\n", pptable->Paddingclks[13]); + dev_info(smu->adev->dev, "Paddingclks[14] = 0x%x\n", pptable->Paddingclks[14]); + dev_info(smu->adev->dev, "Paddingclks[15] = 0x%x\n", pptable->Paddingclks[15]); + + dev_info(smu->adev->dev, "DcModeMaxFreq\n"); + dev_info(smu->adev->dev, " .PPCLK_GFXCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_GFXCLK]); + dev_info(smu->adev->dev, " .PPCLK_SOCCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_SOCCLK]); + dev_info(smu->adev->dev, " .PPCLK_UCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_UCLK]); + dev_info(smu->adev->dev, " .PPCLK_FCLK = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_FCLK]); + dev_info(smu->adev->dev, " .PPCLK_DCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_0]); + dev_info(smu->adev->dev, " .PPCLK_VCLK_0 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_0]); + dev_info(smu->adev->dev, " .PPCLK_DCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_DCLK_1]); + dev_info(smu->adev->dev, " .PPCLK_VCLK_1 = 0x%x\n", pptable->DcModeMaxFreq[PPCLK_VCLK_1]); + + dev_info(smu->adev->dev, "FreqTableUclkDiv\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FreqTableUclkDiv[i]); + + dev_info(smu->adev->dev, "FclkBoostFreq = 0x%x\n", pptable->FclkBoostFreq); + dev_info(smu->adev->dev, "FclkParamPadding = 0x%x\n", pptable->FclkParamPadding); + + dev_info(smu->adev->dev, "Mp0clkFreq\n"); + for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0clkFreq[i]); + + dev_info(smu->adev->dev, "Mp0DpmVoltage\n"); + for (i = 0; i < NUM_MP0CLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->Mp0DpmVoltage[i]); + + dev_info(smu->adev->dev, "MemVddciVoltage\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemVddciVoltage[i]); + + dev_info(smu->adev->dev, "MemMvddVoltage\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->MemMvddVoltage[i]); + + dev_info(smu->adev->dev, "GfxclkFgfxoffEntry = 0x%x\n", pptable->GfxclkFgfxoffEntry); + dev_info(smu->adev->dev, "GfxclkFinit = 0x%x\n", pptable->GfxclkFinit); + dev_info(smu->adev->dev, "GfxclkFidle = 0x%x\n", pptable->GfxclkFidle); + dev_info(smu->adev->dev, "GfxclkSource = 0x%x\n", pptable->GfxclkSource); + dev_info(smu->adev->dev, "GfxclkPadding = 0x%x\n", pptable->GfxclkPadding); + + dev_info(smu->adev->dev, "GfxGpoSubFeatureMask = 0x%x\n", pptable->GfxGpoSubFeatureMask); + + dev_info(smu->adev->dev, "GfxGpoEnabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoEnabledWorkPolicyMask); + dev_info(smu->adev->dev, "GfxGpoDisabledWorkPolicyMask = 0x%x\n", pptable->GfxGpoDisabledWorkPolicyMask); + dev_info(smu->adev->dev, "GfxGpoPadding[0] = 0x%x\n", pptable->GfxGpoPadding[0]); + dev_info(smu->adev->dev, "GfxGpoVotingAllow = 0x%x\n", pptable->GfxGpoVotingAllow); + dev_info(smu->adev->dev, "GfxGpoPadding32[0] = 0x%x\n", pptable->GfxGpoPadding32[0]); + dev_info(smu->adev->dev, "GfxGpoPadding32[1] = 0x%x\n", pptable->GfxGpoPadding32[1]); + dev_info(smu->adev->dev, "GfxGpoPadding32[2] = 0x%x\n", pptable->GfxGpoPadding32[2]); + dev_info(smu->adev->dev, "GfxGpoPadding32[3] = 0x%x\n", pptable->GfxGpoPadding32[3]); + dev_info(smu->adev->dev, "GfxDcsFopt = 0x%x\n", pptable->GfxDcsFopt); + dev_info(smu->adev->dev, "GfxDcsFclkFopt = 0x%x\n", pptable->GfxDcsFclkFopt); + dev_info(smu->adev->dev, "GfxDcsUclkFopt = 0x%x\n", pptable->GfxDcsUclkFopt); + + dev_info(smu->adev->dev, "DcsGfxOffVoltage = 0x%x\n", pptable->DcsGfxOffVoltage); + dev_info(smu->adev->dev, "DcsMinGfxOffTime = 0x%x\n", pptable->DcsMinGfxOffTime); + dev_info(smu->adev->dev, "DcsMaxGfxOffTime = 0x%x\n", pptable->DcsMaxGfxOffTime); + dev_info(smu->adev->dev, "DcsMinCreditAccum = 0x%x\n", pptable->DcsMinCreditAccum); + dev_info(smu->adev->dev, "DcsExitHysteresis = 0x%x\n", pptable->DcsExitHysteresis); + dev_info(smu->adev->dev, "DcsTimeout = 0x%x\n", pptable->DcsTimeout); + + dev_info(smu->adev->dev, "DcsParamPadding[0] = 0x%x\n", pptable->DcsParamPadding[0]); + dev_info(smu->adev->dev, "DcsParamPadding[1] = 0x%x\n", pptable->DcsParamPadding[1]); + dev_info(smu->adev->dev, "DcsParamPadding[2] = 0x%x\n", pptable->DcsParamPadding[2]); + dev_info(smu->adev->dev, "DcsParamPadding[3] = 0x%x\n", pptable->DcsParamPadding[3]); + dev_info(smu->adev->dev, "DcsParamPadding[4] = 0x%x\n", pptable->DcsParamPadding[4]); + + dev_info(smu->adev->dev, "FlopsPerByteTable\n"); + for (i = 0; i < RLC_PACE_TABLE_NUM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FlopsPerByteTable[i]); + + dev_info(smu->adev->dev, "LowestUclkReservedForUlv = 0x%x\n", pptable->LowestUclkReservedForUlv); + dev_info(smu->adev->dev, "vddingMem[0] = 0x%x\n", pptable->PaddingMem[0]); + dev_info(smu->adev->dev, "vddingMem[1] = 0x%x\n", pptable->PaddingMem[1]); + dev_info(smu->adev->dev, "vddingMem[2] = 0x%x\n", pptable->PaddingMem[2]); + + dev_info(smu->adev->dev, "UclkDpmPstates\n"); + for (i = 0; i < NUM_UCLK_DPM_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->UclkDpmPstates[i]); + + dev_info(smu->adev->dev, "UclkDpmSrcFreqRange\n"); + dev_info(smu->adev->dev, " .Fmin = 0x%x\n", + pptable->UclkDpmSrcFreqRange.Fmin); + dev_info(smu->adev->dev, " .Fmax = 0x%x\n", + pptable->UclkDpmSrcFreqRange.Fmax); + dev_info(smu->adev->dev, "UclkDpmTargFreqRange\n"); + dev_info(smu->adev->dev, " .Fmin = 0x%x\n", + pptable->UclkDpmTargFreqRange.Fmin); + dev_info(smu->adev->dev, " .Fmax = 0x%x\n", + pptable->UclkDpmTargFreqRange.Fmax); + dev_info(smu->adev->dev, "UclkDpmMidstepFreq = 0x%x\n", pptable->UclkDpmMidstepFreq); + dev_info(smu->adev->dev, "UclkMidstepPadding = 0x%x\n", pptable->UclkMidstepPadding); + + dev_info(smu->adev->dev, "PcieGenSpeed\n"); + for (i = 0; i < NUM_LINK_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieGenSpeed[i]); + + dev_info(smu->adev->dev, "PcieLaneCount\n"); + for (i = 0; i < NUM_LINK_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->PcieLaneCount[i]); + + dev_info(smu->adev->dev, "LclkFreq\n"); + for (i = 0; i < NUM_LINK_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->LclkFreq[i]); + + dev_info(smu->adev->dev, "FanStopTemp = 0x%x\n", pptable->FanStopTemp); + dev_info(smu->adev->dev, "FanStartTemp = 0x%x\n", pptable->FanStartTemp); + + dev_info(smu->adev->dev, "FanGain\n"); + for (i = 0; i < TEMP_COUNT; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->FanGain[i]); + + dev_info(smu->adev->dev, "FanPwmMin = 0x%x\n", pptable->FanPwmMin); + dev_info(smu->adev->dev, "FanAcousticLimitRpm = 0x%x\n", pptable->FanAcousticLimitRpm); + dev_info(smu->adev->dev, "FanThrottlingRpm = 0x%x\n", pptable->FanThrottlingRpm); + dev_info(smu->adev->dev, "FanMaximumRpm = 0x%x\n", pptable->FanMaximumRpm); + dev_info(smu->adev->dev, "MGpuFanBoostLimitRpm = 0x%x\n", pptable->MGpuFanBoostLimitRpm); + dev_info(smu->adev->dev, "FanTargetTemperature = 0x%x\n", pptable->FanTargetTemperature); + dev_info(smu->adev->dev, "FanTargetGfxclk = 0x%x\n", pptable->FanTargetGfxclk); + dev_info(smu->adev->dev, "FanPadding16 = 0x%x\n", pptable->FanPadding16); + dev_info(smu->adev->dev, "FanTempInputSelect = 0x%x\n", pptable->FanTempInputSelect); + dev_info(smu->adev->dev, "FanPadding = 0x%x\n", pptable->FanPadding); + dev_info(smu->adev->dev, "FanZeroRpmEnable = 0x%x\n", pptable->FanZeroRpmEnable); + dev_info(smu->adev->dev, "FanTachEdgePerRev = 0x%x\n", pptable->FanTachEdgePerRev); + + dev_info(smu->adev->dev, "FuzzyFan_ErrorSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_ErrorRateSetDelta = 0x%x\n", pptable->FuzzyFan_ErrorRateSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_PwmSetDelta = 0x%x\n", pptable->FuzzyFan_PwmSetDelta); + dev_info(smu->adev->dev, "FuzzyFan_Reserved = 0x%x\n", pptable->FuzzyFan_Reserved); + + dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "OverrideAvfsGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->OverrideAvfsGb[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "dBtcGbGfxDfllModelSelect = 0x%x\n", pptable->dBtcGbGfxDfllModelSelect); + dev_info(smu->adev->dev, "Padding8_Avfs = 0x%x\n", pptable->Padding8_Avfs); + + dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_GFX]{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->qAvfsGb[AVFS_VOLTAGE_GFX].a, + pptable->qAvfsGb[AVFS_VOLTAGE_GFX].b, + pptable->qAvfsGb[AVFS_VOLTAGE_GFX].c); + dev_info(smu->adev->dev, "qAvfsGb[AVFS_VOLTAGE_SOC]{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->qAvfsGb[AVFS_VOLTAGE_SOC].a, + pptable->qAvfsGb[AVFS_VOLTAGE_SOC].b, + pptable->qAvfsGb[AVFS_VOLTAGE_SOC].c); + dev_info(smu->adev->dev, "dBtcGbGfxPll{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbGfxPll.a, + pptable->dBtcGbGfxPll.b, + pptable->dBtcGbGfxPll.c); + dev_info(smu->adev->dev, "dBtcGbGfxAfll{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbGfxDfll.a, + pptable->dBtcGbGfxDfll.b, + pptable->dBtcGbGfxDfll.c); + dev_info(smu->adev->dev, "dBtcGbSoc{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->dBtcGbSoc.a, + pptable->dBtcGbSoc.b, + pptable->dBtcGbSoc.c); + dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_GFX]{m = 0x%x b = 0x%x}\n", + pptable->qAgingGb[AVFS_VOLTAGE_GFX].m, + pptable->qAgingGb[AVFS_VOLTAGE_GFX].b); + dev_info(smu->adev->dev, "qAgingGb[AVFS_VOLTAGE_SOC]{m = 0x%x b = 0x%x}\n", + pptable->qAgingGb[AVFS_VOLTAGE_SOC].m, + pptable->qAgingGb[AVFS_VOLTAGE_SOC].b); + + dev_info(smu->adev->dev, "PiecewiseLinearDroopIntGfxDfll\n"); + for (i = 0; i < NUM_PIECE_WISE_LINEAR_DROOP_MODEL_VF_POINTS; i++) { + dev_info(smu->adev->dev, " Fset[%d] = 0x%x\n", + i, pptable->PiecewiseLinearDroopIntGfxDfll.Fset[i]); + dev_info(smu->adev->dev, " Vdroop[%d] = 0x%x\n", + i, pptable->PiecewiseLinearDroopIntGfxDfll.Vdroop[i]); + } + + dev_info(smu->adev->dev, "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); + dev_info(smu->adev->dev, "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); + + dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcTol[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcTol[AVFS_VOLTAGE_SOC]); + + dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcEnabled[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcEnabled[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "Padding8_GfxBtc[0] = 0x%x\n", pptable->Padding8_GfxBtc[0]); + dev_info(smu->adev->dev, "Padding8_GfxBtc[1] = 0x%x\n", pptable->Padding8_GfxBtc[1]); + + dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcMin[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMin[AVFS_VOLTAGE_SOC]); + dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcMax[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcMax[AVFS_VOLTAGE_SOC]); + + dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_GFX] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_GFX]); + dev_info(smu->adev->dev, "DcBtcGb[AVFS_VOLTAGE_SOC] = 0x%x\n", pptable->DcBtcGb[AVFS_VOLTAGE_SOC]); + + dev_info(smu->adev->dev, "XgmiDpmPstates\n"); + for (i = 0; i < NUM_XGMI_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiDpmPstates[i]); + dev_info(smu->adev->dev, "XgmiDpmSpare[0] = 0x%02x\n", pptable->XgmiDpmSpare[0]); + dev_info(smu->adev->dev, "XgmiDpmSpare[1] = 0x%02x\n", pptable->XgmiDpmSpare[1]); + + dev_info(smu->adev->dev, "DebugOverrides = 0x%x\n", pptable->DebugOverrides); + dev_info(smu->adev->dev, "ReservedEquation0{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation0.a, + pptable->ReservedEquation0.b, + pptable->ReservedEquation0.c); + dev_info(smu->adev->dev, "ReservedEquation1{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation1.a, + pptable->ReservedEquation1.b, + pptable->ReservedEquation1.c); + dev_info(smu->adev->dev, "ReservedEquation2{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation2.a, + pptable->ReservedEquation2.b, + pptable->ReservedEquation2.c); + dev_info(smu->adev->dev, "ReservedEquation3{a = 0x%x b = 0x%x c = 0x%x}\n", + pptable->ReservedEquation3.a, + pptable->ReservedEquation3.b, + pptable->ReservedEquation3.c); + + dev_info(smu->adev->dev, "SkuReserved[0] = 0x%x\n", pptable->SkuReserved[0]); + dev_info(smu->adev->dev, "SkuReserved[1] = 0x%x\n", pptable->SkuReserved[1]); + dev_info(smu->adev->dev, "SkuReserved[2] = 0x%x\n", pptable->SkuReserved[2]); + dev_info(smu->adev->dev, "SkuReserved[3] = 0x%x\n", pptable->SkuReserved[3]); + dev_info(smu->adev->dev, "SkuReserved[4] = 0x%x\n", pptable->SkuReserved[4]); + dev_info(smu->adev->dev, "SkuReserved[5] = 0x%x\n", pptable->SkuReserved[5]); + dev_info(smu->adev->dev, "SkuReserved[6] = 0x%x\n", pptable->SkuReserved[6]); + dev_info(smu->adev->dev, "SkuReserved[7] = 0x%x\n", pptable->SkuReserved[7]); + dev_info(smu->adev->dev, "SkuReserved[8] = 0x%x\n", pptable->SkuReserved[8]); + dev_info(smu->adev->dev, "SkuReserved[9] = 0x%x\n", pptable->SkuReserved[9]); + dev_info(smu->adev->dev, "SkuReserved[10] = 0x%x\n", pptable->SkuReserved[10]); + dev_info(smu->adev->dev, "SkuReserved[11] = 0x%x\n", pptable->SkuReserved[11]); + dev_info(smu->adev->dev, "SkuReserved[12] = 0x%x\n", pptable->SkuReserved[12]); + dev_info(smu->adev->dev, "SkuReserved[13] = 0x%x\n", pptable->SkuReserved[13]); + + dev_info(smu->adev->dev, "GamingClk[0] = 0x%x\n", pptable->GamingClk[0]); + dev_info(smu->adev->dev, "GamingClk[1] = 0x%x\n", pptable->GamingClk[1]); + dev_info(smu->adev->dev, "GamingClk[2] = 0x%x\n", pptable->GamingClk[2]); + dev_info(smu->adev->dev, "GamingClk[3] = 0x%x\n", pptable->GamingClk[3]); + dev_info(smu->adev->dev, "GamingClk[4] = 0x%x\n", pptable->GamingClk[4]); + dev_info(smu->adev->dev, "GamingClk[5] = 0x%x\n", pptable->GamingClk[5]); + + for (i = 0; i < NUM_I2C_CONTROLLERS; i++) { + dev_info(smu->adev->dev, "I2cControllers[%d]:\n", i); + dev_info(smu->adev->dev, " .Enabled = 0x%x\n", + pptable->I2cControllers[i].Enabled); + dev_info(smu->adev->dev, " .Speed = 0x%x\n", + pptable->I2cControllers[i].Speed); + dev_info(smu->adev->dev, " .SlaveAddress = 0x%x\n", + pptable->I2cControllers[i].SlaveAddress); + dev_info(smu->adev->dev, " .ControllerPort = 0x%x\n", + pptable->I2cControllers[i].ControllerPort); + dev_info(smu->adev->dev, " .ControllerName = 0x%x\n", + pptable->I2cControllers[i].ControllerName); + dev_info(smu->adev->dev, " .ThermalThrottler = 0x%x\n", + pptable->I2cControllers[i].ThermalThrotter); + dev_info(smu->adev->dev, " .I2cProtocol = 0x%x\n", + pptable->I2cControllers[i].I2cProtocol); + dev_info(smu->adev->dev, " .PaddingConfig = 0x%x\n", + pptable->I2cControllers[i].PaddingConfig); + } + + dev_info(smu->adev->dev, "GpioScl = 0x%x\n", pptable->GpioScl); + dev_info(smu->adev->dev, "GpioSda = 0x%x\n", pptable->GpioSda); + dev_info(smu->adev->dev, "FchUsbPdSlaveAddr = 0x%x\n", pptable->FchUsbPdSlaveAddr); + dev_info(smu->adev->dev, "I2cSpare[0] = 0x%x\n", pptable->I2cSpare[0]); + + dev_info(smu->adev->dev, "Board Parameters:\n"); + dev_info(smu->adev->dev, "VddGfxVrMapping = 0x%x\n", pptable->VddGfxVrMapping); + dev_info(smu->adev->dev, "VddSocVrMapping = 0x%x\n", pptable->VddSocVrMapping); + dev_info(smu->adev->dev, "VddMem0VrMapping = 0x%x\n", pptable->VddMem0VrMapping); + dev_info(smu->adev->dev, "VddMem1VrMapping = 0x%x\n", pptable->VddMem1VrMapping); + dev_info(smu->adev->dev, "GfxUlvPhaseSheddingMask = 0x%x\n", pptable->GfxUlvPhaseSheddingMask); + dev_info(smu->adev->dev, "SocUlvPhaseSheddingMask = 0x%x\n", pptable->SocUlvPhaseSheddingMask); + dev_info(smu->adev->dev, "VddciUlvPhaseSheddingMask = 0x%x\n", pptable->VddciUlvPhaseSheddingMask); + dev_info(smu->adev->dev, "MvddUlvPhaseSheddingMask = 0x%x\n", pptable->MvddUlvPhaseSheddingMask); + + dev_info(smu->adev->dev, "GfxMaxCurrent = 0x%x\n", pptable->GfxMaxCurrent); + dev_info(smu->adev->dev, "GfxOffset = 0x%x\n", pptable->GfxOffset); + dev_info(smu->adev->dev, "Padding_TelemetryGfx = 0x%x\n", pptable->Padding_TelemetryGfx); + + dev_info(smu->adev->dev, "SocMaxCurrent = 0x%x\n", pptable->SocMaxCurrent); + dev_info(smu->adev->dev, "SocOffset = 0x%x\n", pptable->SocOffset); + dev_info(smu->adev->dev, "Padding_TelemetrySoc = 0x%x\n", pptable->Padding_TelemetrySoc); + + dev_info(smu->adev->dev, "Mem0MaxCurrent = 0x%x\n", pptable->Mem0MaxCurrent); + dev_info(smu->adev->dev, "Mem0Offset = 0x%x\n", pptable->Mem0Offset); + dev_info(smu->adev->dev, "Padding_TelemetryMem0 = 0x%x\n", pptable->Padding_TelemetryMem0); + + dev_info(smu->adev->dev, "Mem1MaxCurrent = 0x%x\n", pptable->Mem1MaxCurrent); + dev_info(smu->adev->dev, "Mem1Offset = 0x%x\n", pptable->Mem1Offset); + dev_info(smu->adev->dev, "Padding_TelemetryMem1 = 0x%x\n", pptable->Padding_TelemetryMem1); + + dev_info(smu->adev->dev, "MvddRatio = 0x%x\n", pptable->MvddRatio); + + dev_info(smu->adev->dev, "AcDcGpio = 0x%x\n", pptable->AcDcGpio); + dev_info(smu->adev->dev, "AcDcPolarity = 0x%x\n", pptable->AcDcPolarity); + dev_info(smu->adev->dev, "VR0HotGpio = 0x%x\n", pptable->VR0HotGpio); + dev_info(smu->adev->dev, "VR0HotPolarity = 0x%x\n", pptable->VR0HotPolarity); + dev_info(smu->adev->dev, "VR1HotGpio = 0x%x\n", pptable->VR1HotGpio); + dev_info(smu->adev->dev, "VR1HotPolarity = 0x%x\n", pptable->VR1HotPolarity); + dev_info(smu->adev->dev, "GthrGpio = 0x%x\n", pptable->GthrGpio); + dev_info(smu->adev->dev, "GthrPolarity = 0x%x\n", pptable->GthrPolarity); + dev_info(smu->adev->dev, "LedPin0 = 0x%x\n", pptable->LedPin0); + dev_info(smu->adev->dev, "LedPin1 = 0x%x\n", pptable->LedPin1); + dev_info(smu->adev->dev, "LedPin2 = 0x%x\n", pptable->LedPin2); + dev_info(smu->adev->dev, "LedEnableMask = 0x%x\n", pptable->LedEnableMask); + dev_info(smu->adev->dev, "LedPcie = 0x%x\n", pptable->LedPcie); + dev_info(smu->adev->dev, "LedError = 0x%x\n", pptable->LedError); + dev_info(smu->adev->dev, "LedSpare1[0] = 0x%x\n", pptable->LedSpare1[0]); + dev_info(smu->adev->dev, "LedSpare1[1] = 0x%x\n", pptable->LedSpare1[1]); + + dev_info(smu->adev->dev, "PllGfxclkSpreadEnabled = 0x%x\n", pptable->PllGfxclkSpreadEnabled); + dev_info(smu->adev->dev, "PllGfxclkSpreadPercent = 0x%x\n", pptable->PllGfxclkSpreadPercent); + dev_info(smu->adev->dev, "PllGfxclkSpreadFreq = 0x%x\n", pptable->PllGfxclkSpreadFreq); + + dev_info(smu->adev->dev, "DfllGfxclkSpreadEnabled = 0x%x\n", pptable->DfllGfxclkSpreadEnabled); + dev_info(smu->adev->dev, "DfllGfxclkSpreadPercent = 0x%x\n", pptable->DfllGfxclkSpreadPercent); + dev_info(smu->adev->dev, "DfllGfxclkSpreadFreq = 0x%x\n", pptable->DfllGfxclkSpreadFreq); + + dev_info(smu->adev->dev, "UclkSpreadPadding = 0x%x\n", pptable->UclkSpreadPadding); + dev_info(smu->adev->dev, "UclkSpreadFreq = 0x%x\n", pptable->UclkSpreadFreq); + + dev_info(smu->adev->dev, "FclkSpreadEnabled = 0x%x\n", pptable->FclkSpreadEnabled); + dev_info(smu->adev->dev, "FclkSpreadPercent = 0x%x\n", pptable->FclkSpreadPercent); + dev_info(smu->adev->dev, "FclkSpreadFreq = 0x%x\n", pptable->FclkSpreadFreq); + + dev_info(smu->adev->dev, "MemoryChannelEnabled = 0x%x\n", pptable->MemoryChannelEnabled); + dev_info(smu->adev->dev, "DramBitWidth = 0x%x\n", pptable->DramBitWidth); + dev_info(smu->adev->dev, "PaddingMem1[0] = 0x%x\n", pptable->PaddingMem1[0]); + dev_info(smu->adev->dev, "PaddingMem1[1] = 0x%x\n", pptable->PaddingMem1[1]); + dev_info(smu->adev->dev, "PaddingMem1[2] = 0x%x\n", pptable->PaddingMem1[2]); + + dev_info(smu->adev->dev, "TotalBoardPower = 0x%x\n", pptable->TotalBoardPower); + dev_info(smu->adev->dev, "BoardPowerPadding = 0x%x\n", pptable->BoardPowerPadding); + + dev_info(smu->adev->dev, "XgmiLinkSpeed\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkSpeed[i]); + dev_info(smu->adev->dev, "XgmiLinkWidth\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiLinkWidth[i]); + dev_info(smu->adev->dev, "XgmiFclkFreq\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiFclkFreq[i]); + dev_info(smu->adev->dev, "XgmiSocVoltage\n"); + for (i = 0; i < NUM_XGMI_PSTATE_LEVELS; i++) + dev_info(smu->adev->dev, " .[%d] = 0x%x\n", i, pptable->XgmiSocVoltage[i]); + + dev_info(smu->adev->dev, "HsrEnabled = 0x%x\n", pptable->HsrEnabled); + dev_info(smu->adev->dev, "VddqOffEnabled = 0x%x\n", pptable->VddqOffEnabled); + dev_info(smu->adev->dev, "PaddingUmcFlags[0] = 0x%x\n", pptable->PaddingUmcFlags[0]); + dev_info(smu->adev->dev, "PaddingUmcFlags[1] = 0x%x\n", pptable->PaddingUmcFlags[1]); + + dev_info(smu->adev->dev, "BoardReserved[0] = 0x%x\n", pptable->BoardReserved[0]); + dev_info(smu->adev->dev, "BoardReserved[1] = 0x%x\n", pptable->BoardReserved[1]); + dev_info(smu->adev->dev, "BoardReserved[2] = 0x%x\n", pptable->BoardReserved[2]); + dev_info(smu->adev->dev, "BoardReserved[3] = 0x%x\n", pptable->BoardReserved[3]); + dev_info(smu->adev->dev, "BoardReserved[4] = 0x%x\n", pptable->BoardReserved[4]); + dev_info(smu->adev->dev, "BoardReserved[5] = 0x%x\n", pptable->BoardReserved[5]); + dev_info(smu->adev->dev, "BoardReserved[6] = 0x%x\n", pptable->BoardReserved[6]); + dev_info(smu->adev->dev, "BoardReserved[7] = 0x%x\n", pptable->BoardReserved[7]); + dev_info(smu->adev->dev, "BoardReserved[8] = 0x%x\n", pptable->BoardReserved[8]); + dev_info(smu->adev->dev, "BoardReserved[9] = 0x%x\n", pptable->BoardReserved[9]); + dev_info(smu->adev->dev, "BoardReserved[10] = 0x%x\n", pptable->BoardReserved[10]); + + dev_info(smu->adev->dev, "MmHubPadding[0] = 0x%x\n", pptable->MmHubPadding[0]); + dev_info(smu->adev->dev, "MmHubPadding[1] = 0x%x\n", pptable->MmHubPadding[1]); + dev_info(smu->adev->dev, "MmHubPadding[2] = 0x%x\n", pptable->MmHubPadding[2]); + dev_info(smu->adev->dev, "MmHubPadding[3] = 0x%x\n", pptable->MmHubPadding[3]); + dev_info(smu->adev->dev, "MmHubPadding[4] = 0x%x\n", pptable->MmHubPadding[4]); + dev_info(smu->adev->dev, "MmHubPadding[5] = 0x%x\n", pptable->MmHubPadding[5]); + dev_info(smu->adev->dev, "MmHubPadding[6] = 0x%x\n", pptable->MmHubPadding[6]); + dev_info(smu->adev->dev, "MmHubPadding[7] = 0x%x\n", pptable->MmHubPadding[7]); +} + +static void sienna_cichlid_fill_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->CmdConfig = CMDCONFIG_READWRITE_MASK; + else + cmd->CmdConfig = write ? CMDCONFIG_READWRITE_MASK : 0; + + + /* 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->ReadWriteData = data[i]; + } +} + +static int sienna_cichlid_i2c_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)); + sienna_cichlid_fill_i2c_req(&req, false, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + /* Now read data starting with that address */ + ret = smu_cmn_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].ReadWriteData; + + dev_dbg(adev->dev, "sienna_cichlid_i2c_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 + dev_err(adev->dev, "sienna_cichlid_i2c_read_data - error occurred :%x", ret); + + return ret; +} + +static int sienna_cichlid_i2c_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)); + sienna_cichlid_fill_i2c_req(&req, true, address, numbytes, data); + + mutex_lock(&adev->smu.mutex); + ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true); + mutex_unlock(&adev->smu.mutex); + + if (!ret) { + dev_dbg(adev->dev, "sienna_cichlid_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 + dev_err(adev->dev, "sienna_cichlid_i2c_write- error occurred :%x", ret); + + return ret; +} + +static int sienna_cichlid_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 = sienna_cichlid_i2c_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 = sienna_cichlid_i2c_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 = sienna_cichlid_i2c_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 = sienna_cichlid_i2c_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 sienna_cichlid_i2c_func(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL; +} + + +static const struct i2c_algorithm sienna_cichlid_i2c_algo = { + .master_xfer = sienna_cichlid_i2c_xfer, + .functionality = sienna_cichlid_i2c_func, +}; + +static int sienna_cichlid_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control) +{ + struct amdgpu_device *adev = to_amdgpu_device(control); + int res; + + control->owner = THIS_MODULE; + control->class = I2C_CLASS_SPD; + control->dev.parent = &adev->pdev->dev; + control->algo = &sienna_cichlid_i2c_algo; + snprintf(control->name, sizeof(control->name), "AMDGPU SMU"); + + res = i2c_add_adapter(control); + if (res) + DRM_ERROR("Failed to register hw i2c, err: %d\n", res); + + return res; +} + +static void sienna_cichlid_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control) +{ + i2c_del_adapter(control); +} + + +static const struct pptable_funcs sienna_cichlid_ppt_funcs = { + .get_allowed_feature_mask = sienna_cichlid_get_allowed_feature_mask, + .set_default_dpm_table = sienna_cichlid_set_default_dpm_table, + .dpm_set_vcn_enable = sienna_cichlid_dpm_set_vcn_enable, + .dpm_set_jpeg_enable = sienna_cichlid_dpm_set_jpeg_enable, + .i2c_init = sienna_cichlid_i2c_control_init, + .i2c_fini = sienna_cichlid_i2c_control_fini, + .print_clk_levels = sienna_cichlid_print_clk_levels, + .force_clk_levels = sienna_cichlid_force_clk_levels, + .populate_umd_state_clk = sienna_cichlid_populate_umd_state_clk, + .pre_display_config_changed = sienna_cichlid_pre_display_config_changed, + .display_config_changed = sienna_cichlid_display_config_changed, + .notify_smc_display_config = sienna_cichlid_notify_smc_display_config, + .is_dpm_running = sienna_cichlid_is_dpm_running, + .get_fan_speed_percent = sienna_cichlid_get_fan_speed_percent, + .get_fan_speed_rpm = sienna_cichlid_get_fan_speed_rpm, + .get_power_profile_mode = sienna_cichlid_get_power_profile_mode, + .set_power_profile_mode = sienna_cichlid_set_power_profile_mode, + .set_watermarks_table = sienna_cichlid_set_watermarks_table, + .read_sensor = sienna_cichlid_read_sensor, + .get_uclk_dpm_states = sienna_cichlid_get_uclk_dpm_states, + .set_performance_level = smu_v11_0_set_performance_level, + .get_thermal_temperature_range = sienna_cichlid_get_thermal_temperature_range, + .display_disable_memory_clock_switch = sienna_cichlid_display_disable_memory_clock_switch, + .get_power_limit = sienna_cichlid_get_power_limit, + .update_pcie_parameters = sienna_cichlid_update_pcie_parameters, + .dump_pptable = sienna_cichlid_dump_pptable, + .init_microcode = smu_v11_0_init_microcode, + .load_microcode = smu_v11_0_load_microcode, + .init_smc_tables = sienna_cichlid_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 = sienna_cichlid_setup_pptable, + .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values, + .check_fw_version = smu_v11_0_check_fw_version, + .write_pptable = smu_cmn_write_pptable, + .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_cmn_send_smc_msg_with_param, + .send_smc_msg = smu_cmn_send_smc_msg, + .init_display_count = NULL, + .set_allowed_mask = smu_v11_0_set_allowed_mask, + .get_enabled_mask = smu_cmn_get_enabled_mask, + .feature_is_enabled = smu_cmn_feature_is_enabled, + .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception, + .notify_display_change = NULL, + .set_power_limit = smu_v11_0_set_power_limit, + .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks, + .enable_thermal_alert = smu_v11_0_enable_thermal_alert, + .disable_thermal_alert = smu_v11_0_disable_thermal_alert, + .set_min_dcef_deep_sleep = NULL, + .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= sienna_cichlid_is_baco_supported, + .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, + .mode1_reset_is_support = sienna_cichlid_is_mode1_reset_supported, + .mode1_reset = smu_v11_0_mode1_reset, + .get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq, + .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range, + .get_pp_feature_mask = smu_cmn_get_pp_feature_mask, + .set_pp_feature_mask = smu_cmn_set_pp_feature_mask, +}; + +void sienna_cichlid_set_ppt_funcs(struct smu_context *smu) +{ + smu->ppt_funcs = &sienna_cichlid_ppt_funcs; + smu->message_map = sienna_cichlid_message_map; + smu->clock_map = sienna_cichlid_clk_map; + smu->feature_map = sienna_cichlid_feature_mask_map; + smu->table_map = sienna_cichlid_table_map; + smu->pwr_src_map = sienna_cichlid_pwr_src_map; + smu->workload_map = sienna_cichlid_workload_map; +} diff --git a/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.h b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.h new file mode 100644 index 000000000000..8078886e4cbc --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/sienna_cichlid_ppt.h @@ -0,0 +1,37 @@ +/* + * 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 __SIENNA_CICHLID_PPT_H__ +#define __SIENNA_CICHLID_PPT_H__ + +typedef enum { + POWER_SOURCE_AC, + POWER_SOURCE_DC, + POWER_SOURCE_COUNT, +} POWER_SOURCE_e; + +extern void sienna_cichlid_set_ppt_funcs(struct smu_context *smu); + +#define smnPCIE_LC_SPEED_CNTL 0x11140290 +#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 + +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_cmn.c b/drivers/gpu/drm/amd/powerplay/smu_cmn.c new file mode 100644 index 000000000000..5c23c44c33bd --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smu_cmn.c @@ -0,0 +1,633 @@ +/* + * Copyright 2020 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. + */ + +#define SWSMU_CODE_LAYER_L4 + +#include "amdgpu.h" +#include "amdgpu_smu.h" +#include "smu_cmn.h" +#include "soc15_common.h" + +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + +/* + * Although these are defined in each ASIC's specific header file. + * They share the same definitions and values. That makes common + * APIs for SMC messages issuing for all ASICs possible. + */ +#define mmMP1_SMN_C2PMSG_66 0x0282 +#define mmMP1_SMN_C2PMSG_66_BASE_IDX 0 + +#define mmMP1_SMN_C2PMSG_82 0x0292 +#define mmMP1_SMN_C2PMSG_82_BASE_IDX 0 + +#define mmMP1_SMN_C2PMSG_90 0x029a +#define mmMP1_SMN_C2PMSG_90_BASE_IDX 0 + +#define MP1_C2PMSG_90__CONTENT_MASK 0xFFFFFFFFL + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(type) #type +static const char* __smu_message_names[] = { + SMU_MESSAGE_TYPES +}; + +static 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]; +} + +static void smu_cmn_send_msg_without_waiting(struct smu_context *smu, + uint16_t msg) +{ + struct amdgpu_device *adev = smu->adev; + + WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); +} + +static void smu_cmn_read_arg(struct smu_context *smu, + uint32_t *arg) +{ + struct amdgpu_device *adev = smu->adev; + + *arg = RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82); +} + +static int smu_cmn_wait_for_response(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + uint32_t cur_value, i, timeout = adev->usec_timeout * 10; + + for (i = 0; i < timeout; i++) { + cur_value = RREG32_SOC15_NO_KIQ(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 */ + if (i == timeout) + return -ETIME; + + return RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO; +} + +int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param, + uint32_t *read_arg) +{ + struct amdgpu_device *adev = smu->adev; + int ret = 0, index = 0; + + index = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_MSG, + msg); + if (index < 0) + return index == -EACCES ? 0 : index; + + mutex_lock(&smu->message_lock); + ret = smu_cmn_wait_for_response(smu); + if (ret) { + dev_err(adev->dev, "Msg issuing pre-check failed and " + "SMU may be not in the right state!\n"); + goto out; + } + + WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); + + WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82, param); + + smu_cmn_send_msg_without_waiting(smu, (uint16_t)index); + + ret = smu_cmn_wait_for_response(smu); + if (ret) { + dev_err(adev->dev, "failed send message: %10s (%d) \tparam: 0x%08x response %#x\n", + smu_get_message_name(smu, msg), index, param, ret); + goto out; + } + + if (read_arg) + smu_cmn_read_arg(smu, read_arg); + +out: + mutex_unlock(&smu->message_lock); + return ret; +} + +int smu_cmn_send_smc_msg(struct smu_context *smu, + enum smu_message_type msg, + uint32_t *read_arg) +{ + return smu_cmn_send_smc_msg_with_param(smu, + msg, + 0, + read_arg); +} + +int smu_cmn_to_asic_specific_index(struct smu_context *smu, + enum smu_cmn2asic_mapping_type type, + uint32_t index) +{ + struct cmn2asic_msg_mapping msg_mapping; + struct cmn2asic_mapping mapping; + + switch (type) { + case CMN2ASIC_MAPPING_MSG: + if (index >= SMU_MSG_MAX_COUNT || + !smu->message_map) + return -EINVAL; + + msg_mapping = smu->message_map[index]; + if (!msg_mapping.valid_mapping) + return -EINVAL; + + if (amdgpu_sriov_vf(smu->adev) && + !msg_mapping.valid_in_vf) + return -EACCES; + + return msg_mapping.map_to; + + case CMN2ASIC_MAPPING_CLK: + if (index >= SMU_CLK_COUNT || + !smu->clock_map) + return -EINVAL; + + mapping = smu->clock_map[index]; + if (!mapping.valid_mapping) + return -EINVAL; + + return mapping.map_to; + + case CMN2ASIC_MAPPING_FEATURE: + if (index >= SMU_FEATURE_COUNT || + !smu->feature_map) + return -EINVAL; + + mapping = smu->feature_map[index]; + if (!mapping.valid_mapping) + return -EINVAL; + + return mapping.map_to; + + case CMN2ASIC_MAPPING_TABLE: + if (index >= SMU_TABLE_COUNT || + !smu->table_map) + return -EINVAL; + + mapping = smu->table_map[index]; + if (!mapping.valid_mapping) + return -EINVAL; + + return mapping.map_to; + + case CMN2ASIC_MAPPING_PWR: + if (index >= SMU_POWER_SOURCE_COUNT || + !smu->pwr_src_map) + return -EINVAL; + + mapping = smu->pwr_src_map[index]; + if (!mapping.valid_mapping) + return -EINVAL; + + return mapping.map_to; + + case CMN2ASIC_MAPPING_WORKLOAD: + if (index > PP_SMC_POWER_PROFILE_CUSTOM || + !smu->workload_map) + return -EINVAL; + + mapping = smu->workload_map[index]; + if (!mapping.valid_mapping) + return -EINVAL; + + return mapping.map_to; + + default: + return -EINVAL; + } +} + +int smu_cmn_feature_is_supported(struct smu_context *smu, + enum smu_feature_mask mask) +{ + struct smu_feature *feature = &smu->smu_feature; + int feature_id; + int ret = 0; + + feature_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_FEATURE, + mask); + if (feature_id < 0) + return 0; + + WARN_ON(feature_id > feature->feature_num); + + mutex_lock(&feature->mutex); + ret = test_bit(feature_id, feature->supported); + mutex_unlock(&feature->mutex); + + return ret; +} + +int smu_cmn_feature_is_enabled(struct smu_context *smu, + enum smu_feature_mask mask) +{ + struct smu_feature *feature = &smu->smu_feature; + int feature_id; + int ret = 0; + + if (smu->is_apu) + return 1; + feature_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_FEATURE, + mask); + if (feature_id < 0) + return 0; + + WARN_ON(feature_id > feature->feature_num); + + mutex_lock(&feature->mutex); + ret = test_bit(feature_id, feature->enabled); + mutex_unlock(&feature->mutex); + + return ret; +} + +bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, + enum smu_clk_type clk_type) +{ + enum smu_feature_mask feature_id = 0; + + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + feature_id = SMU_FEATURE_DPM_UCLK_BIT; + break; + case SMU_GFXCLK: + case SMU_SCLK: + feature_id = SMU_FEATURE_DPM_GFXCLK_BIT; + break; + case SMU_SOCCLK: + feature_id = SMU_FEATURE_DPM_SOCCLK_BIT; + break; + default: + return true; + } + + if (!smu_cmn_feature_is_enabled(smu, feature_id)) + return false; + + return true; +} + +int smu_cmn_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; + + if (bitmap_empty(feature->enabled, feature->feature_num)) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh, &feature_mask_high); + if (ret) + return ret; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow, &feature_mask_low); + if (ret) + return ret; + + 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_cmn_feature_update_enable_state(struct smu_context *smu, + uint64_t feature_mask, + bool enabled) +{ + struct smu_feature *feature = &smu->smu_feature; + int ret = 0; + + if (enabled) { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EnableSmuFeaturesLow, + lower_32_bits(feature_mask), + NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_EnableSmuFeaturesHigh, + upper_32_bits(feature_mask), + NULL); + if (ret) + return ret; + } else { + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_DisableSmuFeaturesLow, + lower_32_bits(feature_mask), + NULL); + if (ret) + return ret; + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_DisableSmuFeaturesHigh, + upper_32_bits(feature_mask), + NULL); + 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_cmn_feature_set_enabled(struct smu_context *smu, + enum smu_feature_mask mask, + bool enable) +{ + struct smu_feature *feature = &smu->smu_feature; + int feature_id; + + feature_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_FEATURE, + mask); + if (feature_id < 0) + return -EINVAL; + + WARN_ON(feature_id > feature->feature_num); + + return smu_cmn_feature_update_enable_state(smu, + 1ULL << feature_id, + enable); +} + +#undef __SMU_DUMMY_MAP +#define __SMU_DUMMY_MAP(fea) #fea +static const char* __smu_feature_names[] = { + SMU_FEATURE_MASKS +}; + +static 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_cmn_get_pp_feature_mask(struct smu_context *smu, + char *buf) +{ + 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; + size_t size = 0; + int ret = 0, i; + + ret = smu_cmn_get_enabled_mask(smu, + feature_mask, + 2); + if (ret) + return 0; + + 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_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_FEATURE, + 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_cmn_feature_is_enabled(smu, sort_feature[i]) ? + "enabled" : "disabled"); + } + + return size; +} + +int smu_cmn_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; + + ret = smu_cmn_get_enabled_mask(smu, + feature_mask, + 2); + if (ret) + return ret; + + 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_cmn_feature_update_enable_state(smu, + feature_2_enabled, + true); + if (ret) + return ret; + } + if (feature_2_disabled) { + ret = smu_cmn_feature_update_enable_state(smu, + feature_2_disabled, + false); + if (ret) + return ret; + } + + return ret; +} + +int smu_cmn_disable_all_features_with_exception(struct smu_context *smu, + enum smu_feature_mask mask) +{ + uint64_t features_to_disable = U64_MAX; + int skipped_feature_id; + + skipped_feature_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_FEATURE, + mask); + if (skipped_feature_id < 0) + return -EINVAL; + + features_to_disable &= ~(1ULL << skipped_feature_id); + + return smu_cmn_feature_update_enable_state(smu, + features_to_disable, + 0); +} + +int smu_cmn_get_smc_version(struct smu_context *smu, + uint32_t *if_version, + uint32_t *smu_version) +{ + int ret = 0; + + if (!if_version && !smu_version) + return -EINVAL; + + if (smu->smc_fw_if_version && smu->smc_fw_version) + { + if (if_version) + *if_version = smu->smc_fw_if_version; + + if (smu_version) + *smu_version = smu->smc_fw_version; + + return 0; + } + + if (if_version) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetDriverIfVersion, if_version); + if (ret) + return ret; + + smu->smc_fw_if_version = *if_version; + } + + if (smu_version) { + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_GetSmuVersion, smu_version); + if (ret) + return ret; + + smu->smc_fw_version = *smu_version; + } + + return ret; +} + +int smu_cmn_update_table(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + bool drv2smu) +{ + struct smu_table_context *smu_table = &smu->smu_table; + struct amdgpu_device *adev = smu->adev; + struct smu_table *table = &smu_table->driver_table; + int table_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_TABLE, + table_index); + uint32_t table_size; + int ret = 0; + if (!table_data || table_id >= SMU_TABLE_COUNT || table_id < 0) + return -EINVAL; + + table_size = smu_table->tables[table_index].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_cmn_send_smc_msg_with_param(smu, drv2smu ? + SMU_MSG_TransferTableDram2Smu : + SMU_MSG_TransferTableSmu2Dram, + table_id | ((argument & 0xFFFF) << 16), + NULL); + if (ret) + return ret; + + if (!drv2smu) { + amdgpu_asic_flush_hdp(adev, NULL); + memcpy(table_data, table->cpu_addr, table_size); + } + + return ret; +} + +int smu_cmn_write_watermarks_table(struct smu_context *smu) +{ + void *watermarks_table = smu->smu_table.watermarks_table; + + if (!watermarks_table) + return -EINVAL; + + return smu_cmn_update_table(smu, + SMU_TABLE_WATERMARKS, + 0, + watermarks_table, + true); +} + +int smu_cmn_write_pptable(struct smu_context *smu) +{ + void *pptable = smu->smu_table.driver_pptable; + + return smu_cmn_update_table(smu, + SMU_TABLE_PPTABLE, + 0, + pptable, + true); +} diff --git a/drivers/gpu/drm/amd/powerplay/smu_cmn.h b/drivers/gpu/drm/amd/powerplay/smu_cmn.h new file mode 100644 index 000000000000..98face8c5fd6 --- /dev/null +++ b/drivers/gpu/drm/amd/powerplay/smu_cmn.h @@ -0,0 +1,83 @@ +/* + * Copyright 2020 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_CMN_H__ +#define __SMU_CMN_H__ + +#include "amdgpu_smu.h" + +#if defined(SWSMU_CODE_LAYER_L2) || defined(SWSMU_CODE_LAYER_L3) || defined(SWSMU_CODE_LAYER_L4) +int smu_cmn_send_smc_msg_with_param(struct smu_context *smu, + enum smu_message_type msg, + uint32_t param, + uint32_t *read_arg); + +int smu_cmn_send_smc_msg(struct smu_context *smu, + enum smu_message_type msg, + uint32_t *read_arg); + +int smu_cmn_to_asic_specific_index(struct smu_context *smu, + enum smu_cmn2asic_mapping_type type, + uint32_t index); + +int smu_cmn_feature_is_supported(struct smu_context *smu, + enum smu_feature_mask mask); + +int smu_cmn_feature_is_enabled(struct smu_context *smu, + enum smu_feature_mask mask); + +bool smu_cmn_clk_dpm_is_enabled(struct smu_context *smu, + enum smu_clk_type clk_type); + +int smu_cmn_get_enabled_mask(struct smu_context *smu, + uint32_t *feature_mask, + uint32_t num); + +int smu_cmn_feature_set_enabled(struct smu_context *smu, + enum smu_feature_mask mask, + bool enable); + +size_t smu_cmn_get_pp_feature_mask(struct smu_context *smu, + char *buf); + +int smu_cmn_set_pp_feature_mask(struct smu_context *smu, + uint64_t new_mask); + +int smu_cmn_disable_all_features_with_exception(struct smu_context *smu, + enum smu_feature_mask mask); + +int smu_cmn_get_smc_version(struct smu_context *smu, + uint32_t *if_version, + uint32_t *smu_version); + +int smu_cmn_update_table(struct smu_context *smu, + enum smu_table_id table_index, + int argument, + void *table_data, + bool drv2smu); + +int smu_cmn_write_watermarks_table(struct smu_context *smu); + +int smu_cmn_write_pptable(struct smu_context *smu); + +#endif +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_internal.h b/drivers/gpu/drm/amd/powerplay/smu_internal.h index c97444841abc..264073d4e263 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_internal.h +++ b/drivers/gpu/drm/amd/powerplay/smu_internal.h @@ -25,198 +25,73 @@ #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) - -#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) \ - ((smu)->ppt_funcs->send_smc_msg_with_param? (smu)->ppt_funcs->send_smc_msg_with_param((smu), (msg), (param), (read_arg)) : 0) - -static inline int smu_send_smc_msg(struct smu_context *smu, enum smu_message_type msg, uint32_t *read_arg) { - return smu_send_smc_msg_with_param(smu, msg, 0, read_arg); -} - -#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) - -#define smu_set_power_source(smu, power_src) \ - ((smu)->ppt_funcs->set_power_source ? (smu)->ppt_funcs->set_power_source((smu), (power_src)) : 0) - -#define smu_i2c_eeprom_init(smu, control) \ - ((smu)->ppt_funcs->i2c_eeprom_init ? (smu)->ppt_funcs->i2c_eeprom_init((control)) : 0) -#define smu_i2c_eeprom_fini(smu, control) \ - ((smu)->ppt_funcs->i2c_eeprom_fini ? (smu)->ppt_funcs->i2c_eeprom_fini((control)) : 0) +#if defined(SWSMU_CODE_LAYER_L1) + +#define smu_ppt_funcs(intf, ret, smu, args...) \ + ((smu)->ppt_funcs ? ((smu)->ppt_funcs->intf ? (smu)->ppt_funcs->intf(smu, ##args) : ret) : -EINVAL) + +#define smu_init_microcode(smu) smu_ppt_funcs(init_microcode, 0, smu) +#define smu_fini_microcode(smu) smu_ppt_funcs(fini_microcode, 0, smu) +#define smu_init_smc_tables(smu) smu_ppt_funcs(init_smc_tables, 0, smu) +#define smu_fini_smc_tables(smu) smu_ppt_funcs(fini_smc_tables, 0, smu) +#define smu_init_power(smu) smu_ppt_funcs(init_power, 0, smu) +#define smu_fini_power(smu) smu_ppt_funcs(fini_power, 0, smu) +#define smu_setup_pptable(smu) smu_ppt_funcs(setup_pptable, 0, smu) +#define smu_powergate_sdma(smu, gate) smu_ppt_funcs(powergate_sdma, 0, smu, gate) +#define smu_get_vbios_bootup_values(smu) smu_ppt_funcs(get_vbios_bootup_values, 0, smu) +#define smu_check_fw_version(smu) smu_ppt_funcs(check_fw_version, 0, smu) +#define smu_write_pptable(smu) smu_ppt_funcs(write_pptable, 0, smu) +#define smu_set_min_dcef_deep_sleep(smu, clk) smu_ppt_funcs(set_min_dcef_deep_sleep, 0, smu, clk) +#define smu_set_driver_table_location(smu) smu_ppt_funcs(set_driver_table_location, 0, smu) +#define smu_set_tool_table_location(smu) smu_ppt_funcs(set_tool_table_location, 0, smu) +#define smu_notify_memory_pool_location(smu) smu_ppt_funcs(notify_memory_pool_location, 0, smu) +#define smu_gfx_off_control(smu, enable) smu_ppt_funcs(gfx_off_control, 0, smu, enable) +#define smu_get_gfx_off_status(smu) smu_ppt_funcs(get_gfx_off_status, 0, smu) +#define smu_set_last_dcef_min_deep_sleep_clk(smu) smu_ppt_funcs(set_last_dcef_min_deep_sleep_clk, 0, smu) +#define smu_system_features_control(smu, en) smu_ppt_funcs(system_features_control, 0, smu, en) +#define smu_init_max_sustainable_clocks(smu) smu_ppt_funcs(init_max_sustainable_clocks, 0, smu) +#define smu_set_default_od_settings(smu) smu_ppt_funcs(set_default_od_settings, 0, smu) +#define smu_send_smc_msg_with_param(smu, msg, param, read_arg) smu_ppt_funcs(send_smc_msg_with_param, 0, smu, msg, param, read_arg) +#define smu_send_smc_msg(smu, msg, read_arg) smu_ppt_funcs(send_smc_msg, 0, smu, msg, read_arg) +#define smu_init_display_count(smu, count) smu_ppt_funcs(init_display_count, 0, smu, count) +#define smu_feature_set_allowed_mask(smu) smu_ppt_funcs(set_allowed_mask, 0, smu) +#define smu_feature_get_enabled_mask(smu, mask, num) smu_ppt_funcs(get_enabled_mask, 0, smu, mask, num) +#define smu_feature_is_enabled(smu, mask) smu_ppt_funcs(feature_is_enabled, 0, smu, mask) +#define smu_disable_all_features_with_exception(smu, mask) smu_ppt_funcs(disable_all_features_with_exception, 0, smu, mask) +#define smu_is_dpm_running(smu) smu_ppt_funcs(is_dpm_running, 0 , smu) +#define smu_notify_display_change(smu) smu_ppt_funcs(notify_display_change, 0, smu) +#define smu_populate_umd_state_clk(smu) smu_ppt_funcs(populate_umd_state_clk, 0, smu) +#define smu_set_default_od8_settings(smu) smu_ppt_funcs(set_default_od8_settings, 0, smu) +#define smu_enable_thermal_alert(smu) smu_ppt_funcs(enable_thermal_alert, 0, smu) +#define smu_disable_thermal_alert(smu) smu_ppt_funcs(disable_thermal_alert, 0, smu) +#define smu_smc_read_sensor(smu, sensor, data, size) smu_ppt_funcs(read_sensor, -EINVAL, smu, sensor, data, size) +#define smu_pre_display_config_changed(smu) smu_ppt_funcs(pre_display_config_changed, 0, smu) +#define smu_display_config_changed(smu) smu_ppt_funcs(display_config_changed, 0 , smu) +#define smu_apply_clocks_adjust_rules(smu) smu_ppt_funcs(apply_clocks_adjust_rules, 0, smu) +#define smu_notify_smc_display_config(smu) smu_ppt_funcs(notify_smc_display_config, 0, smu) +#define smu_set_cpu_power_state(smu) smu_ppt_funcs(set_cpu_power_state, 0, smu) +#define smu_run_btc(smu) smu_ppt_funcs(run_btc, 0, smu) +#define smu_get_allowed_feature_mask(smu, feature_mask, num) smu_ppt_funcs(get_allowed_feature_mask, 0, smu, feature_mask, num) +#define smu_store_cc6_data(smu, st, cc6_dis, pst_dis, pst_sw_dis) smu_ppt_funcs(store_cc6_data, 0, smu, st, cc6_dis, pst_dis, pst_sw_dis) +#define smu_get_dal_power_level(smu, clocks) smu_ppt_funcs(get_dal_power_level, 0, smu, clocks) +#define smu_get_perf_level(smu, designation, level) smu_ppt_funcs(get_perf_level, 0, smu, designation, level) +#define smu_get_current_shallow_sleep_clocks(smu, clocks) smu_ppt_funcs(get_current_shallow_sleep_clocks, 0, smu, clocks) +#define smu_set_watermarks_table(smu, clock_ranges) smu_ppt_funcs(set_watermarks_table, 0, smu, clock_ranges) +#define smu_thermal_temperature_range_update(smu, range, rw) smu_ppt_funcs(thermal_temperature_range_update, 0, smu, range, rw) +#define smu_register_irq_handler(smu) smu_ppt_funcs(register_irq_handler, 0, smu) +#define smu_get_dpm_ultimate_freq(smu, param, min, max) smu_ppt_funcs(get_dpm_ultimate_freq, 0, smu, param, min, max) +#define smu_asic_set_performance_level(smu, level) smu_ppt_funcs(set_performance_level, -EINVAL, smu, level) +#define smu_dump_pptable(smu) smu_ppt_funcs(dump_pptable, 0, smu) +#define smu_update_pcie_parameters(smu, pcie_gen_cap, pcie_width_cap) smu_ppt_funcs(update_pcie_parameters, 0, smu, pcie_gen_cap, pcie_width_cap) +#define smu_disable_umc_cdr_12gbps_workaround(smu) smu_ppt_funcs(disable_umc_cdr_12gbps_workaround, 0, smu) +#define smu_set_power_source(smu, power_src) smu_ppt_funcs(set_power_source, 0, smu, power_src) +#define smu_i2c_init(smu, control) smu_ppt_funcs(i2c_init, 0, smu, control) +#define smu_i2c_fini(smu, control) smu_ppt_funcs(i2c_fini, 0, smu, control) +#define smu_get_unique_id(smu) smu_ppt_funcs(get_unique_id, 0, smu) +#define smu_log_thermal_throttling(smu) smu_ppt_funcs(log_thermal_throttling_event, 0, smu) +#define smu_get_asic_power_limits(smu) smu_ppt_funcs(get_power_limit, 0, smu) +#define smu_get_pp_feature_mask(smu, buf) smu_ppt_funcs(get_pp_feature_mask, 0, smu, buf) +#define smu_set_pp_feature_mask(smu, new_mask) smu_ppt_funcs(set_pp_feature_mask, 0, smu, new_mask) #endif +#endif diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c index aa76c2cea747..7b950a582a28 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c @@ -26,18 +26,18 @@ #include <linux/reboot.h> #define SMU_11_0_PARTIAL_PPTABLE +#define SWSMU_CODE_LAYER_L3 #include "amdgpu.h" #include "amdgpu_smu.h" -#include "smu_internal.h" #include "atomfirmware.h" #include "amdgpu_atomfirmware.h" +#include "amdgpu_atombios.h" #include "smu_v11_0.h" -#include "smu_v11_0_pptable.h" #include "soc15_common.h" #include "atom.h" -#include "amd_pcie.h" #include "amdgpu_ras.h" +#include "smu_cmn.h" #include "asic_reg/thm/thm_11_0_2_offset.h" #include "asic_reg/thm/thm_11_0_2_sh_mask.h" @@ -46,96 +46,26 @@ #include "asic_reg/smuio/smuio_11_0_0_offset.h" #include "asic_reg/smuio/smuio_11_0_0_sh_mask.h" -MODULE_FIRMWARE("amdgpu/vega20_smc.bin"); +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + MODULE_FIRMWARE("amdgpu/arcturus_smc.bin"); MODULE_FIRMWARE("amdgpu/navi10_smc.bin"); MODULE_FIRMWARE("amdgpu/navi14_smc.bin"); MODULE_FIRMWARE("amdgpu/navi12_smc.bin"); +MODULE_FIRMWARE("amdgpu/sienna_cichlid_smc.bin"); +MODULE_FIRMWARE("amdgpu/navy_flounder_smc.bin"); #define SMU11_VOLTAGE_SCALE 4 -static int smu_v11_0_send_msg_without_waiting(struct smu_context *smu, - uint16_t msg) -{ - struct amdgpu_device *adev = smu->adev; - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_66, msg); - return 0; -} - -static int smu_v11_0_read_arg(struct smu_context *smu, uint32_t *arg) -{ - struct amdgpu_device *adev = smu->adev; - - *arg = RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82); - return 0; -} - -static int smu_v11_0_wait_for_response(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t cur_value, i, timeout = adev->usec_timeout * 10; - - for (i = 0; i < timeout; i++) { - cur_value = RREG32_SOC15_NO_KIQ(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 */ - if (i == timeout) - return -ETIME; - - return RREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90) == 0x1 ? 0 : -EIO; -} - -int -smu_v11_0_send_msg_with_param(struct smu_context *smu, - enum smu_message_type msg, - uint32_t param, - uint32_t *read_arg) -{ - struct amdgpu_device *adev = smu->adev; - int ret = 0, index = 0; - - index = smu_msg_get_index(smu, msg); - if (index < 0) - return index; - - mutex_lock(&smu->message_lock); - ret = smu_v11_0_wait_for_response(smu); - if (ret) { - pr_err("Msg issuing pre-check failed and " - "SMU may be not in the right state!\n"); - goto out; - } - - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_90, 0); - - WREG32_SOC15_NO_KIQ(MP1, 0, mmMP1_SMN_C2PMSG_82, param); - - smu_v11_0_send_msg_without_waiting(smu, (uint16_t)index); - - ret = smu_v11_0_wait_for_response(smu); - if (ret) { - pr_err("failed send message: %10s (%d) \tparam: 0x%08x response %#x\n", - smu_get_message_name(smu, msg), index, param, ret); - goto out; - } - - if (read_arg) { - ret = smu_v11_0_read_arg(smu, read_arg); - if (ret) { - pr_err("failed to read message arg: %10s (%d) \tparam: 0x%08x response %#x\n", - smu_get_message_name(smu, msg), index, param, ret); - goto out; - } - } -out: - mutex_unlock(&smu->message_lock); - return ret; -} +#define SMU11_MODE1_RESET_WAIT_TIME_IN_MS 500 //500ms int smu_v11_0_init_microcode(struct smu_context *smu) { @@ -148,9 +78,6 @@ int smu_v11_0_init_microcode(struct smu_context *smu) struct amdgpu_firmware_info *ucode = NULL; switch (adev->asic_type) { - case CHIP_VEGA20: - chip_name = "vega20"; - break; case CHIP_ARCTURUS: chip_name = "arcturus"; break; @@ -163,8 +90,15 @@ int smu_v11_0_init_microcode(struct smu_context *smu) case CHIP_NAVI12: chip_name = "navi12"; break; + case CHIP_SIENNA_CICHLID: + chip_name = "sienna_cichlid"; + break; + case CHIP_NAVY_FLOUNDER: + chip_name = "navy_flounder"; + break; default: - BUG(); + dev_err(adev->dev, "Unsupported ASIC type %d\n", adev->asic_type); + return -EINVAL; } snprintf(fw_name, sizeof(fw_name), "amdgpu/%s_smc.bin", chip_name); @@ -199,6 +133,15 @@ out: return err; } +void smu_v11_0_fini_microcode(struct smu_context *smu) +{ + struct amdgpu_device *adev = smu->adev; + + release_firmware(adev->pm.fw); + adev->pm.fw = NULL; + adev->pm.fw_version = 0; +} + int smu_v11_0_load_microcode(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -261,7 +204,7 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) uint8_t smu_minor, smu_debug; int ret = 0; - ret = smu_get_smc_version(smu, &if_version, &smu_version); + ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); if (ret) return ret; @@ -270,9 +213,6 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) smu_debug = (smu_version >> 0) & 0xff; switch (smu->adev->asic_type) { - case CHIP_VEGA20: - smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_VG20; - break; case CHIP_ARCTURUS: smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_ARCT; break; @@ -285,8 +225,14 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) case CHIP_NAVI14: smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_NV14; break; + case CHIP_SIENNA_CICHLID: + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Sienna_Cichlid; + break; + case CHIP_NAVY_FLOUNDER: + smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_Navy_Flounder; + break; default: - pr_err("smu unsupported asic type:%d.\n", smu->adev->asic_type); + dev_err(smu->adev->dev, "smu unsupported asic type:%d.\n", smu->adev->asic_type); smu->smc_driver_if_version = SMU11_DRIVER_IF_VERSION_INV; break; } @@ -300,11 +246,11 @@ int smu_v11_0_check_fw_version(struct smu_context *smu) * of halt driver loading. */ if (if_version != smu->smc_driver_if_version) { - pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " "smu fw version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_version, smu_major, smu_minor, smu_debug); - pr_warn("SMU driver if version not matched\n"); + dev_warn(smu->adev->dev, "SMU driver if version not matched\n"); } return ret; @@ -366,8 +312,9 @@ int smu_v11_0_setup_pptable(struct smu_context *smu) hdr = (const struct smc_firmware_header_v1_0 *) adev->pm.fw->data; 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); + if ((version_major == 2 && smu->smu_table.boot_values.pp_table_id > 0) || + adev->asic_type == CHIP_NAVY_FLOUNDER) { + dev_info(adev->dev, "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); @@ -384,11 +331,11 @@ int smu_v11_0_setup_pptable(struct smu_context *smu) return ret; } else { - pr_info("use vbios provided pptable\n"); + dev_info(adev->dev, "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, &atom_table_size, &frev, &crev, + ret = amdgpu_atombios_get_data_table(adev, index, &atom_table_size, &frev, &crev, (uint8_t **)&table); if (ret) return ret; @@ -403,82 +350,87 @@ int smu_v11_0_setup_pptable(struct smu_context *smu) return 0; } -static int smu_v11_0_init_dpm_context(struct smu_context *smu) -{ - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - - if (smu_dpm->dpm_context || smu_dpm->dpm_context_size != 0) - return -EINVAL; - - return smu_alloc_dpm_context(smu); -} - -static int smu_v11_0_fini_dpm_context(struct smu_context *smu) -{ - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - - if (!smu_dpm->dpm_context || smu_dpm->dpm_context_size == 0) - return -EINVAL; - - kfree(smu_dpm->dpm_context); - kfree(smu_dpm->golden_dpm_context); - kfree(smu_dpm->dpm_current_power_state); - kfree(smu_dpm->dpm_request_power_state); - smu_dpm->dpm_context = NULL; - smu_dpm->golden_dpm_context = NULL; - smu_dpm->dpm_context_size = 0; - smu_dpm->dpm_current_power_state = NULL; - smu_dpm->dpm_request_power_state = NULL; - - return 0; -} - 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; + struct smu_table *tables = smu_table->tables; int ret = 0; - if (smu_table->tables) - return -EINVAL; - - tables = kcalloc(SMU_TABLE_COUNT, sizeof(struct smu_table), - GFP_KERNEL); - if (!tables) - return -ENOMEM; + smu_table->driver_pptable = + kzalloc(tables[SMU_TABLE_PPTABLE].size, GFP_KERNEL); + if (!smu_table->driver_pptable) { + ret = -ENOMEM; + goto err0_out; + } - smu_table->tables = tables; + smu_table->max_sustainable_clocks = + kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks), GFP_KERNEL); + if (!smu_table->max_sustainable_clocks) { + ret = -ENOMEM; + goto err1_out; + } - ret = smu_tables_init(smu, tables); - if (ret) - return ret; + /* Arcturus does not support OVERDRIVE */ + if (tables[SMU_TABLE_OVERDRIVE].size) { + smu_table->overdrive_table = + kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); + if (!smu_table->overdrive_table) { + ret = -ENOMEM; + goto err2_out; + } - ret = smu_v11_0_init_dpm_context(smu); - if (ret) - return ret; + smu_table->boot_overdrive_table = + kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL); + if (!smu_table->boot_overdrive_table) { + ret = -ENOMEM; + goto err3_out; + } + } return 0; + +err3_out: + kfree(smu_table->overdrive_table); +err2_out: + kfree(smu_table->max_sustainable_clocks); +err1_out: + kfree(smu_table->driver_pptable); +err0_out: + return ret; } int smu_v11_0_fini_smc_tables(struct smu_context *smu) { struct smu_table_context *smu_table = &smu->smu_table; - int ret = 0; + struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - if (!smu_table->tables) - return -EINVAL; + kfree(smu_table->boot_overdrive_table); + kfree(smu_table->overdrive_table); + kfree(smu_table->max_sustainable_clocks); + kfree(smu_table->driver_pptable); + smu_table->boot_overdrive_table = NULL; + smu_table->overdrive_table = NULL; + smu_table->max_sustainable_clocks = NULL; + smu_table->driver_pptable = NULL; + kfree(smu_table->hardcode_pptable); + smu_table->hardcode_pptable = NULL; - kfree(smu_table->tables); kfree(smu_table->metrics_table); kfree(smu_table->watermarks_table); - smu_table->tables = NULL; smu_table->metrics_table = NULL; smu_table->watermarks_table = NULL; smu_table->metrics_time = 0; - ret = smu_v11_0_fini_dpm_context(smu); - if (ret) - return ret; + kfree(smu_dpm->dpm_context); + kfree(smu_dpm->golden_dpm_context); + kfree(smu_dpm->dpm_current_power_state); + kfree(smu_dpm->dpm_request_power_state); + smu_dpm->dpm_context = NULL; + smu_dpm->golden_dpm_context = NULL; + smu_dpm->dpm_context_size = 0; + smu_dpm->dpm_current_power_state = NULL; + smu_dpm->dpm_request_power_state = NULL; + return 0; } @@ -512,6 +464,32 @@ int smu_v11_0_fini_power(struct smu_context *smu) return 0; } +static int smu_v11_0_atom_get_smu_clockinfo(struct amdgpu_device *adev, + uint8_t clk_id, + uint8_t syspll_id, + uint32_t *clk_freq) +{ + struct atom_get_smu_clock_info_parameters_v3_1 input = {0}; + struct atom_get_smu_clock_info_output_parameters_v3_1 *output; + int ret, index; + + input.clk_id = clk_id; + input.syspll_id = syspll_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; + *clk_freq = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; + + return 0; +} + int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu) { int ret, index; @@ -524,13 +502,13 @@ int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu) index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1, firmwareinfo); - ret = smu_get_atom_data_table(smu, index, &size, &frev, &crev, + ret = amdgpu_atombios_get_data_table(smu->adev, index, &size, &frev, &crev, (uint8_t **)&header); if (ret) return ret; if (header->format_revision != 3) { - pr_err("unknown atom_firmware_info version! for smu11\n"); + dev_err(smu->adev->dev, "unknown atom_firmware_info version! for smu11\n"); return -EINVAL; } @@ -570,102 +548,37 @@ int smu_v11_0_get_vbios_bootup_values(struct smu_context *smu) smu->smu_table.boot_values.format_revision = header->format_revision; smu->smu_table.boot_values.content_revision = header->content_revision; - return 0; -} + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_SOCCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.socclk); -int smu_v11_0_get_clk_info_from_vbios(struct smu_context *smu) -{ - int ret, index; - struct amdgpu_device *adev = smu->adev; - struct atom_get_smu_clock_info_parameters_v3_1 input = {0}; - struct atom_get_smu_clock_info_output_parameters_v3_1 *output; - - input.clk_id = SMU11_SYSPLL0_SOCCLK_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.socclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; - - memset(&input, 0, sizeof(input)); - input.clk_id = SMU11_SYSPLL0_DCEFCLK_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.dcefclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; - - memset(&input, 0, sizeof(input)); - input.clk_id = SMU11_SYSPLL0_ECLK_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.eclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_DCEFCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.dcefclk); - memset(&input, 0, sizeof(input)); - input.clk_id = SMU11_SYSPLL0_VCLK_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.vclk = le32_to_cpu(output->atom_smu_outputclkfreq.smu_clock_freq_hz) / 10000; - - memset(&input, 0, sizeof(input)); - input.clk_id = SMU11_SYSPLL0_DCLK_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); + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_ECLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.eclk); - ret = amdgpu_atom_execute_table(adev->mode_info.atom_context, index, - (uint32_t *)&input); - if (ret) - return -EINVAL; + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_VCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.vclk); - 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; + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL0_DCLK_ID, + (uint8_t)0, + &smu->smu_table.boot_values.dclk); 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; - } + (smu->smu_table.boot_values.content_revision >= 2)) + smu_v11_0_atom_get_smu_clockinfo(smu->adev, + (uint8_t)SMU11_SYSPLL1_0_FCLK_ID, + (uint8_t)SMU11_SYSPLL1_2_ID, + &smu->smu_table.boot_values.fclk); return 0; } @@ -685,13 +598,13 @@ int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) address_high = (uint32_t)upper_32_bits(address); address_low = (uint32_t)lower_32_bits(address); - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSystemVirtualDramAddrHigh, address_high, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSystemVirtualDramAddrLow, address_low, NULL); @@ -702,15 +615,15 @@ int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) address_high = (uint32_t)upper_32_bits(address); address_low = (uint32_t)lower_32_bits(address); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrHigh, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrHigh, address_high, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrLow, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramAddrLow, address_low, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramSize, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_DramLogSetDramSize, (uint32_t)memory_pool->size, NULL); if (ret) return ret; @@ -718,96 +631,30 @@ int smu_v11_0_notify_memory_pool_location(struct smu_context *smu) return ret; } -int smu_v11_0_check_pptable(struct smu_context *smu) +int smu_v11_0_set_min_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) { int ret; - ret = smu_check_powerplay_table(smu); - return ret; -} - -int smu_v11_0_parse_pptable(struct smu_context *smu) -{ - int ret; - - struct smu_table_context *table_context = &smu->smu_table; - struct smu_table *table = &table_context->tables[SMU_TABLE_PPTABLE]; - - /* during TDR we need to free and alloc the pptable */ - if (table_context->driver_pptable) - kfree(table_context->driver_pptable); - - table_context->driver_pptable = kzalloc(table->size, GFP_KERNEL); - - if (!table_context->driver_pptable) - return -ENOMEM; - - ret = smu_store_powerplay_table(smu); - if (ret) - return -EINVAL; - - ret = smu_append_powerplay_table(smu); - - return ret; -} - -int smu_v11_0_populate_smc_pptable(struct smu_context *smu) -{ - int ret; - - ret = smu_set_default_dpm_table(smu); - - return ret; -} - -int smu_v11_0_write_pptable(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - int ret = 0; - - ret = smu_update_table(smu, SMU_TABLE_PPTABLE, 0, - table_context->driver_pptable, true); - - return ret; -} - -int smu_v11_0_set_deep_sleep_dcefclk(struct smu_context *smu, uint32_t clk) -{ - int ret; - - if (amdgpu_sriov_vf(smu->adev)) - return 0; - - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetMinDeepSleepDcefclk, clk, NULL); if (ret) - pr_err("SMU11 attempt to set divider for DCEFCLK Failed!"); + dev_err(smu->adev->dev, "SMU11 attempt to set divider for DCEFCLK Failed!"); return ret; } -int smu_v11_0_set_min_dcef_deep_sleep(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - - if (!table_context) - return -EINVAL; - - 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, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrHigh, upper_32_bits(driver_table->mc_address), NULL); if (!ret) - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrLow, lower_32_bits(driver_table->mc_address), NULL); @@ -821,16 +668,13 @@ 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]; - if (amdgpu_sriov_vf(smu->adev)) - return 0; - if (tool_table->mc_address) { - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetToolsDramAddrHigh, upper_32_bits(tool_table->mc_address), NULL); if (!ret) - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetToolsDramAddrLow, lower_32_bits(tool_table->mc_address), NULL); @@ -842,14 +686,16 @@ int smu_v11_0_set_tool_table_location(struct smu_context *smu) int smu_v11_0_init_display_count(struct smu_context *smu, uint32_t count) { int ret = 0; + struct amdgpu_device *adev = smu->adev; - if (amdgpu_sriov_vf(smu->adev)) + /* Navy_Flounder do not support to change display num currently */ + if (adev->asic_type == CHIP_NAVY_FLOUNDER) return 0; if (!smu->pm_enabled) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, count, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, count, NULL); return ret; } @@ -860,21 +706,18 @@ int smu_v11_0_set_allowed_mask(struct smu_context *smu) int ret = 0; uint32_t feature_mask[2]; - if (amdgpu_sriov_vf(smu->adev)) - return 0; - mutex_lock(&feature->mutex); if (bitmap_empty(feature->allowed, SMU_FEATURE_MAX) || feature->feature_num < 64) goto failed; bitmap_copy((unsigned long *)feature_mask, feature->allowed, 64); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskHigh, feature_mask[1], NULL); if (ret) goto failed; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskLow, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetAllowedFeaturesMaskLow, feature_mask[0], NULL); if (ret) goto failed; @@ -884,38 +727,6 @@ failed: return ret; } -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 (amdgpu_sriov_vf(smu->adev) && !amdgpu_sriov_is_pp_one_vf(smu->adev)) - return 0; - - if (!feature_mask || num < 2) - return -EINVAL; - - if (bitmap_empty(feature->enabled, feature->feature_num)) { - ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesHigh, &feature_mask_high); - if (ret) - return ret; - - ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow, &feature_mask_low); - if (ret) - return ret; - - 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; -} - int smu_v11_0_system_features_control(struct smu_context *smu, bool en) { @@ -923,7 +734,7 @@ int smu_v11_0_system_features_control(struct smu_context *smu, uint32_t feature_mask[2]; int ret = 0; - ret = smu_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : + ret = smu_cmn_send_smc_msg(smu, (en ? SMU_MSG_EnableAllSmuFeatures : SMU_MSG_DisableAllSmuFeatures), NULL); if (ret) return ret; @@ -932,7 +743,7 @@ int smu_v11_0_system_features_control(struct smu_context *smu, bitmap_zero(feature->supported, feature->feature_num); if (en) { - ret = smu_feature_get_enabled_mask(smu, feature_mask, 2); + ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2); if (ret) return ret; @@ -949,15 +760,12 @@ int smu_v11_0_notify_display_change(struct smu_context *smu) { int ret = 0; - if (amdgpu_sriov_vf(smu->adev)) - return 0; - if (!smu->pm_enabled) return ret; - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT) && smu->adev->gmc.vram_type == AMDGPU_VRAM_TYPE_HBM) - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetUclkFastSwitch, 1, NULL); return ret; } @@ -969,18 +777,20 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, int ret = 0; int clk_id; - if ((smu_msg_get_index(smu, SMU_MSG_GetDcModeMaxDpmFreq) < 0) || - (smu_msg_get_index(smu, SMU_MSG_GetMaxDpmFreq) < 0)) + if ((smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetDcModeMaxDpmFreq) < 0) || + (smu_cmn_to_asic_specific_index(smu, CMN2ASIC_MAPPING_MSG, SMU_MSG_GetMaxDpmFreq) < 0)) return 0; - clk_id = smu_clk_get_index(smu, clock_select); + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clock_select); if (clk_id < 0) return -EINVAL; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetDcModeMaxDpmFreq, clk_id << 16, clock); if (ret) { - pr_err("[GetMaxSustainableClock] Failed to get max DC clock from SMC!"); + dev_err(smu->adev->dev, "[GetMaxSustainableClock] Failed to get max DC clock from SMC!"); return ret; } @@ -988,10 +798,10 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, return 0; /* if DC limit is zero, return AC limit */ - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, clk_id << 16, clock); if (ret) { - pr_err("[GetMaxSustainableClock] failed to get max AC clock from SMC!"); + dev_err(smu->adev->dev, "[GetMaxSustainableClock] failed to get max AC clock from SMC!"); return ret; } @@ -1000,17 +810,10 @@ smu_v11_0_get_max_sustainable_clock(struct smu_context *smu, uint32_t *clock, int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) { - struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks; + struct smu_11_0_max_sustainable_clocks *max_sustainable_clocks = + smu->smu_table.max_sustainable_clocks; int ret = 0; - if (!smu->smu_table.max_sustainable_clocks) - max_sustainable_clocks = kzalloc(sizeof(struct smu_11_0_max_sustainable_clocks), - GFP_KERNEL); - else - max_sustainable_clocks = smu->smu_table.max_sustainable_clocks; - - smu->smu_table.max_sustainable_clocks = (void *)max_sustainable_clocks; - max_sustainable_clocks->uclock = smu->smu_table.boot_values.uclk / 100; max_sustainable_clocks->soc_clock = smu->smu_table.boot_values.socclk / 100; max_sustainable_clocks->dcef_clock = smu->smu_table.boot_values.dcefclk / 100; @@ -1018,34 +821,34 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) max_sustainable_clocks->phy_clock = 0xFFFFFFFF; max_sustainable_clocks->pixel_clock = 0xFFFFFFFF; - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { ret = smu_v11_0_get_max_sustainable_clock(smu, &(max_sustainable_clocks->uclock), SMU_UCLK); if (ret) { - pr_err("[%s] failed to get max UCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max UCLK from SMC!", __func__); return ret; } } - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { ret = smu_v11_0_get_max_sustainable_clock(smu, &(max_sustainable_clocks->soc_clock), SMU_SOCCLK); if (ret) { - pr_err("[%s] failed to get max SOCCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max SOCCLK from SMC!", __func__); return ret; } } - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { ret = smu_v11_0_get_max_sustainable_clock(smu, &(max_sustainable_clocks->dcef_clock), SMU_DCEFCLK); if (ret) { - pr_err("[%s] failed to get max DCEFCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max DCEFCLK from SMC!", __func__); return ret; } @@ -1054,7 +857,7 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) &(max_sustainable_clocks->display_clock), SMU_DISPCLK); if (ret) { - pr_err("[%s] failed to get max DISPCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max DISPCLK from SMC!", __func__); return ret; } @@ -1062,7 +865,7 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) &(max_sustainable_clocks->phy_clock), SMU_PHYCLK); if (ret) { - pr_err("[%s] failed to get max PHYCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max PHYCLK from SMC!", __func__); return ret; } @@ -1070,7 +873,7 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) &(max_sustainable_clocks->pixel_clock), SMU_PIXCLK); if (ret) { - pr_err("[%s] failed to get max PIXCLK from SMC!", + dev_err(smu->adev->dev, "[%s] failed to get max PIXCLK from SMC!", __func__); return ret; } @@ -1082,190 +885,64 @@ int smu_v11_0_init_max_sustainable_clocks(struct smu_context *smu) return 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; - - 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; - } +int smu_v11_0_get_current_power_limit(struct smu_context *smu, + uint32_t *power_limit) +{ + int power_src; + int ret = 0; - if (smu->od_enabled) { - od_limit = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]); + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) + return -EINVAL; - pr_debug("ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_limit, smu->default_power_limit); + power_src = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_PWR, + smu->adev->pm.ac_power ? + SMU_POWER_SOURCE_AC : + SMU_POWER_SOURCE_DC); + if (power_src < 0) + return -EINVAL; - max_power_limit *= (100 + od_limit); - max_power_limit /= 100; - } + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetPptLimit, + power_src << 16, + power_limit); + if (ret) + dev_err(smu->adev->dev, "[%s] get PPT limit failed!", __func__); - return max_power_limit; + return ret; } int smu_v11_0_set_power_limit(struct smu_context *smu, uint32_t n) { int ret = 0; - uint32_t max_power_limit; - - if (amdgpu_sriov_vf(smu->adev)) - return 0; - - 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; - - if (!smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { - pr_err("Setting new power limit is not supported!\n"); + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT)) { + dev_err(smu->adev->dev, "Setting new power limit is not supported!\n"); return -EOPNOTSUPP; } - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetPptLimit, n, NULL); if (ret) { - pr_err("[%s] Set power limit Failed!\n", __func__); + dev_err(smu->adev->dev, "[%s] Set power limit Failed!\n", __func__); return ret; } - smu->power_limit = n; - - return 0; -} - -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) - ret = smu_get_current_clk_freq_by_table(smu, clk_id, &freq); - else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetDpmClockFreq, - (asic_clk_id << 16), &freq); - if (ret) - return ret; - } - - freq *= 100; - *value = freq; - - return ret; -} - -static int smu_v11_0_set_thermal_range(struct smu_context *smu, - 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; - - 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; - val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 0); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 0); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high & 0xff)); - val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low & 0xff)); - val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); - - WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val); + smu->current_power_limit = n; return 0; } -static int smu_v11_0_enable_thermal_alert(struct smu_context *smu) +int smu_v11_0_enable_thermal_alert(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - uint32_t val = 0; - - val |= (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT); - val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT); - val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT); - - WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val); + if (smu->smu_table.thermal_controller_type) + return amdgpu_irq_get(smu->adev, &smu->irq_source, 0); return 0; } -int smu_v11_0_start_thermal_control(struct smu_context *smu) -{ - int ret = 0; - struct smu_temperature_range range; - struct amdgpu_device *adev = smu->adev; - - 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); - if (ret) - return ret; - - ret = smu_v11_0_enable_thermal_alert(smu); - if (ret) - return ret; - - ret = smu_set_thermal_fan_table(smu); - if (ret) - return ret; - } - - 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) +int smu_v11_0_disable_thermal_alert(struct smu_context *smu) { - struct amdgpu_device *adev = smu->adev; - - WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0); - - return 0; + return amdgpu_irq_put(smu->adev, &smu->irq_source, 0); } static uint16_t convert_to_vddc(uint8_t vid) @@ -1273,7 +950,7 @@ static uint16_t convert_to_vddc(uint8_t vid) return (uint16_t) ((6200 - (vid * 25)) / SMU11_VOLTAGE_SCALE); } -static int smu_v11_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) +int smu_v11_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) { struct amdgpu_device *adev = smu->adev; uint32_t vdd = 0, val_vid = 0; @@ -1292,43 +969,6 @@ static int smu_v11_0_get_gfx_vdd(struct smu_context *smu, uint32_t *value) } -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); - *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_VDDGFX: - ret = smu_v11_0_get_gfx_vdd(smu, (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; -} - int smu_v11_0_display_clock_voltage_request(struct smu_context *smu, struct pp_display_clock_request @@ -1339,8 +979,8 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, enum smu_clk_type clk_select = 0; uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) || - smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { + if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) || + smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { switch (clk_type) { case amd_pp_dcef_clock: clk_select = SMU_DCEFCLK; @@ -1358,7 +998,7 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, clk_select = SMU_UCLK; break; default: - pr_info("[%s] Invalid Clock Type!", __func__); + dev_info(smu->adev->dev, "[%s] Invalid Clock Type!", __func__); ret = -EINVAL; break; } @@ -1369,7 +1009,7 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, if (clk_select == SMU_UCLK && smu->disable_uclk_switch) return 0; - ret = smu_set_hard_freq_range(smu, clk_select, clk_freq, 0); + ret = smu_v11_0_set_hard_freq_limited_range(smu, clk_select, clk_freq, 0); if(clk_select == SMU_UCLK) smu->hard_min_uclk_req_from_dal = clk_freq; @@ -1385,17 +1025,17 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) struct amdgpu_device *adev = smu->adev; switch (adev->asic_type) { - case CHIP_VEGA20: - break; case CHIP_NAVI10: case CHIP_NAVI14: case CHIP_NAVI12: + case CHIP_SIENNA_CICHLID: + case CHIP_NAVY_FLOUNDER: if (!(adev->pm.pp_feature & PP_GFXOFF_MASK)) return 0; if (enable) - ret = smu_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL); else - ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL); break; default: break; @@ -1407,7 +1047,7 @@ int smu_v11_0_gfx_off_control(struct smu_context *smu, bool enable) uint32_t smu_v11_0_get_fan_control_mode(struct smu_context *smu) { - if (!smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) + if (!smu_cmn_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) return AMD_FAN_CTRL_MANUAL; else return AMD_FAN_CTRL_AUTO; @@ -1418,12 +1058,12 @@ 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)) + if (!smu_cmn_feature_is_supported(smu, SMU_FEATURE_FAN_CONTROL_BIT)) return 0; - ret = smu_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, auto_fan_control); + ret = smu_cmn_feature_set_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT, auto_fan_control); if (ret) - pr_err("[%s]%s smc FAN CONTROL feature failed!", + dev_err(smu->adev->dev, "[%s]%s smc FAN CONTROL feature failed!", __func__, (auto_fan_control ? "Start" : "Stop")); return ret; @@ -1494,7 +1134,7 @@ smu_v11_0_set_fan_control_mode(struct smu_context *smu, } if (ret) { - pr_err("[%s]Set fan control mode failed!", __func__); + dev_err(smu->adev->dev, "[%s]Set fan control mode failed!", __func__); return -EINVAL; } @@ -1531,16 +1171,81 @@ int smu_v11_0_set_xgmi_pstate(struct smu_context *smu, uint32_t pstate) { int ret = 0; - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetXgmiMode, pstate ? XGMI_MODE_PSTATE_D0 : XGMI_MODE_PSTATE_D3, NULL); return ret; } +static int smu_v11_0_set_irq_state(struct amdgpu_device *adev, + struct amdgpu_irq_src *source, + unsigned tyep, + enum amdgpu_interrupt_state state) +{ + struct smu_context *smu = &adev->smu; + uint32_t low, high; + uint32_t val = 0; + + switch (state) { + case AMDGPU_IRQ_STATE_DISABLE: + /* For THM irqs */ + val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 1); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 1); + WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val); + + WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, 0); + + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 1); + WREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL, val); + + break; + case AMDGPU_IRQ_STATE_ENABLE: + /* For THM irqs */ + low = max(SMU_THERMAL_MINIMUM_ALERT_TEMP, + smu->thermal_range.min / SMU_TEMPERATURE_UNITS_PER_CENTIGRADES); + high = min(SMU_THERMAL_MAXIMUM_ALERT_TEMP, + smu->thermal_range.software_shutdown_temp); + + val = RREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, MAX_IH_CREDIT, 5); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_IH_HW_ENA, 1); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTH_MASK, 0); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, THERM_INTL_MASK, 0); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTH, (high & 0xff)); + val = REG_SET_FIELD(val, THM_THERMAL_INT_CTRL, DIG_THERM_INTL, (low & 0xff)); + val = val & (~THM_THERMAL_INT_CTRL__THERM_TRIGGER_MASK_MASK); + WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_CTRL, val); + + val = (1 << THM_THERMAL_INT_ENA__THERM_INTH_CLR__SHIFT); + val |= (1 << THM_THERMAL_INT_ENA__THERM_INTL_CLR__SHIFT); + val |= (1 << THM_THERMAL_INT_ENA__THERM_TRIGGER_CLR__SHIFT); + WREG32_SOC15(THM, 0, mmTHM_THERMAL_INT_ENA, val); + + /* For MP1 SW irqs */ + val = RREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, ID, 0xFE); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT, VALID, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT, val); + + val = RREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL); + val = REG_SET_FIELD(val, MP1_SMN_IH_SW_INT_CTRL, INT_MASK, 0); + WREG32_SOC15(MP1, 0, mmMP1_SMN_IH_SW_INT_CTRL, val); + + break; + default: + break; + } + + return 0; +} + static int smu_v11_0_ack_ac_dc_interrupt(struct smu_context *smu) { - return smu_send_smc_msg(smu, + return smu_cmn_send_smc_msg(smu, SMU_MSG_ReenableAcDcInterrupt, NULL); } @@ -1554,6 +1259,7 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, struct amdgpu_irq_src *source, struct amdgpu_iv_entry *entry) { + struct smu_context *smu = &adev->smu; uint32_t client_id = entry->client_id; uint32_t src_id = entry->src_id; /* @@ -1605,6 +1311,14 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, dev_dbg(adev->dev, "Switched to DC mode!\n"); smu_v11_0_ack_ac_dc_interrupt(&adev->smu); break; + case 0x7: + if (!atomic_read(&adev->throttling_logging_enabled)) + return 0; + + if (__ratelimit(&adev->throttling_logging_rs)) + schedule_work(&smu->throttling_logging_work); + + break; } } } @@ -1614,24 +1328,17 @@ static int smu_v11_0_irq_process(struct amdgpu_device *adev, static const struct amdgpu_irq_src_funcs smu_v11_0_irq_funcs = { + .set = smu_v11_0_set_irq_state, .process = smu_v11_0_irq_process, }; 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; + struct amdgpu_irq_src *irq_src = &smu->irq_source; int ret = 0; - /* already register */ - if (irq_src) - return 0; - - irq_src = kzalloc(sizeof(struct amdgpu_irq_src), GFP_KERNEL); - if (!irq_src) - return -ENOMEM; - smu->irq_source = irq_src; - + irq_src->num_types = 1; irq_src->funcs = &smu_v11_0_irq_funcs; ret = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_THM, @@ -1696,14 +1403,14 @@ int smu_v11_0_set_azalia_d3_pme(struct smu_context *smu) { int ret = 0; - ret = smu_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_BacoAudioD3PME, NULL); return ret; } static int smu_v11_0_baco_set_armd3_sequence(struct smu_context *smu, enum smu_v11_0_baco_seq baco_seq) { - return smu_send_smc_msg_with_param(smu, SMU_MSG_ArmD3, baco_seq, NULL); + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_ArmD3, baco_seq, NULL); } bool smu_v11_0_baco_is_support(struct smu_context *smu) @@ -1719,8 +1426,8 @@ bool smu_v11_0_baco_is_support(struct smu_context *smu) return false; /* 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)) + if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_BACO_BIT) && + !smu_cmn_feature_is_enabled(smu, SMU_FEATURE_BACO_BIT)) return false; return true; @@ -1757,21 +1464,15 @@ int smu_v11_0_baco_set_state(struct smu_context *smu, enum smu_baco_state state) data |= 0x80000000; WREG32_SOC15(THM, 0, mmTHM_BACO_CNTL, data); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 0, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 0, NULL); } else { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 1, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnterBaco, 1, NULL); } } else { - ret = smu_send_smc_msg(smu, SMU_MSG_ExitBaco, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_ExitBaco, NULL); if (ret) goto out; - if (ras && ras->supported) { - ret = smu_send_smc_msg(smu, SMU_MSG_PrepareMp1ForUnload, NULL); - if (ret) - goto out; - } - /* 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); @@ -1817,13 +1518,54 @@ int smu_v11_0_baco_exit(struct smu_context *smu) return ret; } +int smu_v11_0_mode1_reset(struct smu_context *smu) +{ + int ret = 0; + + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode1Reset, NULL); + if (!ret) + msleep(SMU11_MODE1_RESET_WAIT_TIME_IN_MS); + + return ret; +} + 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; + uint32_t clock_limit; - clk_id = smu_clk_get_index(smu, clk_type); + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) { + switch (clk_type) { + case SMU_MCLK: + case SMU_UCLK: + clock_limit = smu->smu_table.boot_values.uclk; + break; + case SMU_GFXCLK: + case SMU_SCLK: + clock_limit = smu->smu_table.boot_values.gfxclk; + break; + case SMU_SOCCLK: + clock_limit = smu->smu_table.boot_values.socclk; + break; + default: + clock_limit = 0; + break; + } + + /* clock in Mhz unit */ + if (min) + *min = clock_limit / 100; + if (max) + *max = clock_limit / 100; + + return 0; + } + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); if (clk_id < 0) { ret = -EINVAL; goto failed; @@ -1831,13 +1573,13 @@ int smu_v11_0_get_dpm_ultimate_freq(struct smu_context *smu, enum smu_clk_type c param = (clk_id & 0xffff) << 16; if (max) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, param, max); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMaxDpmFreq, param, max); if (ret) goto failed; } if (min) { - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param, min); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GetMinDpmFreq, param, min); if (ret) goto failed; } @@ -1846,147 +1588,187 @@ 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 smu_v11_0_set_soft_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) { + struct amdgpu_device *adev = smu->adev; int ret = 0, clk_id = 0; uint32_t param; - clk_id = smu_clk_get_index(smu, clk_type); + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); if (clk_id < 0) return clk_id; + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, false); + if (max > 0) { param = (uint32_t)((clk_id << 16) | (max & 0xffff)); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxByFreq, param, NULL); if (ret) - return ret; + goto out; } if (min > 0) { param = (uint32_t)((clk_id << 16) | (min & 0xffff)); - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMinByFreq, param, NULL); if (ret) - return ret; + goto out; } +out: + if (clk_type == SMU_GFXCLK) + amdgpu_gfx_off_ctrl(adev, true); + return ret; } -int smu_v11_0_override_pcie_parameters(struct smu_context *smu) +int smu_v11_0_set_hard_freq_limited_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t min, + uint32_t max) { - struct amdgpu_device *adev = smu->adev; - uint32_t pcie_gen = 0, pcie_width = 0; - int ret; - - if (amdgpu_sriov_vf(smu->adev)) - return 0; - - 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__); + int ret = 0, clk_id = 0; + uint32_t param; - return ret; + if (min <= 0 && max <= 0) + return -EINVAL; -} + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; -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; + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; - 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"); + if (max > 0) { + param = (uint32_t)((clk_id << 16) | (max & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMaxByFreq, + param, NULL); + if (ret) 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; + + if (min > 0) { + param = (uint32_t)((clk_id << 16) | (min & 0xffff)); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinByFreq, + param, NULL); + if (ret) + return ret; } + return ret; } int smu_v11_0_set_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) { + struct smu_11_0_dpm_context *dpm_context = + smu->smu_dpm.dpm_context; + struct smu_11_0_dpm_table *gfx_table = + &dpm_context->dpm_tables.gfx_table; + struct smu_11_0_dpm_table *mem_table = + &dpm_context->dpm_tables.uclk_table; + struct smu_11_0_dpm_table *soc_table = + &dpm_context->dpm_tables.soc_table; + struct smu_umd_pstate_table *pstate_table = + &smu->pstate_table; + struct amdgpu_device *adev = smu->adev; + uint32_t sclk_min = 0, sclk_max = 0; + uint32_t mclk_min = 0, mclk_max = 0; + uint32_t socclk_min = 0, socclk_max = 0; 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); + sclk_min = sclk_max = gfx_table->max; + mclk_min = mclk_max = mem_table->max; + socclk_min = socclk_max = soc_table->max; break; case AMD_DPM_FORCED_LEVEL_LOW: - ret = smu_force_dpm_limit_value(smu, false); + sclk_min = sclk_max = gfx_table->min; + mclk_min = mclk_max = mem_table->min; + socclk_min = socclk_max = soc_table->min; break; case AMD_DPM_FORCED_LEVEL_AUTO: + sclk_min = gfx_table->min; + sclk_max = gfx_table->max; + mclk_min = mem_table->min; + mclk_max = mem_table->max; + socclk_min = soc_table->min; + socclk_max = soc_table->max; + break; case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: - ret = smu_unforce_dpm_levels(smu); + sclk_min = sclk_max = pstate_table->gfxclk_pstate.standard; + mclk_min = mclk_max = pstate_table->uclk_pstate.standard; + socclk_min = socclk_max = pstate_table->socclk_pstate.standard; break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + sclk_min = sclk_max = pstate_table->gfxclk_pstate.min; + break; case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + mclk_min = mclk_max = pstate_table->uclk_pstate.min; + break; 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); + sclk_min = sclk_max = pstate_table->gfxclk_pstate.peak; + mclk_min = mclk_max = pstate_table->uclk_pstate.peak; + socclk_min = socclk_max = pstate_table->socclk_pstate.peak; break; case AMD_DPM_FORCED_LEVEL_MANUAL: case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: + return 0; default: - break; + dev_err(adev->dev, "Invalid performance level %d\n", level); + return -EINVAL; } + + /* + * Separate MCLK and SOCCLK soft min/max settings are not allowed + * on Arcturus. + */ + if (adev->asic_type == CHIP_ARCTURUS) { + mclk_min = mclk_max = 0; + socclk_min = socclk_max = 0; + } + + if (sclk_min && sclk_max) { + ret = smu_v11_0_set_soft_freq_limited_range(smu, + SMU_GFXCLK, + sclk_min, + sclk_max); + if (ret) + return ret; + } + + if (mclk_min && mclk_max) { + ret = smu_v11_0_set_soft_freq_limited_range(smu, + SMU_MCLK, + mclk_min, + mclk_max); + if (ret) + return ret; + } + + if (socclk_min && socclk_max) { + ret = smu_v11_0_set_soft_freq_limited_range(smu, + SMU_SOCCLK, + socclk_min, + socclk_max); + if (ret) + return ret; + } + return ret; } @@ -1995,13 +1777,139 @@ int smu_v11_0_set_power_source(struct smu_context *smu, { int pwr_source; - pwr_source = smu_power_get_index(smu, (uint32_t)power_src); + pwr_source = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_PWR, + (uint32_t)power_src); if (pwr_source < 0) return -EINVAL; - return smu_send_smc_msg_with_param(smu, + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NotifyPowerSource, pwr_source, NULL); } +int smu_v11_0_get_dpm_freq_by_index(struct smu_context *smu, + enum smu_clk_type clk_type, + uint16_t level, + uint32_t *value) +{ + int ret = 0, clk_id = 0; + uint32_t param; + + if (!value) + return -EINVAL; + + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + + clk_id = smu_cmn_to_asic_specific_index(smu, + CMN2ASIC_MAPPING_CLK, + clk_type); + if (clk_id < 0) + return clk_id; + + param = (uint32_t)(((clk_id & 0xffff) << 16) | (level & 0xffff)); + + ret = smu_cmn_send_smc_msg_with_param(smu, + SMU_MSG_GetDpmFreqByIndex, + param, + value); + if (ret) + return ret; + + /* + * BIT31: 0 - Fine grained DPM, 1 - Dicrete DPM + * now, we un-support it + */ + *value = *value & 0x7fffffff; + + return ret; +} + +int smu_v11_0_get_dpm_level_count(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *value) +{ + return smu_v11_0_get_dpm_freq_by_index(smu, + clk_type, + 0xff, + value); +} + +int smu_v11_0_set_single_dpm_table(struct smu_context *smu, + enum smu_clk_type clk_type, + struct smu_11_0_dpm_table *single_dpm_table) +{ + int ret = 0; + uint32_t clk; + int i; + + ret = smu_v11_0_get_dpm_level_count(smu, + clk_type, + &single_dpm_table->count); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get dpm levels!\n", __func__); + return ret; + } + + for (i = 0; i < single_dpm_table->count; i++) { + ret = smu_v11_0_get_dpm_freq_by_index(smu, + clk_type, + i, + &clk); + if (ret) { + dev_err(smu->adev->dev, "[%s] failed to get dpm freq by index!\n", __func__); + return ret; + } + + single_dpm_table->dpm_levels[i].value = clk; + single_dpm_table->dpm_levels[i].enabled = true; + + if (i == 0) + single_dpm_table->min = clk; + else if (i == single_dpm_table->count - 1) + single_dpm_table->max = clk; + } + + return 0; +} + +int smu_v11_0_get_dpm_level_range(struct smu_context *smu, + enum smu_clk_type clk_type, + uint32_t *min_value, + uint32_t *max_value) +{ + uint32_t level_count = 0; + int ret = 0; + + if (!min_value && !max_value) + return -EINVAL; + + if (min_value) { + /* by default, level 0 clock value as min value */ + ret = smu_v11_0_get_dpm_freq_by_index(smu, + clk_type, + 0, + min_value); + if (ret) + return ret; + } + + if (max_value) { + ret = smu_v11_0_get_dpm_level_count(smu, + clk_type, + &level_count); + if (ret) + return ret; + + ret = smu_v11_0_get_dpm_freq_by_index(smu, + clk_type, + level_count - 1, + max_value); + if (ret) + return ret; + } + + return ret; +} diff --git a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c index 4023d10fb49b..31456437bb18 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v12_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v12_0.c @@ -20,21 +20,33 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#define SWSMU_CODE_LAYER_L3 + #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 "smu_cmn.h" #include "asic_reg/mp/mp_12_0_0_offset.h" #include "asic_reg/mp/mp_12_0_0_sh_mask.h" #include "asic_reg/smuio/smuio_12_0_0_offset.h" #include "asic_reg/smuio/smuio_12_0_0_sh_mask.h" +/* + * DO NOT use these for err/warn/info/debug messages. + * Use dev_err, dev_warn, dev_info and dev_dbg instead. + * They are more MGPU friendly. + */ +#undef pr_err +#undef pr_warn +#undef pr_info +#undef pr_debug + // because some SMU12 based ASICs use older ip offset tables // we should undefine this register from the smuio12 header // to prevent confusion down the road @@ -42,86 +54,6 @@ #define smnMP1_FIRMWARE_FLAGS 0x3010024 -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; -} - -static 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, - uint32_t *read_arg) -{ - struct amdgpu_device *adev = smu->adev; - int ret = 0, index = 0; - - index = smu_msg_get_index(smu, msg); - if (index < 0) - return index; - - mutex_lock(&smu->message_lock); - 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"); - goto out; - } - - 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); - goto out; - } - if (read_arg) { - ret = smu_v12_0_read_arg(smu, read_arg); - if (ret) { - pr_err("Failed to read message arg 0x%x, response 0x%x param 0x%x\n", - index, ret, param); - goto out; - } - } -out: - mutex_unlock(&smu->message_lock); - return ret; -} - int smu_v12_0_check_fw_status(struct smu_context *smu) { struct amdgpu_device *adev = smu->adev; @@ -144,7 +76,7 @@ int smu_v12_0_check_fw_version(struct smu_context *smu) uint8_t smu_minor, smu_debug; int ret = 0; - ret = smu_get_smc_version(smu, &if_version, &smu_version); + ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version); if (ret) return ret; @@ -161,11 +93,11 @@ int smu_v12_0_check_fw_version(struct smu_context *smu) * of halt driver loading. */ if (if_version != smu->smc_driver_if_version) { - pr_info("smu driver if version = 0x%08x, smu fw if version = 0x%08x, " + dev_info(smu->adev->dev, "smu driver if version = 0x%08x, smu fw if version = 0x%08x, " "smu fw version = 0x%08x (%d.%d.%d)\n", smu->smc_driver_if_version, if_version, smu_version, smu_major, smu_minor, smu_debug); - pr_warn("SMU driver if version not matched\n"); + dev_warn(smu->adev->dev, "SMU driver if version not matched\n"); } return ret; @@ -177,31 +109,9 @@ int smu_v12_0_powergate_sdma(struct smu_context *smu, bool gate) return 0; if (gate) - return smu_send_smc_msg(smu, SMU_MSG_PowerDownSdma, NULL); - else - return smu_send_smc_msg(smu, SMU_MSG_PowerUpSdma, NULL); -} - -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, NULL); + return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownSdma, NULL); else - return smu_send_smc_msg(smu, SMU_MSG_PowerUpVcn, NULL); -} - -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, NULL); - else - return smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpJpeg, 0, NULL); + return smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpSdma, NULL); } int smu_v12_0_set_gfx_cgpg(struct smu_context *smu, bool enable) @@ -209,45 +119,12 @@ 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, + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetGfxCGPG, enable ? 1 : 0, NULL); } -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 * @@ -278,10 +155,10 @@ 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, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_AllowGfxOff, NULL); } else { - ret = smu_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL); + ret = smu_cmn_send_smc_msg(smu, SMU_MSG_DisallowGfxOff, NULL); /* confirm gfx is back to "on" state, timeout is 0.5 second */ while (!(smu_v12_0_get_gfxoff_status(smu) == 2)) { @@ -297,164 +174,31 @@ int smu_v12_0_gfx_off_control(struct smu_context *smu, bool enable) 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; + kfree(smu_table->metrics_table); + smu_table->metrics_table = NULL; - return smu_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); -} + kfree(smu_table->watermarks_table); + smu_table->watermarks_table = NULL; -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, &feature_mask_high); - if (ret) - return ret; - - ret = smu_send_smc_msg(smu, SMU_MSG_GetEnabledSmuFeaturesLow, &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; + return 0; } -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_set_default_dpm_tables(struct smu_context *smu) { - 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, max); - if (ret) { - pr_err("Attempt to get max GX frequency from SMC Failed !\n"); - 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; - } - } + struct smu_table_context *smu_table = &smu->smu_table; - if (min) { - switch (clk_type) { - case SMU_GFXCLK: - case SMU_SCLK: - ret = smu_send_smc_msg(smu, SMU_MSG_GetMinGfxclkFrequency, min); - if (ret) { - pr_err("Attempt to get min GX frequency from SMC Failed !\n"); - 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; + return smu_cmn_update_table(smu, SMU_TABLE_DPMCLOCKS, 0, smu_table->clocks_table, false); } 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, NULL); + return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_GfxDeviceDriverReset, SMU_RESET_MODE_2, NULL); } int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_type clk_type, @@ -462,42 +206,45 @@ int smu_v12_0_set_soft_freq_limited_range(struct smu_context *smu, enum smu_clk_ { int ret = 0; + if (!smu_cmn_clk_dpm_is_enabled(smu, clk_type)) + return 0; + switch (clk_type) { case SMU_GFXCLK: case SMU_SCLK: - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinGfxClk, min, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxGfxClk, max, NULL); if (ret) return ret; break; case SMU_FCLK: case SMU_MCLK: - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinFclkByFreq, min, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxFclkByFreq, max, NULL); if (ret) return ret; break; case SMU_SOCCLK: - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinSocclkByFreq, min, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxSocclkByFreq, max, NULL); if (ret) return ret; break; case SMU_VCLK: - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetHardMinVcn, min, NULL); if (ret) return ret; - ret = smu_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max, NULL); + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetSoftMaxVcn, max, NULL); if (ret) return ret; break; @@ -514,12 +261,12 @@ int smu_v12_0_set_driver_table_location(struct smu_context *smu) int ret = 0; if (driver_table->mc_address) { - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrHigh, upper_32_bits(driver_table->mc_address), NULL); if (!ret) - ret = smu_send_smc_msg_with_param(smu, + ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetDriverDramAddrLow, lower_32_bits(driver_table->mc_address), NULL); diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c index 56923a96b450..c18169aa59ce 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/ci_smumgr.c @@ -183,7 +183,7 @@ static int ci_program_jump_on_start(struct pp_hwmgr *hwmgr) return 0; } -bool ci_is_smc_ram_running(struct pp_hwmgr *hwmgr) +static bool ci_is_smc_ram_running(struct pp_hwmgr *hwmgr) { return ((0 == PHM_READ_VFPF_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SMC_SYSCON_CLOCK_CNTL_0, ck_disable)) @@ -2725,7 +2725,10 @@ static int ci_initialize_mc_reg_table(struct pp_hwmgr *hwmgr) static bool ci_is_dpm_running(struct pp_hwmgr *hwmgr) { - return ci_is_smc_ram_running(hwmgr); + return (1 == PHM_READ_INDIRECT_FIELD(hwmgr->device, + CGS_IND_REG__SMC, FEATURE_STATUS, + VOLTAGE_CONTROLLER_ON)) + ? true : false; } static int ci_smu_init(struct pp_hwmgr *hwmgr) diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c index 398e7e3587de..4bfadb49521b 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/tonga_smumgr.c @@ -1083,7 +1083,7 @@ static int tonga_populate_single_memory_level( return result; } -int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr) +static int tonga_populate_all_memory_levels(struct pp_hwmgr *hwmgr) { struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend); struct tonga_smumgr *smu_data = diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c index 2fb97554134f..cf43629d29d2 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vega20_smumgr.c @@ -522,7 +522,7 @@ static int vega20_smu_init(struct pp_hwmgr *hwmgr) priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].version = 0x01; priv->smu_tables.entry[TABLE_ACTIVITY_MONITOR_COEFF].size = sizeof(DpmActivityMonitorCoeffInt_t); - ret = smu_v11_0_i2c_eeprom_control_init(&adev->pm.smu_i2c); + ret = smu_v11_0_i2c_control_init(&adev->pm.smu_i2c); if (ret) goto err4; @@ -560,7 +560,7 @@ static int vega20_smu_fini(struct pp_hwmgr *hwmgr) (struct vega20_smumgr *)(hwmgr->smu_backend); struct amdgpu_device *adev = hwmgr->adev; - smu_v11_0_i2c_eeprom_control_fini(&adev->pm.smu_i2c); + smu_v11_0_i2c_control_fini(&adev->pm.smu_i2c); if (priv) { amdgpu_bo_free_kernel(&priv->smu_tables.entry[TABLE_PPTABLE].handle, diff --git a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c index 3da71a088b92..0ecc18b55ffb 100644 --- a/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c +++ b/drivers/gpu/drm/amd/powerplay/smumgr/vegam_smumgr.c @@ -644,9 +644,6 @@ static int vegam_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr, /* sclk is bigger than max sclk in the dependence table */ *voltage |= (dep_table->entries[i - 1].vddc * VOLTAGE_SCALE) << VDDC_SHIFT; - vddci = phm_find_closest_vddci(&(data->vddci_voltage_table), - (dep_table->entries[i - 1].vddc - - (uint16_t)VDDC_VDDCI_DELTA)); if (SMU7_VOLTAGE_CONTROL_NONE == data->vddci_control) *voltage |= (data->vbios_boot_state.vddci_bootup_value * @@ -654,8 +651,13 @@ static int vegam_get_dependency_volt_by_clk(struct pp_hwmgr *hwmgr, else if (dep_table->entries[i - 1].vddci) *voltage |= (dep_table->entries[i - 1].vddci * VOLTAGE_SCALE) << VDDC_SHIFT; - else + else { + vddci = phm_find_closest_vddci(&(data->vddci_voltage_table), + (dep_table->entries[i - 1].vddc - + (uint16_t)VDDC_VDDCI_DELTA)); + *voltage |= (vddci * VOLTAGE_SCALE) << VDDCI_SHIFT; + } if (SMU7_VOLTAGE_CONTROL_NONE == data->mvdd_control) *mvdd = data->vbios_boot_state.mvdd_bootup_value * VOLTAGE_SCALE; diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c deleted file mode 100644 index 61923530b2e4..000000000000 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c +++ /dev/null @@ -1,3288 +0,0 @@ -/* - * 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 <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.h" -#include "soc15_common.h" -#include "atom.h" -#include "power_state.h" -#include "vega20_ppt.h" -#include "vega20_pptable.h" -#include "vega20_ppsmc.h" -#include "nbio/nbio_7_4_offset.h" -#include "nbio/nbio_7_4_sh_mask.h" -#include "asic_reg/thm/thm_11_0_2_offset.h" -#include "asic_reg/thm/thm_11_0_2_sh_mask.h" - -#define smnPCIE_LC_SPEED_CNTL 0x11140290 -#define smnPCIE_LC_LINK_WIDTH_CNTL 0x11140288 - -#define CTF_OFFSET_EDGE 5 -#define CTF_OFFSET_HOTSPOT 5 -#define CTF_OFFSET_HBM 5 - -#define MSG_MAP(msg) \ - [SMU_MSG_##msg] = {1, PPSMC_MSG_##msg} - -#define SMC_DPM_FEATURE (FEATURE_DPM_PREFETCHER_MASK | \ - FEATURE_DPM_GFXCLK_MASK | \ - FEATURE_DPM_UCLK_MASK | \ - FEATURE_DPM_SOCCLK_MASK | \ - FEATURE_DPM_UVD_MASK | \ - FEATURE_DPM_VCE_MASK | \ - FEATURE_DPM_MP0CLK_MASK | \ - FEATURE_DPM_LINK_MASK | \ - FEATURE_DPM_DCEFCLK_MASK) - -static struct smu_11_0_cmn2aisc_mapping vega20_message_map[SMU_MSG_MAX_COUNT] = { - MSG_MAP(TestMessage), - MSG_MAP(GetSmuVersion), - MSG_MAP(GetDriverIfVersion), - MSG_MAP(SetAllowedFeaturesMaskLow), - MSG_MAP(SetAllowedFeaturesMaskHigh), - MSG_MAP(EnableAllSmuFeatures), - MSG_MAP(DisableAllSmuFeatures), - MSG_MAP(EnableSmuFeaturesLow), - MSG_MAP(EnableSmuFeaturesHigh), - MSG_MAP(DisableSmuFeaturesLow), - MSG_MAP(DisableSmuFeaturesHigh), - MSG_MAP(GetEnabledSmuFeaturesLow), - MSG_MAP(GetEnabledSmuFeaturesHigh), - MSG_MAP(SetWorkloadMask), - MSG_MAP(SetPptLimit), - MSG_MAP(SetDriverDramAddrHigh), - MSG_MAP(SetDriverDramAddrLow), - MSG_MAP(SetToolsDramAddrHigh), - MSG_MAP(SetToolsDramAddrLow), - MSG_MAP(TransferTableSmu2Dram), - MSG_MAP(TransferTableDram2Smu), - MSG_MAP(UseDefaultPPTable), - MSG_MAP(UseBackupPPTable), - MSG_MAP(RunBtc), - MSG_MAP(RequestI2CBus), - MSG_MAP(ReleaseI2CBus), - MSG_MAP(SetFloorSocVoltage), - MSG_MAP(SoftReset), - MSG_MAP(StartBacoMonitor), - MSG_MAP(CancelBacoMonitor), - MSG_MAP(EnterBaco), - MSG_MAP(SetSoftMinByFreq), - MSG_MAP(SetSoftMaxByFreq), - MSG_MAP(SetHardMinByFreq), - MSG_MAP(SetHardMaxByFreq), - MSG_MAP(GetMinDpmFreq), - MSG_MAP(GetMaxDpmFreq), - MSG_MAP(GetDpmFreqByIndex), - MSG_MAP(GetDpmClockFreq), - MSG_MAP(GetSsVoltageByDpm), - MSG_MAP(SetMemoryChannelConfig), - MSG_MAP(SetGeminiMode), - MSG_MAP(SetGeminiApertureHigh), - MSG_MAP(SetGeminiApertureLow), - MSG_MAP(SetMinLinkDpmByIndex), - MSG_MAP(OverridePcieParameters), - MSG_MAP(OverDriveSetPercentage), - MSG_MAP(SetMinDeepSleepDcefclk), - MSG_MAP(ReenableAcDcInterrupt), - MSG_MAP(NotifyPowerSource), - MSG_MAP(SetUclkFastSwitch), - MSG_MAP(SetUclkDownHyst), - MSG_MAP(GetCurrentRpm), - MSG_MAP(SetVideoFps), - MSG_MAP(SetTjMax), - MSG_MAP(SetFanTemperatureTarget), - MSG_MAP(PrepareMp1ForUnload), - MSG_MAP(DramLogSetDramAddrHigh), - MSG_MAP(DramLogSetDramAddrLow), - MSG_MAP(DramLogSetDramSize), - MSG_MAP(SetFanMaxRpm), - MSG_MAP(SetFanMinPwm), - MSG_MAP(ConfigureGfxDidt), - MSG_MAP(NumOfDisplays), - MSG_MAP(RemoveMargins), - MSG_MAP(ReadSerialNumTop32), - MSG_MAP(ReadSerialNumBottom32), - MSG_MAP(SetSystemVirtualDramAddrHigh), - MSG_MAP(SetSystemVirtualDramAddrLow), - MSG_MAP(WaflTest), - MSG_MAP(SetFclkGfxClkRatio), - MSG_MAP(AllowGfxOff), - MSG_MAP(DisallowGfxOff), - MSG_MAP(GetPptLimit), - MSG_MAP(GetDcModeMaxDpmFreq), - MSG_MAP(GetDebugData), - MSG_MAP(SetXgmiMode), - MSG_MAP(RunAfllBtc), - MSG_MAP(ExitBaco), - MSG_MAP(PrepareMp1ForReset), - MSG_MAP(PrepareMp1ForShutdown), - MSG_MAP(SetMGpuFanBoostLimitRpm), - MSG_MAP(GetAVFSVoltageByDpm), - MSG_MAP(DFCstateControl), -}; - -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), - CLK_MAP(ECLK, PPCLK_ECLK), - CLK_MAP(SOCCLK, PPCLK_SOCCLK), - CLK_MAP(UCLK, PPCLK_UCLK), - CLK_MAP(DCEFCLK, PPCLK_DCEFCLK), - CLK_MAP(DISPCLK, PPCLK_DISPCLK), - CLK_MAP(PIXCLK, PPCLK_PIXCLK), - CLK_MAP(PHYCLK, PPCLK_PHYCLK), - CLK_MAP(FCLK, PPCLK_FCLK), -}; - -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), - FEA_MAP(DPM_SOCCLK), - FEA_MAP(DPM_UVD), - FEA_MAP(DPM_VCE), - FEA_MAP(ULV), - FEA_MAP(DPM_MP0CLK), - FEA_MAP(DPM_LINK), - FEA_MAP(DPM_DCEFCLK), - FEA_MAP(DS_GFXCLK), - FEA_MAP(DS_SOCCLK), - FEA_MAP(DS_LCLK), - FEA_MAP(PPT), - FEA_MAP(TDC), - FEA_MAP(THERMAL), - FEA_MAP(GFX_PER_CU_CG), - FEA_MAP(RM), - FEA_MAP(DS_DCEFCLK), - FEA_MAP(ACDC), - FEA_MAP(VR0HOT), - FEA_MAP(VR1HOT), - FEA_MAP(FW_CTF), - FEA_MAP(LED_DISPLAY), - FEA_MAP(FAN_CONTROL), - FEA_MAP(GFX_EDC), - FEA_MAP(GFXOFF), - FEA_MAP(CG), - FEA_MAP(DPM_FCLK), - FEA_MAP(DS_FCLK), - FEA_MAP(DS_MP1CLK), - FEA_MAP(DS_MP0CLK), - FEA_MAP(XGMI), -}; - -static struct smu_11_0_cmn2aisc_mapping vega20_table_map[SMU_TABLE_COUNT] = { - TAB_MAP(PPTABLE), - TAB_MAP(WATERMARKS), - 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(ACTIVITY_MONITOR_COEFF), - TAB_MAP(OVERDRIVE), -}; - -static struct smu_11_0_cmn2aisc_mapping vega20_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { - PWR_MAP(AC), - PWR_MAP(DC), -}; - -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_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) -{ - struct smu_11_0_cmn2aisc_mapping mapping; - - if (index >= SMU_TABLE_COUNT) - return -EINVAL; - - mapping = vega20_table_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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 = vega20_pwr_src_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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 = vega20_feature_mask_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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 = vega20_clk_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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 = vega20_message_map[index]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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 = vega20_workload_map[profile]; - if (!(mapping.valid_mapping)) { - return -EINVAL; - } - - return mapping.map_to; -} - -static int vega20_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_WATERMARKS, sizeof(Watermarks_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_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_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_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; - - smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL); - if (!smu_table->watermarks_table) - return -ENOMEM; - - return 0; -} - -static int vega20_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 vega20_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 vega20_dpm_table), - GFP_KERNEL); - if (!smu_dpm->golden_dpm_context) - return -ENOMEM; - - smu_dpm->dpm_context_size = sizeof(struct vega20_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 vega20_setup_od8_information(struct smu_context *smu) -{ - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; - struct smu_table_context *table_context = &smu->smu_table; - struct vega20_od8_settings *od8_settings = (struct vega20_od8_settings *)smu->od_settings; - - uint32_t od_feature_count, od_feature_array_size, - od_setting_count, od_setting_array_size; - - if (!table_context->power_play_table) - return -EINVAL; - - powerplay_table = table_context->power_play_table; - - if (powerplay_table->OverDrive8Table.ucODTableRevision == 1) { - /* Setup correct ODFeatureCount, and store ODFeatureArray from - * powerplay table to od_feature_capabilities */ - od_feature_count = - (le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount) > - ATOM_VEGA20_ODFEATURE_COUNT) ? - ATOM_VEGA20_ODFEATURE_COUNT : - le32_to_cpu(powerplay_table->OverDrive8Table.ODFeatureCount); - - od_feature_array_size = sizeof(uint8_t) * od_feature_count; - - if (od8_settings->od_feature_capabilities) - return -EINVAL; - - od8_settings->od_feature_capabilities = kmemdup(&powerplay_table->OverDrive8Table.ODFeatureCapabilities, - od_feature_array_size, - GFP_KERNEL); - if (!od8_settings->od_feature_capabilities) - return -ENOMEM; - - /* Setup correct ODSettingCount, and store ODSettingArray from - * powerplay table to od_settings_max and od_setting_min */ - od_setting_count = - (le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount) > - ATOM_VEGA20_ODSETTING_COUNT) ? - ATOM_VEGA20_ODSETTING_COUNT : - le32_to_cpu(powerplay_table->OverDrive8Table.ODSettingCount); - - od_setting_array_size = sizeof(uint32_t) * od_setting_count; - - if (od8_settings->od_settings_max) - return -EINVAL; - - od8_settings->od_settings_max = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMax, - od_setting_array_size, - GFP_KERNEL); - - if (!od8_settings->od_settings_max) { - kfree(od8_settings->od_feature_capabilities); - od8_settings->od_feature_capabilities = NULL; - return -ENOMEM; - } - - if (od8_settings->od_settings_min) - return -EINVAL; - - od8_settings->od_settings_min = kmemdup(&powerplay_table->OverDrive8Table.ODSettingsMin, - od_setting_array_size, - GFP_KERNEL); - - if (!od8_settings->od_settings_min) { - kfree(od8_settings->od_feature_capabilities); - od8_settings->od_feature_capabilities = NULL; - kfree(od8_settings->od_settings_max); - od8_settings->od_settings_max = NULL; - return -ENOMEM; - } - } - - return 0; -} - -static int vega20_store_powerplay_table(struct smu_context *smu) -{ - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; - struct smu_table_context *table_context = &smu->smu_table; - - if (!table_context->power_play_table) - return -EINVAL; - - powerplay_table = table_context->power_play_table; - - memcpy(table_context->driver_pptable, &powerplay_table->smcPPTable, - sizeof(PPTable_t)); - - table_context->thermal_controller_type = powerplay_table->ucThermalControllerType; - - return 0; -} - -static int vega20_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_4 *smc_dpm_table; - int index, i, 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; - - smc_pptable->MaxVoltageStepGfx = smc_dpm_table->maxvoltagestepgfx; - smc_pptable->MaxVoltageStepSoc = smc_dpm_table->maxvoltagestepsoc; - - smc_pptable->VddGfxVrMapping = smc_dpm_table->vddgfxvrmapping; - smc_pptable->VddSocVrMapping = smc_dpm_table->vddsocvrmapping; - smc_pptable->VddMem0VrMapping = smc_dpm_table->vddmem0vrmapping; - smc_pptable->VddMem1VrMapping = smc_dpm_table->vddmem1vrmapping; - - smc_pptable->GfxUlvPhaseSheddingMask = smc_dpm_table->gfxulvphasesheddingmask; - smc_pptable->SocUlvPhaseSheddingMask = smc_dpm_table->soculvphasesheddingmask; - smc_pptable->ExternalSensorPresent = smc_dpm_table->externalsensorpresent; - - smc_pptable->GfxMaxCurrent = smc_dpm_table->gfxmaxcurrent; - smc_pptable->GfxOffset = smc_dpm_table->gfxoffset; - smc_pptable->Padding_TelemetryGfx = smc_dpm_table->padding_telemetrygfx; - - smc_pptable->SocMaxCurrent = smc_dpm_table->socmaxcurrent; - smc_pptable->SocOffset = smc_dpm_table->socoffset; - smc_pptable->Padding_TelemetrySoc = smc_dpm_table->padding_telemetrysoc; - - smc_pptable->Mem0MaxCurrent = smc_dpm_table->mem0maxcurrent; - smc_pptable->Mem0Offset = smc_dpm_table->mem0offset; - smc_pptable->Padding_TelemetryMem0 = smc_dpm_table->padding_telemetrymem0; - - smc_pptable->Mem1MaxCurrent = smc_dpm_table->mem1maxcurrent; - smc_pptable->Mem1Offset = smc_dpm_table->mem1offset; - smc_pptable->Padding_TelemetryMem1 = smc_dpm_table->padding_telemetrymem1; - - smc_pptable->AcDcGpio = smc_dpm_table->acdcgpio; - smc_pptable->AcDcPolarity = smc_dpm_table->acdcpolarity; - smc_pptable->VR0HotGpio = smc_dpm_table->vr0hotgpio; - smc_pptable->VR0HotPolarity = smc_dpm_table->vr0hotpolarity; - - smc_pptable->VR1HotGpio = smc_dpm_table->vr1hotgpio; - smc_pptable->VR1HotPolarity = smc_dpm_table->vr1hotpolarity; - smc_pptable->Padding1 = smc_dpm_table->padding1; - smc_pptable->Padding2 = smc_dpm_table->padding2; - - smc_pptable->LedPin0 = smc_dpm_table->ledpin0; - smc_pptable->LedPin1 = smc_dpm_table->ledpin1; - smc_pptable->LedPin2 = smc_dpm_table->ledpin2; - - smc_pptable->PllGfxclkSpreadEnabled = smc_dpm_table->pllgfxclkspreadenabled; - smc_pptable->PllGfxclkSpreadPercent = smc_dpm_table->pllgfxclkspreadpercent; - smc_pptable->PllGfxclkSpreadFreq = smc_dpm_table->pllgfxclkspreadfreq; - - smc_pptable->UclkSpreadEnabled = 0; - smc_pptable->UclkSpreadPercent = smc_dpm_table->uclkspreadpercent; - smc_pptable->UclkSpreadFreq = smc_dpm_table->uclkspreadfreq; - - smc_pptable->FclkSpreadEnabled = smc_dpm_table->fclkspreadenabled; - smc_pptable->FclkSpreadPercent = smc_dpm_table->fclkspreadpercent; - smc_pptable->FclkSpreadFreq = smc_dpm_table->fclkspreadfreq; - - smc_pptable->FllGfxclkSpreadEnabled = smc_dpm_table->fllgfxclkspreadenabled; - smc_pptable->FllGfxclkSpreadPercent = smc_dpm_table->fllgfxclkspreadpercent; - smc_pptable->FllGfxclkSpreadFreq = smc_dpm_table->fllgfxclkspreadfreq; - - for (i = 0; i < I2C_CONTROLLER_NAME_COUNT; i++) { - smc_pptable->I2cControllers[i].Enabled = - smc_dpm_table->i2ccontrollers[i].enabled; - smc_pptable->I2cControllers[i].SlaveAddress = - smc_dpm_table->i2ccontrollers[i].slaveaddress; - smc_pptable->I2cControllers[i].ControllerPort = - smc_dpm_table->i2ccontrollers[i].controllerport; - smc_pptable->I2cControllers[i].ThermalThrottler = - smc_dpm_table->i2ccontrollers[i].thermalthrottler; - smc_pptable->I2cControllers[i].I2cProtocol = - smc_dpm_table->i2ccontrollers[i].i2cprotocol; - smc_pptable->I2cControllers[i].I2cSpeed = - smc_dpm_table->i2ccontrollers[i].i2cspeed; - } - - return 0; -} - -static int vega20_check_powerplay_table(struct smu_context *smu) -{ - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = NULL; - struct smu_table_context *table_context = &smu->smu_table; - - powerplay_table = table_context->power_play_table; - - if (powerplay_table->sHeader.format_revision < ATOM_VEGA20_TABLE_REVISION_VEGA20) { - pr_err("Unsupported PPTable format!"); - return -EINVAL; - } - - if (!powerplay_table->sHeader.structuresize) { - pr_err("Invalid PowerPlay Table!"); - return -EINVAL; - } - - return 0; -} - -static int vega20_run_btc_afll(struct smu_context *smu) -{ - return smu_send_smc_msg(smu, SMU_MSG_RunAfllBtc, NULL); -} - -#define FEATURE_MASK(feature) (1ULL << feature) -static int -vega20_get_allowed_feature_mask(struct smu_context *smu, - uint32_t *feature_mask, uint32_t num) -{ - if (num > 2) - return -EINVAL; - - 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_UCLK_BIT) - | FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT) - | FEATURE_MASK(FEATURE_DPM_UVD_BIT) - | FEATURE_MASK(FEATURE_DPM_VCE_BIT) - | FEATURE_MASK(FEATURE_ULV_BIT) - | FEATURE_MASK(FEATURE_DPM_MP0CLK_BIT) - | FEATURE_MASK(FEATURE_DPM_LINK_BIT) - | FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT) - | FEATURE_MASK(FEATURE_PPT_BIT) - | FEATURE_MASK(FEATURE_TDC_BIT) - | FEATURE_MASK(FEATURE_THERMAL_BIT) - | FEATURE_MASK(FEATURE_GFX_PER_CU_CG_BIT) - | FEATURE_MASK(FEATURE_RM_BIT) - | FEATURE_MASK(FEATURE_ACDC_BIT) - | FEATURE_MASK(FEATURE_VR0HOT_BIT) - | FEATURE_MASK(FEATURE_VR1HOT_BIT) - | FEATURE_MASK(FEATURE_FW_CTF_BIT) - | FEATURE_MASK(FEATURE_LED_DISPLAY_BIT) - | FEATURE_MASK(FEATURE_FAN_CONTROL_BIT) - | FEATURE_MASK(FEATURE_GFX_EDC_BIT) - | FEATURE_MASK(FEATURE_GFXOFF_BIT) - | FEATURE_MASK(FEATURE_CG_BIT) - | FEATURE_MASK(FEATURE_DPM_FCLK_BIT) - | FEATURE_MASK(FEATURE_XGMI_BIT); - return 0; -} - -static enum -amd_pm_state_type vega20_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 -vega20_set_single_dpm_table(struct smu_context *smu, - struct vega20_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), - &num_of_levels); - if (ret) { - pr_err("[GetNumOfDpmLevel] failed to get dpm levels!"); - return ret; - } - - if (!num_of_levels) { - pr_err("[GetNumOfDpmLevel] number of clk levels is invalid!"); - 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), - &clk); - if (ret) { - pr_err("[GetDpmFreqByIndex] failed to get dpm freq by index!"); - return ret; - } - if (!clk) { - pr_err("[GetDpmFreqByIndex] clk value is invalid!"); - return -EINVAL; - } - single_dpm_table->dpm_levels[i].value = clk; - single_dpm_table->dpm_levels[i].enabled = true; - } - return 0; -} - -static void vega20_init_single_dpm_state(struct vega20_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 vega20_set_default_dpm_table(struct smu_context *smu) -{ - int ret; - - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_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 = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_SOCCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get socclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 100; - } - vega20_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 = vega20_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; - } - vega20_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 = vega20_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; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* eclk */ - single_dpm_table = &(dpm_table->eclk_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_ECLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get eclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.eclk / 100; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* vclk */ - single_dpm_table = &(dpm_table->vclk_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_VCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get vclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 100; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* dclk */ - single_dpm_table = &(dpm_table->dclk_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, PPCLK_DCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get dclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 100; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* dcefclk */ - single_dpm_table = &(dpm_table->dcef_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_DCEFCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get dcefclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* pixclk */ - single_dpm_table = &(dpm_table->pixel_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_PIXCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get pixclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 0; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* dispclk */ - single_dpm_table = &(dpm_table->display_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_DISPCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get dispclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 0; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* phyclk */ - single_dpm_table = &(dpm_table->phy_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_PHYCLK); - if (ret) { - pr_err("[SetupDefaultDpmTable] failed to get phyclk dpm levels!"); - return ret; - } - } else { - single_dpm_table->count = 0; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - /* fclk */ - single_dpm_table = &(dpm_table->fclk_table); - - if (smu_feature_is_enabled(smu,FEATURE_DPM_FCLK_BIT)) { - ret = vega20_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 = 0; - } - vega20_init_single_dpm_state(&(single_dpm_table->dpm_state)); - - memcpy(smu_dpm->golden_dpm_context, dpm_table, - sizeof(struct vega20_dpm_table)); - - return 0; -} - -static int vega20_populate_umd_state_clk(struct smu_context *smu) -{ - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_single_dpm_table *gfx_table = NULL; - struct vega20_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 > VEGA20_UMD_PSTATE_GFXCLK_LEVEL && - mem_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL) { - smu->pstate_sclk = gfx_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; - smu->pstate_mclk = mem_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; - } - - smu->pstate_sclk = smu->pstate_sclk * 100; - smu->pstate_mclk = smu->pstate_mclk * 100; - - return 0; -} - -static int vega20_get_clk_table(struct smu_context *smu, - struct pp_clock_levels_with_latency *clocks, - struct vega20_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 vega20_print_clk_levels(struct smu_context *smu, - enum smu_clk_type type, char *buf) -{ - int i, now, size = 0; - int ret = 0; - uint32_t gen_speed, lane_width; - struct amdgpu_device *adev = smu->adev; - struct pp_clock_levels_with_latency clocks; - struct vega20_single_dpm_table *single_dpm_table; - struct smu_table_context *table_context = &smu->smu_table; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_od8_settings *od8_settings = - (struct vega20_od8_settings *)smu->od_settings; - OverDriveTable_t *od_table = - (OverDriveTable_t *)(table_context->overdrive_table); - PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable; - - 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 = vega20_get_clk_table(smu, &clocks, single_dpm_table); - if (ret) { - pr_err("Attempt to get gfx 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.data[i].clocks_in_khz == now * 10) - ? "*" : ""); - 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 = vega20_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.data[i].clocks_in_khz == now * 10) - ? "*" : ""); - 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 = vega20_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.data[i].clocks_in_khz == now * 10) - ? "*" : ""); - 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); - 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, - (single_dpm_table->dpm_levels[i].value == now / 100) - ? "*" : ""); - break; - - case SMU_DCEFCLK: - ret = smu_get_current_clk_freq(smu, SMU_DCEFCLK, &now); - if (ret) { - pr_err("Attempt to get current dcefclk Failed!"); - return ret; - } - - single_dpm_table = &(dpm_table->dcef_table); - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); - if (ret) { - pr_err("Attempt to get dcefclk 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.data[i].clocks_in_khz == now * 10) ? "*" : ""); - 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, - (pptable->PcieGenSpeed[i] == 0) ? "2.5GT/s," : - (pptable->PcieGenSpeed[i] == 1) ? "5.0GT/s," : - (pptable->PcieGenSpeed[i] == 2) ? "8.0GT/s," : - (pptable->PcieGenSpeed[i] == 3) ? "16.0GT/s," : "", - (pptable->PcieLaneCount[i] == 1) ? "x1" : - (pptable->PcieLaneCount[i] == 2) ? "x2" : - (pptable->PcieLaneCount[i] == 3) ? "x4" : - (pptable->PcieLaneCount[i] == 4) ? "x8" : - (pptable->PcieLaneCount[i] == 5) ? "x12" : - (pptable->PcieLaneCount[i] == 6) ? "x16" : "", - pptable->LclkFreq[i], - (gen_speed == pptable->PcieGenSpeed[i]) && - (lane_width == pptable->PcieLaneCount[i]) ? - "*" : ""); - break; - - case SMU_OD_SCLK: - if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { - size = sprintf(buf, "%s:\n", "OD_SCLK"); - size += sprintf(buf + size, "0: %10uMhz\n", - od_table->GfxclkFmin); - size += sprintf(buf + size, "1: %10uMhz\n", - od_table->GfxclkFmax); - } - - break; - - case SMU_OD_MCLK: - if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { - size = sprintf(buf, "%s:\n", "OD_MCLK"); - size += sprintf(buf + size, "1: %10uMhz\n", - od_table->UclkFmax); - } - - break; - - case SMU_OD_VDDC_CURVE: - if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { - size = sprintf(buf, "%s:\n", "OD_VDDC_CURVE"); - size += sprintf(buf + size, "0: %10uMhz %10dmV\n", - od_table->GfxclkFreq1, - od_table->GfxclkVolt1 / VOLTAGE_SCALE); - size += sprintf(buf + size, "1: %10uMhz %10dmV\n", - od_table->GfxclkFreq2, - od_table->GfxclkVolt2 / VOLTAGE_SCALE); - size += sprintf(buf + size, "2: %10uMhz %10dmV\n", - od_table->GfxclkFreq3, - od_table->GfxclkVolt3 / VOLTAGE_SCALE); - } - - break; - - case SMU_OD_RANGE: - size = sprintf(buf, "%s:\n", "OD_RANGE"); - - if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id) { - size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); - } - - if (od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { - single_dpm_table = &(dpm_table->mem_table); - ret = vega20_get_clk_table(smu, &clocks, single_dpm_table); - if (ret) { - pr_err("Attempt to get memory clk levels Failed!"); - return ret; - } - - size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n", - clocks.data[0].clocks_in_khz / 1000, - od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); - } - - if (od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id) { - size += sprintf(buf + size, "VDDC_CURVE_SCLK[0]: %7uMhz %10uMhz\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[0]: %7dmV %11dmV\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].max_value); - size += sprintf(buf + size, "VDDC_CURVE_SCLK[1]: %7uMhz %10uMhz\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[1]: %7dmV %11dmV\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].max_value); - size += sprintf(buf + size, "VDDC_CURVE_SCLK[2]: %7uMhz %10uMhz\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].max_value); - size += sprintf(buf + size, "VDDC_CURVE_VOLT[2]: %7dmV %11dmV\n", - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].max_value); - } - - break; - - default: - break; - } - return size; -} - -static int vega20_upload_dpm_level(struct smu_context *smu, bool max, - uint32_t feature_mask) -{ - struct vega20_dpm_table *dpm_table; - struct vega20_single_dpm_table *single_dpm_table; - uint32_t freq; - int ret = 0; - - dpm_table = smu->smu_dpm.dpm_context; - - 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), - NULL); - 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), - NULL); - 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), - NULL); - if (ret) { - pr_err("Failed to set soft %s socclk !\n", - max ? "max" : "min"); - return ret; - } - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_FCLK_BIT) && - (feature_mask & FEATURE_DPM_FCLK_MASK)) { - single_dpm_table = &(dpm_table->fclk_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_FCLK << 16) | (freq & 0xffff), - NULL); - if (ret) { - pr_err("Failed to set soft %s fclk !\n", - max ? "max" : "min"); - return ret; - } - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && - (feature_mask & FEATURE_DPM_DCEFCLK_MASK)) { - single_dpm_table = &(dpm_table->dcef_table); - freq = single_dpm_table->dpm_state.hard_min_level; - if (!max) { - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_SetHardMinByFreq, - (PPCLK_DCEFCLK << 16) | (freq & 0xffff), - NULL); - if (ret) { - pr_err("Failed to set hard min dcefclk !\n"); - return ret; - } - } - } - - return ret; -} - -static int vega20_force_clk_levels(struct smu_context *smu, - enum smu_clk_type clk_type, uint32_t mask) -{ - 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; - 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 (clk_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 = vega20_upload_dpm_level(smu, false, FEATURE_DPM_GFXCLK_MASK); - if (ret) { - pr_err("Failed to upload boot level to lowest!\n"); - break; - } - - ret = vega20_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: - single_dpm_table = &(dpm_table->mem_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 = vega20_upload_dpm_level(smu, false, FEATURE_DPM_UCLK_MASK); - if (ret) { - pr_err("Failed to upload boot level to lowest!\n"); - break; - } - - ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_UCLK_MASK); - if (ret) - pr_err("Failed to upload dpm max level to highest!\n"); - - break; - - case SMU_SOCCLK: - single_dpm_table = &(dpm_table->soc_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 = vega20_upload_dpm_level(smu, false, FEATURE_DPM_SOCCLK_MASK); - if (ret) { - pr_err("Failed to upload boot level to lowest!\n"); - break; - } - - ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_SOCCLK_MASK); - if (ret) - pr_err("Failed to upload dpm max level to highest!\n"); - - break; - - case SMU_FCLK: - single_dpm_table = &(dpm_table->fclk_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 = vega20_upload_dpm_level(smu, false, FEATURE_DPM_FCLK_MASK); - if (ret) { - pr_err("Failed to upload boot level to lowest!\n"); - break; - } - - ret = vega20_upload_dpm_level(smu, true, FEATURE_DPM_FCLK_MASK); - if (ret) - pr_err("Failed to upload dpm max level to highest!\n"); - - break; - - case SMU_DCEFCLK: - hard_min_level = soft_min_level; - single_dpm_table = &(dpm_table->dcef_table); - - if (hard_min_level >= single_dpm_table->count) { - pr_err("Clock level specified %d is over max allowed %d\n", - hard_min_level, single_dpm_table->count - 1); - ret = -EINVAL; - break; - } - - single_dpm_table->dpm_state.hard_min_level = - single_dpm_table->dpm_levels[hard_min_level].value; - - ret = vega20_upload_dpm_level(smu, false, FEATURE_DPM_DCEFCLK_MASK); - if (ret) - pr_err("Failed to upload boot level to lowest!\n"); - - break; - - case SMU_PCIE: - if (soft_min_level >= NUM_LINK_LEVELS || - soft_max_level >= NUM_LINK_LEVELS) { - ret = -EINVAL; - break; - } - - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_SetMinLinkDpmByIndex, - soft_min_level, - NULL); - if (ret) - pr_err("Failed to set min link dpm level!\n"); - - break; - - default: - break; - } - - return ret; -} - -static int vega20_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; - struct vega20_single_dpm_table *single_dpm_table; - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - - dpm_table = smu_dpm->dpm_context; - - switch (clk_type) { - case SMU_GFXCLK: - single_dpm_table = &(dpm_table->gfx_table); - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); - break; - case SMU_MCLK: - single_dpm_table = &(dpm_table->mem_table); - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); - break; - case SMU_DCEFCLK: - single_dpm_table = &(dpm_table->dcef_table); - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); - break; - case SMU_SOCCLK: - single_dpm_table = &(dpm_table->soc_table); - ret = vega20_get_clk_table(smu, clocks, single_dpm_table); - break; - default: - ret = -EINVAL; - } - - return ret; -} - -static int vega20_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu, - uint32_t *voltage, - uint32_t freq) -{ - int ret; - - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_GetAVFSVoltageByDpm, - ((AVFS_CURVE << 24) | (OD8_HOTCURVE_TEMPERATURE << 16) | freq), - voltage); - if (ret) { - pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!"); - return ret; - } - - *voltage = *voltage / VOLTAGE_SCALE; - - return 0; -} - -static int vega20_set_default_od8_setttings(struct smu_context *smu) -{ - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTable_t *od_table = (OverDriveTable_t *)(table_context->overdrive_table); - struct vega20_od8_settings *od8_settings = NULL; - PPTable_t *smc_pptable = table_context->driver_pptable; - int i, ret; - - if (smu->od_settings) - return -EINVAL; - - od8_settings = kzalloc(sizeof(struct vega20_od8_settings), GFP_KERNEL); - - if (!od8_settings) - return -ENOMEM; - - smu->od_settings = (void *)od8_settings; - - ret = vega20_setup_od8_information(smu); - if (ret) { - pr_err("Retrieve board OD limits failed!\n"); - return ret; - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_LIMITS] && - od8_settings->od_settings_max[OD8_SETTING_GFXCLK_FMAX] > 0 && - od8_settings->od_settings_min[OD8_SETTING_GFXCLK_FMIN] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_GFXCLK_FMAX] >= - od8_settings->od_settings_min[OD8_SETTING_GFXCLK_FMIN])) { - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id = - OD8_GFXCLK_LIMITS; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id = - OD8_GFXCLK_LIMITS; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].default_value = - od_table->GfxclkFmin; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].default_value = - od_table->GfxclkFmax; - } - - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_GFXCLK_CURVE] && - (od8_settings->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] >= - smc_pptable->MinVoltageGfx / VOLTAGE_SCALE) && - (od8_settings->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3] <= - smc_pptable->MaxVoltageGfx / VOLTAGE_SCALE) && - (od8_settings->od_settings_min[OD8_SETTING_GFXCLK_VOLTAGE1] <= - od8_settings->od_settings_max[OD8_SETTING_GFXCLK_VOLTAGE3])) { - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id = - OD8_GFXCLK_CURVE; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id = - OD8_GFXCLK_CURVE; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id = - OD8_GFXCLK_CURVE; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id = - OD8_GFXCLK_CURVE; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id = - OD8_GFXCLK_CURVE; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id = - OD8_GFXCLK_CURVE; - - od_table->GfxclkFreq1 = od_table->GfxclkFmin; - od_table->GfxclkFreq2 = (od_table->GfxclkFmin + od_table->GfxclkFmax) / 2; - od_table->GfxclkFreq3 = od_table->GfxclkFmax; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].default_value = - od_table->GfxclkFreq1; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].default_value = - od_table->GfxclkFreq2; - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].default_value = - od_table->GfxclkFreq3; - - ret = vega20_overdrive_get_gfx_clk_base_voltage(smu, - &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value, - od_table->GfxclkFreq1); - if (ret) - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value = 0; - od_table->GfxclkVolt1 = - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].default_value - * VOLTAGE_SCALE; - ret = vega20_overdrive_get_gfx_clk_base_voltage(smu, - &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value, - od_table->GfxclkFreq2); - if (ret) - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value = 0; - od_table->GfxclkVolt2 = - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].default_value - * VOLTAGE_SCALE; - ret = vega20_overdrive_get_gfx_clk_base_voltage(smu, - &od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value, - od_table->GfxclkFreq3); - if (ret) - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value = 0; - od_table->GfxclkVolt3 = - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].default_value - * VOLTAGE_SCALE; - } - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_UCLK_MAX] && - od8_settings->od_settings_min[OD8_SETTING_UCLK_FMAX] > 0 && - od8_settings->od_settings_max[OD8_SETTING_UCLK_FMAX] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_UCLK_FMAX] >= - od8_settings->od_settings_min[OD8_SETTING_UCLK_FMAX])) { - od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id = - OD8_UCLK_MAX; - od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].default_value = - od_table->UclkFmax; - } - } - - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_POWER_LIMIT] && - od8_settings->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] > 0 && - od8_settings->od_settings_min[OD8_SETTING_POWER_PERCENTAGE] <= 100 && - od8_settings->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] > 0 && - od8_settings->od_settings_max[OD8_SETTING_POWER_PERCENTAGE] <= 100) { - od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].feature_id = - OD8_POWER_LIMIT; - od8_settings->od8_settings_array[OD8_SETTING_POWER_PERCENTAGE].default_value = - od_table->OverDrivePct; - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_FAN_CONTROL_BIT)) { - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_ACOUSTIC_LIMIT] && - od8_settings->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && - od8_settings->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_FAN_ACOUSTIC_LIMIT] >= - od8_settings->od_settings_min[OD8_SETTING_FAN_ACOUSTIC_LIMIT])) { - od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].feature_id = - OD8_ACOUSTIC_LIMIT_SCLK; - od8_settings->od8_settings_array[OD8_SETTING_FAN_ACOUSTIC_LIMIT].default_value = - od_table->FanMaximumRpm; - } - - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_FAN_SPEED_MIN] && - od8_settings->od_settings_min[OD8_SETTING_FAN_MIN_SPEED] > 0 && - od8_settings->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_FAN_MIN_SPEED] >= - od8_settings->od_settings_min[OD8_SETTING_FAN_MIN_SPEED])) { - od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].feature_id = - OD8_FAN_SPEED_MIN; - od8_settings->od8_settings_array[OD8_SETTING_FAN_MIN_SPEED].default_value = - od_table->FanMinimumPwm * smc_pptable->FanMaximumRpm / 100; - } - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_THERMAL_BIT)) { - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_FAN] && - od8_settings->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP] > 0 && - od8_settings->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_FAN_TARGET_TEMP] >= - od8_settings->od_settings_min[OD8_SETTING_FAN_TARGET_TEMP])) { - od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].feature_id = - OD8_TEMPERATURE_FAN; - od8_settings->od8_settings_array[OD8_SETTING_FAN_TARGET_TEMP].default_value = - od_table->FanTargetTemperature; - } - - if (od8_settings->od_feature_capabilities[ATOM_VEGA20_ODFEATURE_TEMPERATURE_SYSTEM] && - od8_settings->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && - od8_settings->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] > 0 && - (od8_settings->od_settings_max[OD8_SETTING_OPERATING_TEMP_MAX] >= - od8_settings->od_settings_min[OD8_SETTING_OPERATING_TEMP_MAX])) { - od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].feature_id = - OD8_TEMPERATURE_SYSTEM; - od8_settings->od8_settings_array[OD8_SETTING_OPERATING_TEMP_MAX].default_value = - od_table->MaxOpTemp; - } - } - - for (i = 0; i < OD8_SETTING_COUNT; i++) { - if (od8_settings->od8_settings_array[i].feature_id) { - od8_settings->od8_settings_array[i].min_value = - od8_settings->od_settings_min[i]; - od8_settings->od8_settings_array[i].max_value = - od8_settings->od_settings_max[i]; - od8_settings->od8_settings_array[i].current_value = - od8_settings->od8_settings_array[i].default_value; - } else { - od8_settings->od8_settings_array[i].min_value = 0; - od8_settings->od8_settings_array[i].max_value = 0; - od8_settings->od8_settings_array[i].current_value = 0; - } - } - - return 0; -} - -static int vega20_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 vega20_set_default_od_settings(struct smu_context *smu, - bool initialize) -{ - struct smu_table_context *table_context = &smu->smu_table; - int 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; - } - - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, - table_context->overdrive_table, true); - if (ret) { - pr_err("Failed to import over drive table!\n"); - return ret; - } - - return 0; -} - -static int vega20_get_od_percentage(struct smu_context *smu, - enum smu_clk_type clk_type) -{ - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_dpm_table *golden_table = NULL; - struct vega20_single_dpm_table *single_dpm_table; - struct vega20_single_dpm_table *golden_dpm_table; - int value, golden_value; - - dpm_table = smu_dpm->dpm_context; - golden_table = smu_dpm->golden_dpm_context; - - switch (clk_type) { - case SMU_OD_SCLK: - single_dpm_table = &(dpm_table->gfx_table); - golden_dpm_table = &(golden_table->gfx_table); - break; - case SMU_OD_MCLK: - single_dpm_table = &(dpm_table->mem_table); - golden_dpm_table = &(golden_table->mem_table); - break; - default: - return -EINVAL; - break; - } - - value = single_dpm_table->dpm_levels[single_dpm_table->count - 1].value; - golden_value = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value; - - value -= golden_value; - value = DIV_ROUND_UP(value * 100, golden_value); - - return value; -} - -static int vega20_get_power_profile_mode(struct smu_context *smu, char *buf) -{ - DpmActivityMonitorCoeffInt_t activity_monitor; - uint32_t i, size = 0; - int16_t workload_type = 0; - 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"}; - int result = 0; - - if (!buf) - return -EINVAL; - - 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]); - - 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); - 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) ? "*" : " "); - - 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, - "SOCCLK", - activity_monitor.Soc_FPS, - activity_monitor.Soc_UseRlcBusy, - activity_monitor.Soc_MinActiveFreqType, - activity_monitor.Soc_MinActiveFreq, - activity_monitor.Soc_BoosterFreqType, - activity_monitor.Soc_BoosterFreq, - activity_monitor.Soc_PD_Data_limit_c, - activity_monitor.Soc_PD_Data_error_coeff, - activity_monitor.Soc_PD_Data_error_rate_coeff); - - size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", - " ", - 2, - "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); - - size += sprintf(buf + size, "%19s %d(%13s) %7d %7d %7d %7d %7d %7d %7d %7d %7d\n", - " ", - 3, - "FCLK", - activity_monitor.Fclk_FPS, - activity_monitor.Fclk_UseRlcBusy, - activity_monitor.Fclk_MinActiveFreqType, - activity_monitor.Fclk_MinActiveFreq, - activity_monitor.Fclk_BoosterFreqType, - activity_monitor.Fclk_BoosterFreq, - activity_monitor.Fclk_PD_Data_limit_c, - activity_monitor.Fclk_PD_Data_error_coeff, - activity_monitor.Fclk_PD_Data_error_rate_coeff); - } - - return size; -} - -static int vega20_set_power_profile_mode(struct smu_context *smu, long *input, uint32_t size) -{ - DpmActivityMonitorCoeffInt_t activity_monitor; - int workload_type = 0, ret = 0; - - smu->power_profile_mode = input[size]; - - if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) { - pr_err("Invalid power profile mode %d\n", smu->power_profile_mode); - return -EINVAL; - } - - if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) { - 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: /* Socclk */ - activity_monitor.Soc_FPS = input[1]; - activity_monitor.Soc_UseRlcBusy = input[2]; - activity_monitor.Soc_MinActiveFreqType = input[3]; - activity_monitor.Soc_MinActiveFreq = input[4]; - activity_monitor.Soc_BoosterFreqType = input[5]; - activity_monitor.Soc_BoosterFreq = input[6]; - activity_monitor.Soc_PD_Data_limit_c = input[7]; - activity_monitor.Soc_PD_Data_error_coeff = input[8]; - activity_monitor.Soc_PD_Data_error_rate_coeff = input[9]; - break; - case 2: /* 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; - case 3: /* Fclk */ - activity_monitor.Fclk_FPS = input[1]; - activity_monitor.Fclk_UseRlcBusy = input[2]; - activity_monitor.Fclk_MinActiveFreqType = input[3]; - activity_monitor.Fclk_MinActiveFreq = input[4]; - activity_monitor.Fclk_BoosterFreqType = input[5]; - activity_monitor.Fclk_BoosterFreq = input[6]; - activity_monitor.Fclk_PD_Data_limit_c = input[7]; - activity_monitor.Fclk_PD_Data_error_coeff = input[8]; - activity_monitor.Fclk_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 */ - 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, - NULL); - - return ret; -} - -static int -vega20_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 vega20_dpm_table *dpm_table = (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; - struct vega20_single_dpm_table *gfx_dpm_table; - struct vega20_single_dpm_table *mem_dpm_table; - struct vega20_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 > VEGA20_UMD_PSTATE_GFXCLK_LEVEL && - mem_dpm_table->count > VEGA20_UMD_PSTATE_MCLK_LEVEL && - soc_dpm_table->count > VEGA20_UMD_PSTATE_SOCCLK_LEVEL) { - *sclk_mask = VEGA20_UMD_PSTATE_GFXCLK_LEVEL; - *mclk_mask = VEGA20_UMD_PSTATE_MCLK_LEVEL; - *soc_mask = VEGA20_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 -vega20_set_uclk_to_highest_dpm_level(struct smu_context *smu, - struct vega20_single_dpm_table *dpm_table) -{ - int ret = 0; - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - if (!smu_dpm_ctx->dpm_context) - return -EINVAL; - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { - if (dpm_table->count <= 0) { - pr_err("[%s] Dpm table has no entry!", __func__); - return -EINVAL; - } - - if (dpm_table->count > NUM_UCLK_DPM_LEVELS) { - pr_err("[%s] Dpm table has too many entries!", __func__); - return -EINVAL; - } - - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_SetHardMinByFreq, - (PPCLK_UCLK << 16) | dpm_table->dpm_state.hard_min_level, - NULL); - if (ret) { - pr_err("[%s] Set hard min uclk failed!", __func__); - return ret; - } - } - - return ret; -} - -static int vega20_pre_display_config_changed(struct smu_context *smu) -{ - int ret = 0; - struct vega20_dpm_table *dpm_table = smu->smu_dpm.dpm_context; - - if (!smu->smu_dpm.dpm_context) - return -EINVAL; - - smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL); - ret = vega20_set_uclk_to_highest_dpm_level(smu, - &dpm_table->mem_table); - if (ret) - pr_err("Failed to set uclk to highest dpm level"); - return ret; -} - -static int vega20_display_config_changed(struct smu_context *smu) -{ - int ret = 0; - - 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; - } - - if ((smu->watermarks_bitmap & WATERMARKS_EXIST) && - smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) && - smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) { - smu_send_smc_msg_with_param(smu, - SMU_MSG_NumOfDisplays, - smu->display_config->num_display, - NULL); - } - - return ret; -} - -static int vega20_apply_clocks_adjust_rules(struct smu_context *smu) -{ - struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); - struct vega20_dpm_table *dpm_ctx = (struct vega20_dpm_table *)(smu_dpm_ctx->dpm_context); - struct vega20_single_dpm_table *dpm_table; - bool vblank_too_short = false; - bool disable_mclk_switching; - uint32_t i, latency; - - disable_mclk_switching = ((1 < smu->display_config->num_display) && - !smu->display_config->multi_monitor_in_sync) || vblank_too_short; - latency = smu->display_config->dce_tolerable_mclk_in_active_latency; - - /* gfxclk */ - dpm_table = &(dpm_ctx->gfx_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_GFXCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_GFXCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - - /* memclk */ - dpm_table = &(dpm_ctx->mem_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_MCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_MCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[0].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - - /* honour DAL's UCLK Hardmin */ - if (dpm_table->dpm_state.hard_min_level < (smu->display_config->min_mem_set_clock / 100)) - dpm_table->dpm_state.hard_min_level = smu->display_config->min_mem_set_clock / 100; - - /* Hardmin is dependent on displayconfig */ - if (disable_mclk_switching) { - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - for (i = 0; i < smu_dpm_ctx->mclk_latency_table->count - 1; i++) { - if (smu_dpm_ctx->mclk_latency_table->entries[i].latency <= latency) { - if (dpm_table->dpm_levels[i].value >= (smu->display_config->min_mem_set_clock / 100)) { - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[i].value; - break; - } - } - } - } - - if (smu->display_config->nb_pstate_switch_disable) - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - /* vclk */ - dpm_table = &(dpm_ctx->vclk_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - - /* dclk */ - dpm_table = &(dpm_ctx->dclk_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_UVDCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_UVDCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - - /* socclk */ - dpm_table = &(dpm_ctx->soc_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_SOCCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_SOCCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - - /* eclk */ - dpm_table = &(dpm_ctx->eclk_table); - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.hard_min_level = dpm_table->dpm_levels[0].value; - dpm_table->dpm_state.hard_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - - if (VEGA20_UMD_PSTATE_VCEMCLK_LEVEL < dpm_table->count) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[VEGA20_UMD_PSTATE_VCEMCLK_LEVEL].value; - } - - if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) { - dpm_table->dpm_state.soft_min_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - dpm_table->dpm_state.soft_max_level = dpm_table->dpm_levels[dpm_table->count - 1].value; - } - return 0; -} - -static int -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; - struct smu_clocks min_clocks = {0}; - struct pp_display_clock_request clock_req; - int ret = 0; - - min_clocks.dcef_clock = smu->display_config->min_dcef_set_clk; - min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk; - min_clocks.memory_clock = smu->display_config->min_mem_set_clock; - - 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_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, - min_clocks.dcef_clock_in_sr/100, - NULL); - if (ret) { - pr_err("Attempt to set divider for DCEFCLK Failed!"); - return ret; - } - } - } else { - pr_info("Attempt to set Hard Min for DCEFCLK Failed!"); - } - } - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) { - memtable->dpm_state.hard_min_level = min_clocks.memory_clock/100; - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_SetHardMinByFreq, - (PPCLK_UCLK << 16) | memtable->dpm_state.hard_min_level, - NULL); - if (ret) { - pr_err("[%s] Set hard min uclk failed!", __func__); - return ret; - } - } - - return 0; -} - -static uint32_t vega20_find_lowest_dpm_level(struct vega20_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 vega20_find_highest_dpm_level(struct vega20_single_dpm_table *table) -{ - int i = 0; - - if (!table) { - pr_err("[%s] DPM Table does not exist!", __func__); - return 0; - } - if (table->count <= 0) { - pr_err("[%s] DPM Table has no entry!", __func__); - return 0; - } - if (table->count > MAX_REGULAR_DPM_NUMBER) { - pr_err("[%s] DPM Table has too many entries!", __func__); - return MAX_REGULAR_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 vega20_force_dpm_limit_value(struct smu_context *smu, bool highest) -{ - uint32_t soft_level; - int ret = 0; - struct vega20_dpm_table *dpm_table = - (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; - - if (highest) - soft_level = vega20_find_highest_dpm_level(&(dpm_table->gfx_table)); - else - soft_level = vega20_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; - - if (highest) - soft_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table)); - else - soft_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table)); - - dpm_table->mem_table.dpm_state.soft_min_level = - dpm_table->mem_table.dpm_state.soft_max_level = - dpm_table->mem_table.dpm_levels[soft_level].value; - - if (highest) - soft_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table)); - else - soft_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table)); - - dpm_table->soc_table.dpm_state.soft_min_level = - dpm_table->soc_table.dpm_state.soft_max_level = - dpm_table->soc_table.dpm_levels[soft_level].value; - - ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); - if (ret) { - pr_err("Failed to upload boot level to %s!\n", - highest ? "highest" : "lowest"); - return ret; - } - - ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); - if (ret) { - pr_err("Failed to upload dpm max level to %s!\n!", - highest ? "highest" : "lowest"); - return ret; - } - - return ret; -} - -static int vega20_unforce_dpm_levels(struct smu_context *smu) -{ - uint32_t soft_min_level, soft_max_level; - int ret = 0; - struct vega20_dpm_table *dpm_table = - (struct vega20_dpm_table *)smu->smu_dpm.dpm_context; - - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->gfx_table)); - soft_max_level = vega20_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; - - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->mem_table)); - soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->mem_table)); - dpm_table->mem_table.dpm_state.soft_min_level = - dpm_table->gfx_table.dpm_levels[soft_min_level].value; - dpm_table->mem_table.dpm_state.soft_max_level = - dpm_table->gfx_table.dpm_levels[soft_max_level].value; - - soft_min_level = vega20_find_lowest_dpm_level(&(dpm_table->soc_table)); - soft_max_level = vega20_find_highest_dpm_level(&(dpm_table->soc_table)); - dpm_table->soc_table.dpm_state.soft_min_level = - dpm_table->soc_table.dpm_levels[soft_min_level].value; - dpm_table->soc_table.dpm_state.soft_max_level = - dpm_table->soc_table.dpm_levels[soft_max_level].value; - - ret = vega20_upload_dpm_level(smu, false, 0xFFFFFFFF); - if (ret) { - pr_err("Failed to upload DPM Bootup Levels!"); - return ret; - } - - ret = vega20_upload_dpm_level(smu, true, 0xFFFFFFFF); - if (ret) { - pr_err("Failed to upload DPM Max Levels!"); - return ret; - } - - return ret; -} - -static int vega20_update_specified_od8_value(struct smu_context *smu, - uint32_t index, - uint32_t value) -{ - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTable_t *od_table = - (OverDriveTable_t *)(table_context->overdrive_table); - struct vega20_od8_settings *od8_settings = - (struct vega20_od8_settings *)smu->od_settings; - - switch (index) { - case OD8_SETTING_GFXCLK_FMIN: - od_table->GfxclkFmin = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_FMAX: - if (value < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].min_value || - value > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) - return -EINVAL; - od_table->GfxclkFmax = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_FREQ1: - od_table->GfxclkFreq1 = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_VOLTAGE1: - od_table->GfxclkVolt1 = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_FREQ2: - od_table->GfxclkFreq2 = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_VOLTAGE2: - od_table->GfxclkVolt2 = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_FREQ3: - od_table->GfxclkFreq3 = (uint16_t)value; - break; - - case OD8_SETTING_GFXCLK_VOLTAGE3: - od_table->GfxclkVolt3 = (uint16_t)value; - break; - - case OD8_SETTING_UCLK_FMAX: - if (value < od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].min_value || - value > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) - return -EINVAL; - od_table->UclkFmax = (uint16_t)value; - break; - - case OD8_SETTING_POWER_PERCENTAGE: - od_table->OverDrivePct = (int16_t)value; - break; - - case OD8_SETTING_FAN_ACOUSTIC_LIMIT: - od_table->FanMaximumRpm = (uint16_t)value; - break; - - case OD8_SETTING_FAN_MIN_SPEED: - od_table->FanMinimumPwm = (uint16_t)value; - break; - - case OD8_SETTING_FAN_TARGET_TEMP: - od_table->FanTargetTemperature = (uint16_t)value; - break; - - case OD8_SETTING_OPERATING_TEMP_MAX: - od_table->MaxOpTemp = (uint16_t)value; - break; - } - - return 0; -} - -static int vega20_update_od8_settings(struct smu_context *smu, - uint32_t index, - uint32_t value) -{ - struct smu_table_context *table_context = &smu->smu_table; - int ret; - - 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 = vega20_update_specified_od8_value(smu, index, value); - if (ret) - return ret; - - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, - table_context->overdrive_table, true); - if (ret) { - pr_err("Failed to import over drive table!\n"); - return ret; - } - - return 0; -} - -static int vega20_set_od_percentage(struct smu_context *smu, - enum smu_clk_type clk_type, - uint32_t value) -{ - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_dpm_table *golden_table = NULL; - struct vega20_single_dpm_table *single_dpm_table; - struct vega20_single_dpm_table *golden_dpm_table; - uint32_t od_clk, index; - int ret = 0; - int feature_enabled; - PPCLK_e clk_id; - - dpm_table = smu_dpm->dpm_context; - golden_table = smu_dpm->golden_dpm_context; - - switch (clk_type) { - case SMU_OD_SCLK: - single_dpm_table = &(dpm_table->gfx_table); - golden_dpm_table = &(golden_table->gfx_table); - feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT); - clk_id = PPCLK_GFXCLK; - index = OD8_SETTING_GFXCLK_FMAX; - break; - case SMU_OD_MCLK: - single_dpm_table = &(dpm_table->mem_table); - golden_dpm_table = &(golden_table->mem_table); - feature_enabled = smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT); - clk_id = PPCLK_UCLK; - index = OD8_SETTING_UCLK_FMAX; - break; - default: - ret = -EINVAL; - break; - } - - if (ret) - goto set_od_failed; - - od_clk = golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value * value; - od_clk /= 100; - od_clk += golden_dpm_table->dpm_levels[golden_dpm_table->count - 1].value; - - ret = vega20_update_od8_settings(smu, index, od_clk); - if (ret) { - pr_err("[Setoverdrive] failed to set od clk!\n"); - goto set_od_failed; - } - - if (feature_enabled) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - clk_id); - if (ret) { - pr_err("[Setoverdrive] failed to refresh dpm table!\n"); - goto set_od_failed; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; - } - - ret = smu_handle_task(smu, smu_dpm->dpm_level, - AMD_PP_TASK_READJUST_POWER_STATE, - false); - -set_od_failed: - return ret; -} - -static int vega20_odn_edit_dpm_table(struct smu_context *smu, - enum PP_OD_DPM_TABLE_COMMAND type, - long *input, uint32_t size) -{ - struct smu_table_context *table_context = &smu->smu_table; - OverDriveTable_t *od_table = - (OverDriveTable_t *)(table_context->overdrive_table); - struct smu_dpm_context *smu_dpm = &smu->smu_dpm; - struct vega20_dpm_table *dpm_table = NULL; - struct vega20_single_dpm_table *single_dpm_table; - struct vega20_od8_settings *od8_settings = - (struct vega20_od8_settings *)smu->od_settings; - struct pp_clock_levels_with_latency clocks; - int32_t input_index, input_clk, input_vol, i; - int od8_id; - int ret = 0; - - dpm_table = smu_dpm->dpm_context; - - if (!input) { - pr_warn("NULL user input for clock and voltage\n"); - return -EINVAL; - } - - switch (type) { - case PP_OD_EDIT_SCLK_VDDC_TABLE: - if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].feature_id)) { - pr_info("Sclk min/max frequency overdrive not supported\n"); - return -EOPNOTSUPP; - } - - for (i = 0; i < size; i += 2) { - if (i + 2 > size) { - pr_info("invalid number of input parameters %d\n", size); - return -EINVAL; - } - - input_index = input[i]; - input_clk = input[i + 1]; - - if (input_index != 0 && input_index != 1) { - pr_info("Invalid index %d\n", input_index); - pr_info("Support min/max sclk frequency settingonly which index by 0/1\n"); - return -EINVAL; - } - - if (input_clk < od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value || - input_clk > od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value) { - pr_info("clock freq %d is not within allowed range [%d - %d]\n", - input_clk, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMIN].min_value, - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FMAX].max_value); - return -EINVAL; - } - - if (input_index == 0 && od_table->GfxclkFmin != input_clk) { - od_table->GfxclkFmin = input_clk; - od8_settings->od_gfxclk_update = true; - } else if (input_index == 1 && od_table->GfxclkFmax != input_clk) { - od_table->GfxclkFmax = input_clk; - od8_settings->od_gfxclk_update = true; - } - } - - break; - - case PP_OD_EDIT_MCLK_VDDC_TABLE: - if (!od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].feature_id) { - pr_info("Mclk max frequency overdrive not supported\n"); - return -EOPNOTSUPP; - } - - single_dpm_table = &(dpm_table->mem_table); - ret = vega20_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 < size; i += 2) { - if (i + 2 > size) { - pr_info("invalid number of input parameters %d\n", - size); - return -EINVAL; - } - - input_index = input[i]; - input_clk = input[i + 1]; - - if (input_index != 1) { - pr_info("Invalid index %d\n", input_index); - pr_info("Support max Mclk frequency setting only which index by 1\n"); - return -EINVAL; - } - - if (input_clk < clocks.data[0].clocks_in_khz / 1000 || - input_clk > od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value) { - pr_info("clock freq %d is not within allowed range [%d - %d]\n", - input_clk, - clocks.data[0].clocks_in_khz / 1000, - od8_settings->od8_settings_array[OD8_SETTING_UCLK_FMAX].max_value); - return -EINVAL; - } - - if (input_index == 1 && od_table->UclkFmax != input_clk) { - od8_settings->od_gfxclk_update = true; - od_table->UclkFmax = input_clk; - } - } - - break; - - case PP_OD_EDIT_VDDC_CURVE: - if (!(od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_FREQ3].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE1].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE2].feature_id && - od8_settings->od8_settings_array[OD8_SETTING_GFXCLK_VOLTAGE3].feature_id)) { - pr_info("Voltage curve calibrate not supported\n"); - return -EOPNOTSUPP; - } - - for (i = 0; i < size; i += 3) { - if (i + 3 > size) { - pr_info("invalid number of input parameters %d\n", - size); - return -EINVAL; - } - - input_index = input[i]; - input_clk = input[i + 1]; - input_vol = input[i + 2]; - - if (input_index > 2) { - pr_info("Setting for point %d is not supported\n", - input_index + 1); - pr_info("Three supported points index by 0, 1, 2\n"); - return -EINVAL; - } - - od8_id = OD8_SETTING_GFXCLK_FREQ1 + 2 * input_index; - if (input_clk < od8_settings->od8_settings_array[od8_id].min_value || - input_clk > od8_settings->od8_settings_array[od8_id].max_value) { - pr_info("clock freq %d is not within allowed range [%d - %d]\n", - input_clk, - od8_settings->od8_settings_array[od8_id].min_value, - od8_settings->od8_settings_array[od8_id].max_value); - return -EINVAL; - } - - od8_id = OD8_SETTING_GFXCLK_VOLTAGE1 + 2 * input_index; - if (input_vol < od8_settings->od8_settings_array[od8_id].min_value || - input_vol > od8_settings->od8_settings_array[od8_id].max_value) { - pr_info("clock voltage %d is not within allowed range [%d- %d]\n", - input_vol, - od8_settings->od8_settings_array[od8_id].min_value, - od8_settings->od8_settings_array[od8_id].max_value); - return -EINVAL; - } - - switch (input_index) { - case 0: - od_table->GfxclkFreq1 = input_clk; - od_table->GfxclkVolt1 = input_vol * VOLTAGE_SCALE; - break; - case 1: - od_table->GfxclkFreq2 = input_clk; - od_table->GfxclkVolt2 = input_vol * VOLTAGE_SCALE; - break; - case 2: - od_table->GfxclkFreq3 = input_clk; - od_table->GfxclkVolt3 = input_vol * VOLTAGE_SCALE; - break; - } - } - - 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: - ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, table_context->overdrive_table, true); - if (ret) { - pr_err("Failed to import over drive table!\n"); - return ret; - } - - /* retrieve updated gfxclk table */ - if (od8_settings->od_gfxclk_update) { - od8_settings->od_gfxclk_update = false; - single_dpm_table = &(dpm_table->gfx_table); - - if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) { - ret = vega20_set_single_dpm_table(smu, single_dpm_table, - PPCLK_GFXCLK); - if (ret) { - pr_err("[Setoverdrive] failed to refresh dpm table!\n"); - return ret; - } - } else { - single_dpm_table->count = 1; - single_dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 100; - } - } - - break; - - default: - return -EINVAL; - } - - if (type == PP_OD_COMMIT_DPM_TABLE) { - ret = smu_handle_task(smu, smu_dpm->dpm_level, - AMD_PP_TASK_READJUST_POWER_STATE, - false); - } - - return ret; -} - -static int vega20_dpm_set_uvd_enable(struct smu_context *smu, bool enable) -{ - if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_UVD_BIT)) - return 0; - - if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UVD_BIT)) - return 0; - - return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_UVD_BIT, enable); -} - -static int vega20_dpm_set_vce_enable(struct smu_context *smu, bool enable) -{ - if (!smu_feature_is_supported(smu, SMU_FEATURE_DPM_VCE_BIT)) - return 0; - - if (enable == smu_feature_is_enabled(smu, SMU_FEATURE_DPM_VCE_BIT)) - return 0; - - return smu_feature_set_enabled(smu, SMU_FEATURE_DPM_VCE_BIT, enable); -} - -static bool vega20_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 vega20_set_thermal_fan_table(struct smu_context *smu) -{ - int ret; - struct smu_table_context *table_context = &smu->smu_table; - PPTable_t *pptable = table_context->driver_pptable; - - ret = smu_send_smc_msg_with_param(smu, - SMU_MSG_SetFanTemperatureTarget, - (uint32_t)pptable->FanTargetTemperature, - NULL); - - return ret; -} - -static int vega20_get_fan_speed_rpm(struct smu_context *smu, - uint32_t *speed) -{ - int ret; - - ret = smu_send_smc_msg(smu, SMU_MSG_GetCurrentRpm, speed); - - if (ret) { - pr_err("Attempt to get current RPM from SMC Failed!\n"); - return ret; - } - - return 0; -} - -static int vega20_get_fan_speed_percent(struct smu_context *smu, - uint32_t *speed) -{ - int ret = 0; - uint32_t current_rpm = 0, percent = 0; - PPTable_t *pptable = smu->smu_table.driver_pptable; - - ret = vega20_get_fan_speed_rpm(smu, ¤t_rpm); - if (ret) - return ret; - - percent = current_rpm * 100 / pptable->FanMaximumRpm; - *speed = percent > 100 ? 100 : percent; - - return 0; -} - -static int vega20_get_gpu_power(struct smu_context *smu, uint32_t *value) -{ - uint32_t smu_version; - int ret = 0; - SmuMetrics_t metrics; - - if (!value) - return -EINVAL; - - ret = vega20_get_metrics_table(smu, &metrics); - if (ret) - return ret; - - 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; -} - -static int vega20_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 = vega20_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 vega20_thermal_get_temperature(struct smu_context *smu, - enum amd_pp_sensors sensor, - uint32_t *value) -{ - struct amdgpu_device *adev = smu->adev; - SmuMetrics_t metrics; - uint32_t temp = 0; - int ret = 0; - - if (!value) - return -EINVAL; - - ret = vega20_get_metrics_table(smu, &metrics); - if (ret) - return ret; - - switch (sensor) { - case AMDGPU_PP_SENSOR_HOTSPOT_TEMP: - temp = RREG32_SOC15(THM, 0, mmCG_MULT_THERMAL_STATUS); - temp = (temp & CG_MULT_THERMAL_STATUS__CTF_TEMP_MASK) >> - CG_MULT_THERMAL_STATUS__CTF_TEMP__SHIFT; - - temp = temp & 0x1ff; - temp *= SMU_TEMPERATURE_UNITS_PER_CENTIGRADES; - - *value = temp; - 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 vega20_read_sensor(struct smu_context *smu, - enum amd_pp_sensors sensor, - void *data, uint32_t *size) -{ - int ret = 0; - 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; - *size = 4; - break; - case AMDGPU_PP_SENSOR_MEM_LOAD: - case AMDGPU_PP_SENSOR_GPU_LOAD: - ret = vega20_get_current_activity_percent(smu, - sensor, - (uint32_t *)data); - *size = 4; - break; - case AMDGPU_PP_SENSOR_GPU_POWER: - ret = vega20_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 = vega20_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 vega20_set_watermarks_table(struct smu_context *smu, - void *watermarks, struct - dm_pp_wm_sets_with_clock_ranges_soc15 - *clock_ranges) -{ - int i; - 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; - - for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) { - table->WatermarkRow[1][i].MinClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MaxClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MinUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz / - 1000)); - table->WatermarkRow[1][i].MaxUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz / - 1000)); - table->WatermarkRow[1][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[0][i].MinClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MaxClock = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MinUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].MaxUclk = - cpu_to_le16((uint16_t) - (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz / - 1000)); - table->WatermarkRow[0][i].WmSetting = (uint8_t) - clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id; - } - - return 0; -} - -static int vega20_get_thermal_temperature_range(struct smu_context *smu, - struct smu_temperature_range *range) -{ - struct smu_table_context *table_context = &smu->smu_table; - ATOM_Vega20_POWERPLAYTABLE *powerplay_table = table_context->power_play_table; - PPTable_t *pptable = smu->smu_table.driver_pptable; - - if (!range || !powerplay_table) - return -EINVAL; - - 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, NULL); -} - -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, - NULL); - } - - return ret; -} - -static bool vega20_is_baco_supported(struct smu_context *smu) -{ - struct amdgpu_device *adev = smu->adev; - uint32_t val; - - if (!smu_v11_0_baco_is_support(smu)) - return false; - - val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0); - return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false; -} - -static const struct pptable_funcs vega20_ppt_funcs = { - .tables_init = vega20_tables_init, - .alloc_dpm_context = vega20_allocate_dpm_context, - .store_powerplay_table = vega20_store_powerplay_table, - .check_powerplay_table = vega20_check_powerplay_table, - .append_powerplay_table = vega20_append_powerplay_table, - .get_smu_msg_index = vega20_get_smu_msg_index, - .get_smu_clk_index = vega20_get_smu_clk_index, - .get_smu_feature_index = vega20_get_smu_feature_index, - .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_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, - .set_power_state = NULL, - .populate_umd_state_clk = vega20_populate_umd_state_clk, - .print_clk_levels = vega20_print_clk_levels, - .force_clk_levels = vega20_force_clk_levels, - .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency, - .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, - .dpm_set_uvd_enable = vega20_dpm_set_uvd_enable, - .dpm_set_vce_enable = vega20_dpm_set_vce_enable, - .read_sensor = vega20_read_sensor, - .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_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, - .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, - .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, - .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= vega20_is_baco_supported, - .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) -{ - smu->ppt_funcs = &vega20_ppt_funcs; -} diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.h b/drivers/gpu/drm/amd/powerplay/vega20_ppt.h deleted file mode 100644 index 2dc10e47b767..000000000000 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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 __VEGA20_PPT_H__ -#define __VEGA20_PPT_H__ - -#define VEGA20_UMD_PSTATE_GFXCLK_LEVEL 0x3 -#define VEGA20_UMD_PSTATE_SOCCLK_LEVEL 0x3 -#define VEGA20_UMD_PSTATE_MCLK_LEVEL 0x2 -#define VEGA20_UMD_PSTATE_UVDCLK_LEVEL 0x3 -#define VEGA20_UMD_PSTATE_VCEMCLK_LEVEL 0x3 - -#define MAX_REGULAR_DPM_NUMBER 16 -#define MAX_PCIE_CONF 2 - -#define VOLTAGE_SCALE 4 -#define AVFS_CURVE 0 -#define OD8_HOTCURVE_TEMPERATURE 85 - -#define SMU_FEATURES_LOW_MASK 0x00000000FFFFFFFF -#define SMU_FEATURES_LOW_SHIFT 0 -#define SMU_FEATURES_HIGH_MASK 0xFFFFFFFF00000000 -#define SMU_FEATURES_HIGH_SHIFT 32 - -enum { - GNLD_DPM_PREFETCHER = 0, - GNLD_DPM_GFXCLK, - GNLD_DPM_UCLK, - GNLD_DPM_SOCCLK, - GNLD_DPM_UVD, - GNLD_DPM_VCE, - GNLD_ULV, - GNLD_DPM_MP0CLK, - GNLD_DPM_LINK, - GNLD_DPM_DCEFCLK, - GNLD_DS_GFXCLK, - GNLD_DS_SOCCLK, - GNLD_DS_LCLK, - GNLD_PPT, - GNLD_TDC, - GNLD_THERMAL, - GNLD_GFX_PER_CU_CG, - GNLD_RM, - GNLD_DS_DCEFCLK, - GNLD_ACDC, - GNLD_VR0HOT, - GNLD_VR1HOT, - GNLD_FW_CTF, - GNLD_LED_DISPLAY, - GNLD_FAN_CONTROL, - GNLD_DIDT, - GNLD_GFXOFF, - GNLD_CG, - GNLD_DPM_FCLK, - GNLD_DS_FCLK, - GNLD_DS_MP1CLK, - GNLD_DS_MP0CLK, - GNLD_XGMI, - GNLD_ECC, - - GNLD_FEATURES_MAX -}; - -struct vega20_dpm_level { - bool enabled; - uint32_t value; - uint32_t param1; -}; - -struct vega20_dpm_state { - uint32_t soft_min_level; - uint32_t soft_max_level; - uint32_t hard_min_level; - uint32_t hard_max_level; -}; - -struct vega20_single_dpm_table { - uint32_t count; - struct vega20_dpm_state dpm_state; - struct vega20_dpm_level dpm_levels[MAX_REGULAR_DPM_NUMBER]; -}; - -struct vega20_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 vega20_dpm_table { - struct vega20_single_dpm_table soc_table; - struct vega20_single_dpm_table gfx_table; - struct vega20_single_dpm_table mem_table; - struct vega20_single_dpm_table eclk_table; - struct vega20_single_dpm_table vclk_table; - struct vega20_single_dpm_table dclk_table; - struct vega20_single_dpm_table dcef_table; - struct vega20_single_dpm_table pixel_table; - struct vega20_single_dpm_table display_table; - struct vega20_single_dpm_table phy_table; - struct vega20_single_dpm_table fclk_table; - struct vega20_pcie_table pcie_table; -}; - -enum OD8_FEATURE_ID -{ - OD8_GFXCLK_LIMITS = 1 << 0, - OD8_GFXCLK_CURVE = 1 << 1, - OD8_UCLK_MAX = 1 << 2, - OD8_POWER_LIMIT = 1 << 3, - OD8_ACOUSTIC_LIMIT_SCLK = 1 << 4, //FanMaximumRpm - OD8_FAN_SPEED_MIN = 1 << 5, //FanMinimumPwm - OD8_TEMPERATURE_FAN = 1 << 6, //FanTargetTemperature - OD8_TEMPERATURE_SYSTEM = 1 << 7, //MaxOpTemp - OD8_MEMORY_TIMING_TUNE = 1 << 8, - OD8_FAN_ZERO_RPM_CONTROL = 1 << 9 -}; - -enum OD8_SETTING_ID -{ - OD8_SETTING_GFXCLK_FMIN = 0, - OD8_SETTING_GFXCLK_FMAX, - OD8_SETTING_GFXCLK_FREQ1, - OD8_SETTING_GFXCLK_VOLTAGE1, - OD8_SETTING_GFXCLK_FREQ2, - OD8_SETTING_GFXCLK_VOLTAGE2, - OD8_SETTING_GFXCLK_FREQ3, - OD8_SETTING_GFXCLK_VOLTAGE3, - OD8_SETTING_UCLK_FMAX, - OD8_SETTING_POWER_PERCENTAGE, - OD8_SETTING_FAN_ACOUSTIC_LIMIT, - OD8_SETTING_FAN_MIN_SPEED, - OD8_SETTING_FAN_TARGET_TEMP, - OD8_SETTING_OPERATING_TEMP_MAX, - OD8_SETTING_AC_TIMING, - OD8_SETTING_FAN_ZERO_RPM_CONTROL, - OD8_SETTING_COUNT -}; - -struct vega20_od8_single_setting { - uint32_t feature_id; - int32_t min_value; - int32_t max_value; - int32_t current_value; - int32_t default_value; -}; - -struct vega20_od8_settings { - struct vega20_od8_single_setting od8_settings_array[OD8_SETTING_COUNT]; - uint8_t *od_feature_capabilities; - uint32_t *od_settings_max; - uint32_t *od_settings_min; - void *od8_settings; - bool od_gfxclk_update; - bool od_memclk_update; -}; - -extern void vega20_set_ppt_funcs(struct smu_context *smu); - -#endif |