diff options
Diffstat (limited to 'drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c')
-rw-r--r-- | drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 221 |
1 files changed, 201 insertions, 20 deletions
diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index e84c737e3967..d143ef1b460b 100644 --- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c +++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c @@ -266,6 +266,119 @@ int smu_dpm_set_power_gate(struct smu_context *smu, uint32_t block_type, return ret; } +/** + * smu_set_user_clk_dependencies - set user profile clock dependencies + * + * @smu: smu_context pointer + * @clk: enum smu_clk_type type + * + * Enable/Disable the clock dependency for the @clk type. + */ +static void smu_set_user_clk_dependencies(struct smu_context *smu, enum smu_clk_type clk) +{ + if (smu->adev->in_suspend) + return; + + /* + * mclk, fclk and socclk are interdependent + * on each other + */ + if (clk == SMU_MCLK) { + /* reset clock dependency */ + smu->user_dpm_profile.clk_dependency = 0; + /* set mclk dependent clocks(fclk and socclk) */ + smu->user_dpm_profile.clk_dependency = BIT(SMU_FCLK) | BIT(SMU_SOCCLK); + } else if (clk == SMU_FCLK) { + /* give priority to mclk, if mclk dependent clocks are set */ + if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK))) + return; + + /* reset clock dependency */ + smu->user_dpm_profile.clk_dependency = 0; + /* set fclk dependent clocks(mclk and socclk) */ + smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_SOCCLK); + } else if (clk == SMU_SOCCLK) { + /* give priority to mclk, if mclk dependent clocks are set */ + if (smu->user_dpm_profile.clk_dependency == (BIT(SMU_FCLK) | BIT(SMU_SOCCLK))) + return; + + /* reset clock dependency */ + smu->user_dpm_profile.clk_dependency = 0; + /* set socclk dependent clocks(mclk and fclk) */ + smu->user_dpm_profile.clk_dependency = BIT(SMU_MCLK) | BIT(SMU_FCLK); + } else + /* add clk dependencies here, if any */ + return; +} + +/** + * smu_restore_dpm_user_profile - reinstate user dpm profile + * + * @smu: smu_context pointer + * + * Restore the saved user power configurations include power limit, + * clock frequencies, fan control mode and fan speed. + */ +static void smu_restore_dpm_user_profile(struct smu_context *smu) +{ + struct smu_dpm_context *smu_dpm_ctx = &(smu->smu_dpm); + int ret = 0; + + if (!smu->adev->in_suspend) + return; + + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) + return; + + /* Enable restore flag */ + smu->user_dpm_profile.flags = SMU_DPM_USER_PROFILE_RESTORE; + + /* set the user dpm power limit */ + if (smu->user_dpm_profile.power_limit) { + ret = smu_set_power_limit(smu, smu->user_dpm_profile.power_limit); + if (ret) + dev_err(smu->adev->dev, "Failed to set power limit value\n"); + } + + /* set the user dpm clock configurations */ + if (smu_dpm_ctx->dpm_level == AMD_DPM_FORCED_LEVEL_MANUAL) { + enum smu_clk_type clk_type; + + for (clk_type = 0; clk_type < SMU_CLK_COUNT; clk_type++) { + /* + * Iterate over smu clk type and force the saved user clk + * configs, skip if clock dependency is enabled + */ + if (!(smu->user_dpm_profile.clk_dependency & BIT(clk_type)) && + smu->user_dpm_profile.clk_mask[clk_type]) { + ret = smu_force_clk_levels(smu, clk_type, + smu->user_dpm_profile.clk_mask[clk_type]); + if (ret) + dev_err(smu->adev->dev, "Failed to set clock type = %d\n", + clk_type); + } + } + } + + /* set the user dpm fan configurations */ + if (smu->user_dpm_profile.fan_mode == AMD_FAN_CTRL_MANUAL) { + ret = smu_set_fan_control_mode(smu, smu->user_dpm_profile.fan_mode); + if (ret) { + dev_err(smu->adev->dev, "Failed to set manual fan control mode\n"); + return; + } + + if (!ret && smu->user_dpm_profile.fan_speed_percent) { + ret = smu_set_fan_speed_percent(smu, smu->user_dpm_profile.fan_speed_percent); + if (ret) + dev_err(smu->adev->dev, "Failed to set manual fan speed\n"); + } + } + + /* Disable restore flag */ + smu->user_dpm_profile.flags &= ~SMU_DPM_USER_PROFILE_RESTORE; +} + int smu_get_power_num_states(struct smu_context *smu, struct pp_states_info *state_info) { @@ -288,6 +401,20 @@ bool is_support_sw_smu(struct amdgpu_device *adev) return false; } +bool is_support_cclk_dpm(struct amdgpu_device *adev) +{ + struct smu_context *smu = &adev->smu; + + if (!is_support_sw_smu(adev)) + return false; + + if (!smu_feature_is_enabled(smu, SMU_FEATURE_CCLK_DPM_BIT)) + return false; + + return true; +} + + int smu_sys_get_pp_table(struct smu_context *smu, void **table) { struct smu_table_context *smu_table = &smu->smu_table; @@ -405,8 +532,6 @@ static int smu_set_funcs(struct amdgpu_device *adev) break; case CHIP_VANGOGH: vangogh_set_ppt_funcs(smu); - /* enable the OD by default to allow the fine grain tuning function */ - smu->od_enabled = true; break; default: return -EINVAL; @@ -478,9 +603,6 @@ static int smu_late_init(void *handle) smu_set_fine_grain_gfx_freq_parameters(smu); - if (adev->asic_type == CHIP_VANGOGH) - return 0; - if (!smu->pm_enabled) return 0; @@ -517,6 +639,8 @@ static int smu_late_init(void *handle) AMD_PP_TASK_COMPLETE_INIT, false); + smu_restore_dpm_user_profile(smu); + return 0; } @@ -1610,6 +1734,12 @@ int smu_force_performance_level(struct smu_context *smu, enum amd_dpm_forced_lev mutex_unlock(&smu->mutex); + /* reset user dpm clock state */ + if (!ret && smu_dpm_ctx->dpm_level != AMD_DPM_FORCED_LEVEL_MANUAL) { + memset(smu->user_dpm_profile.clk_mask, 0, sizeof(smu->user_dpm_profile.clk_mask)); + smu->user_dpm_profile.clk_dependency = 0; + } + return ret; } @@ -1644,8 +1774,13 @@ int smu_force_clk_levels(struct smu_context *smu, mutex_lock(&smu->mutex); - if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels) + if (smu->ppt_funcs && smu->ppt_funcs->force_clk_levels) { ret = smu->ppt_funcs->force_clk_levels(smu, clk_type, mask); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) { + smu->user_dpm_profile.clk_mask[clk_type] = mask; + smu_set_user_clk_dependencies(smu, clk_type); + } + } mutex_unlock(&smu->mutex); @@ -1887,6 +2022,7 @@ int smu_set_gfx_cgpg(struct smu_context *smu, bool enabled) int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) { + u32 percent; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -1894,8 +2030,12 @@ int smu_set_fan_speed_rpm(struct smu_context *smu, uint32_t speed) mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_fan_speed_rpm) - ret = smu->ppt_funcs->set_fan_speed_rpm(smu, speed); + if (smu->ppt_funcs->set_fan_speed_percent) { + percent = speed * 100 / smu->fan_max_rpm; + ret = smu->ppt_funcs->set_fan_speed_percent(smu, percent); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.fan_speed_percent = percent; + } mutex_unlock(&smu->mutex); @@ -1904,22 +2044,40 @@ 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 max_setting) + enum smu_ppt_limit_level limit_level) { + uint32_t limit_type = *limit >> 24; + int ret = 0; + if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - *limit = (max_setting ? smu->max_power_limit : smu->current_power_limit); + if (limit_type != SMU_DEFAULT_PPT_LIMIT) { + if (smu->ppt_funcs->get_ppt_limit) + ret = smu->ppt_funcs->get_ppt_limit(smu, limit, limit_type, limit_level); + } else { + switch (limit_level) { + case SMU_PPT_LIMIT_CURRENT: + *limit = smu->current_power_limit; + break; + case SMU_PPT_LIMIT_MAX: + *limit = smu->max_power_limit; + break; + default: + break; + } + } mutex_unlock(&smu->mutex); - return 0; + return ret; } int smu_set_power_limit(struct smu_context *smu, uint32_t limit) { + uint32_t limit_type = limit >> 24; int ret = 0; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) @@ -1927,6 +2085,12 @@ int smu_set_power_limit(struct smu_context *smu, uint32_t limit) mutex_lock(&smu->mutex); + if (limit_type != SMU_DEFAULT_PPT_LIMIT) + if (smu->ppt_funcs->set_power_limit) { + ret = smu->ppt_funcs->set_power_limit(smu, limit); + goto out; + } + if (limit > smu->max_power_limit) { dev_err(smu->adev->dev, "New power limit (%d) is over the max allowed %d\n", @@ -1937,8 +2101,11 @@ int smu_set_power_limit(struct smu_context *smu, uint32_t limit) if (!limit) limit = smu->current_power_limit; - if (smu->ppt_funcs->set_power_limit) + if (smu->ppt_funcs->set_power_limit) { ret = smu->ppt_funcs->set_power_limit(smu, limit); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.power_limit = limit; + } out: mutex_unlock(&smu->mutex); @@ -2115,11 +2282,19 @@ int smu_set_fan_control_mode(struct smu_context *smu, int value) mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_fan_control_mode) + if (smu->ppt_funcs->set_fan_control_mode) { ret = smu->ppt_funcs->set_fan_control_mode(smu, value); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.fan_mode = value; + } mutex_unlock(&smu->mutex); + /* reset user dpm fan speed */ + if (!ret && value != AMD_FAN_CTRL_MANUAL && + smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.fan_speed_percent = 0; + return ret; } @@ -2127,17 +2302,15 @@ int smu_get_fan_speed_percent(struct smu_context *smu, uint32_t *speed) { int ret = 0; uint32_t percent; - uint32_t current_rpm; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->get_fan_speed_rpm) { - ret = smu->ppt_funcs->get_fan_speed_rpm(smu, ¤t_rpm); + if (smu->ppt_funcs->get_fan_speed_percent) { + ret = smu->ppt_funcs->get_fan_speed_percent(smu, &percent); if (!ret) { - percent = current_rpm * 100 / smu->fan_max_rpm; *speed = percent > 100 ? 100 : percent; } } @@ -2157,8 +2330,13 @@ int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) mutex_lock(&smu->mutex); - if (smu->ppt_funcs->set_fan_speed_percent) + if (smu->ppt_funcs->set_fan_speed_percent) { + if (speed > 100) + speed = 100; ret = smu->ppt_funcs->set_fan_speed_percent(smu, speed); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.fan_speed_percent = speed; + } mutex_unlock(&smu->mutex); @@ -2168,14 +2346,17 @@ int smu_set_fan_speed_percent(struct smu_context *smu, uint32_t speed) int smu_get_fan_speed_rpm(struct smu_context *smu, uint32_t *speed) { int ret = 0; + u32 percent; if (!smu->pm_enabled || !smu->adev->pm.dpm_enabled) return -EOPNOTSUPP; mutex_lock(&smu->mutex); - if (smu->ppt_funcs->get_fan_speed_rpm) - ret = smu->ppt_funcs->get_fan_speed_rpm(smu, speed); + if (smu->ppt_funcs->get_fan_speed_percent) { + ret = smu->ppt_funcs->get_fan_speed_percent(smu, &percent); + *speed = percent * smu->fan_max_rpm / 100; + } mutex_unlock(&smu->mutex); |