From 9a431038e30a45c470c5f949824a76538809662d Mon Sep 17 00:00:00 2001 From: Chengming Gui Date: Fri, 18 Jan 2019 11:27:25 +0800 Subject: [PATCH] drm/amd/powerplay: implement power_dpm_force_performance_level for SMU11 add get_performance_level and force_performance_level to implement the sys interface for SMU11. Signed-off-by: Chengming Gui Reviewed-by: Huang Rui Acked-by: Alex Deucher Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 23 ++++- drivers/gpu/drm/amd/powerplay/amdgpu_smu.c | 2 + .../gpu/drm/amd/powerplay/inc/amdgpu_smu.h | 6 ++ drivers/gpu/drm/amd/powerplay/smu_v11_0.c | 2 - drivers/gpu/drm/amd/powerplay/vega20_ppt.c | 99 +++++++++++++++++++ 5 files changed, 127 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 694d85b0f0a0..77d946f8fca5 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -264,7 +264,9 @@ static ssize_t amdgpu_get_dpm_forced_performance_level(struct device *dev, (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) return snprintf(buf, PAGE_SIZE, "off\n"); - if (adev->powerplay.pp_funcs->get_performance_level) + if (is_support_sw_smu(adev)) + level = smu_get_performance_level(&adev->smu); + else if (adev->powerplay.pp_funcs->get_performance_level) level = amdgpu_dpm_get_performance_level(adev); else level = adev->pm.dpm.forced_level; @@ -297,7 +299,9 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev, (ddev->switch_power_state != DRM_SWITCH_POWER_ON)) return -EINVAL; - if (adev->powerplay.pp_funcs->get_performance_level) + if (is_support_sw_smu(adev)) + current_level = smu_get_performance_level(&adev->smu); + else if (adev->powerplay.pp_funcs->get_performance_level) current_level = amdgpu_dpm_get_performance_level(adev); if (strncmp("low", buf, strlen("low")) == 0) { @@ -326,7 +330,20 @@ static ssize_t amdgpu_set_dpm_forced_performance_level(struct device *dev, if (current_level == level) return count; - if (adev->powerplay.pp_funcs->force_performance_level) { + if (is_support_sw_smu(adev)) { + mutex_lock(&adev->pm.mutex); + if (adev->pm.dpm.thermal_active) { + count = -EINVAL; + mutex_unlock(&adev->pm.mutex); + goto fail; + } + ret = smu_force_performance_level(&adev->smu, level); + if (ret) + count = -EINVAL; + else + adev->pm.dpm.forced_level = level; + mutex_unlock(&adev->pm.mutex); + } else if (adev->powerplay.pp_funcs->force_performance_level) { mutex_lock(&adev->pm.mutex); if (adev->pm.dpm.thermal_active) { count = -EINVAL; diff --git a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c index 83fadcac18e6..2917411a10eb 100644 --- a/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/powerplay/amdgpu_smu.c @@ -351,6 +351,8 @@ static int smu_sw_init(void *handle) smu->workload_setting[6] = PP_SMC_POWER_PROFILE_CUSTOM; smu->display_config = &adev->pm.pm_display_cfg; + smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO; + 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"); diff --git a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h index 63cd1ba60dc2..111424d0581d 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/powerplay/inc/amdgpu_smu.h @@ -423,6 +423,8 @@ 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); + enum amd_dpm_forced_level (*get_performance_level)(struct smu_context *smu); + int (*force_performance_level)(struct smu_context *smu, enum amd_dpm_forced_level level); }; struct smu_funcs @@ -594,6 +596,10 @@ struct smu_funcs ((smu)->funcs->get_power_profile_mode ? (smu)->funcs->get_power_profile_mode((smu), buf) : 0) #define smu_set_power_profile_mode(smu, param, param_size) \ ((smu)->funcs->set_power_profile_mode ? (smu)->funcs->set_power_profile_mode((smu), (param), (param_size)) : 0) +#define smu_get_performance_level(smu) \ + ((smu)->ppt_funcs->get_performance_level ? (smu)->ppt_funcs->get_performance_level((smu)) : 0) +#define smu_force_performance_level(smu, level) \ + ((smu)->ppt_funcs->force_performance_level ? (smu)->ppt_funcs->force_performance_level((smu), (level)) : 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) diff --git a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c index 93552d8c39fb..74ad160e1335 100644 --- a/drivers/gpu/drm/amd/powerplay/smu_v11_0.c +++ b/drivers/gpu/drm/amd/powerplay/smu_v11_0.c @@ -1100,7 +1100,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, PPCLK_e clk_select = 0; uint32_t clk_freq = clock_req->clock_freq_in_khz / 1000; - mutex_lock(&smu->mutex); if (smu_feature_is_enabled(smu, FEATURE_DPM_DCEFCLK_BIT)) { switch (clk_type) { case amd_pp_dcef_clock: @@ -1129,7 +1128,6 @@ smu_v11_0_display_clock_voltage_request(struct smu_context *smu, } failed: - mutex_unlock(&smu->mutex); return ret; } diff --git a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c index 5de0eabbeb29..911296d1f7cc 100644 --- a/drivers/gpu/drm/amd/powerplay/vega20_ppt.c +++ b/drivers/gpu/drm/amd/powerplay/vega20_ppt.c @@ -1744,6 +1744,103 @@ static int vega20_unforce_dpm_levels(struct smu_context *smu) return ret; } +static enum amd_dpm_forced_level vega20_get_performance_level(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + if (!smu_dpm_ctx->dpm_context) + return -EINVAL; + + if (smu_dpm_ctx->dpm_level != smu_dpm_ctx->saved_dpm_level) { + mutex_lock(&(smu->mutex)); + smu_dpm_ctx->saved_dpm_level = smu_dpm_ctx->dpm_level; + mutex_unlock(&(smu->mutex)); + } + return smu_dpm_ctx->dpm_level; +} + +static int +vega20_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_level level) +{ + int ret = 0; + int index = 0; + int i = 0; + uint32_t sclk_mask, mclk_mask, soc_mask; + long workload; + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + if (!smu_dpm_ctx->dpm_context) + return -EINVAL; + + for (i = 0; i < smu->adev->num_ip_blocks; i++) { + if (smu->adev->ip_blocks[i].version->type == AMD_IP_BLOCK_TYPE_SMC) + break; + } + mutex_lock(&smu->mutex); + smu->adev->ip_blocks[i].version->funcs->enable_umd_pstate(smu, &level); + ret = vega20_display_config_changed(smu); + if (ret) { + pr_err("Failed to change display config!"); + goto failed; + } + ret = vega20_apply_clocks_adjust_rules(smu); + if (ret) { + pr_err("Failed to apply clocks adjust rules!"); + goto failed; + } + ret = vega20_notify_smc_dispaly_config(smu); + if (ret) { + pr_err("Failed to notify smc display config!"); + goto failed; + } + switch (level) { + case AMD_DPM_FORCED_LEVEL_HIGH: + ret = vega20_force_dpm_highest(smu); + break; + + case AMD_DPM_FORCED_LEVEL_LOW: + ret = vega20_force_dpm_lowest(smu); + break; + + case AMD_DPM_FORCED_LEVEL_AUTO: + ret = vega20_unforce_dpm_levels(smu); + break; + + case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK: + case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK: + ret = vega20_get_profiling_clk_mask(smu, level, + &sclk_mask, + &mclk_mask, + &soc_mask); + if (ret) + goto failed; + vega20_force_clk_levels(smu, PP_SCLK, 1 << sclk_mask); + vega20_force_clk_levels(smu, PP_MCLK, 1 << mclk_mask); + break; + + case AMD_DPM_FORCED_LEVEL_MANUAL: + case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT: + default: + break; + } + + if (!ret) + smu_dpm_ctx->dpm_level = level; + + if (smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { + index = fls(smu->workload_mask); + index = index > 0 && index <= WORKLOAD_POLICY_MAX ? index - 1 : 0; + workload = smu->workload_setting[index]; + + if (smu->power_profile_mode != workload) + smu->funcs->set_power_profile_mode(smu, &workload, 0); + } + +failed: + mutex_unlock(&smu->mutex); + return ret; +} + static const struct pptable_funcs vega20_ppt_funcs = { .alloc_dpm_context = vega20_allocate_dpm_context, .store_powerplay_table = vega20_store_powerplay_table, @@ -1761,6 +1858,8 @@ static const struct pptable_funcs vega20_ppt_funcs = { .get_clock_by_type_with_latency = vega20_get_clock_by_type_with_latency, .set_default_od8_settings = vega20_set_default_od8_setttings, .get_od_percentage = vega20_get_od_percentage, + .get_performance_level = vega20_get_performance_level, + .force_performance_level = vega20_force_performance_level, }; void vega20_set_ppt_funcs(struct smu_context *smu) -- 2.30.2