From eb3b425166cbdb942b7c38bd9998b97837bd6b29 Mon Sep 17 00:00:00 2001 From: Arunpravin Date: Tue, 19 Jan 2021 23:47:32 +0530 Subject: [PATCH] drm/amd/pm: store and reinstate swsmu user power configurations store swsmu user power configurations which include power limit, clock frequencies, fan speed and fan mode on suspend and reinstate on resume. V2: Addressed Lijo's review comments added a function to set clock interdependencies add check on fan control mode to reapply fan speed V3: Addressed review comments from Alex moved store logic and reinstate function call into swSMU V4: added a logic to keep off storing configurations in suspend V5: Addressed review comments from Lijo add a restore flag give restore priority to mclk comparing fclk and socclk Signed-off-by: Arunpravin Acked-by: Alex Deucher Reviewed-by: Lijo Lazar Reviewed-by: Kevin Wang Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h | 15 +++ drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 148 +++++++++++++++++++++- 2 files changed, 159 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h index a087e00382e6..631a36a75ae3 100644 --- a/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h +++ b/drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h @@ -33,6 +33,8 @@ #define SMU_TEMPERATURE_UNITS_PER_CENTIGRADES 1000 #define SMU_FW_NAME_LEN 0x24 +#define SMU_DPM_USER_PROFILE_RESTORE (1 << 0) + struct smu_hw_power_state { unsigned int magic; }; @@ -168,6 +170,17 @@ enum smu_memory_pool_size SMU_MEMORY_POOL_SIZE_2_GB = 0x80000000, }; +struct smu_user_dpm_profile { + uint32_t fan_mode; + uint32_t power_limit; + uint32_t fan_speed_rpm; + uint32_t flags; + + /* user clock state information */ + uint32_t clk_mask[SMU_CLK_COUNT]; + uint32_t clk_dependency; +}; + #define SMU_TABLE_INIT(tables, table_id, s, a, d) \ do { \ tables[table_id].size = s; \ @@ -473,6 +486,8 @@ struct smu_context uint32_t cpu_actual_soft_max_freq; uint32_t cpu_core_id_select; uint16_t cpu_core_num; + + struct smu_user_dpm_profile user_dpm_profile; }; struct i2c_adapter; diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c index 7fe61ad3ed10..f958b02f9317 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_rpm) { + ret = smu_set_fan_speed_rpm(smu, smu->user_dpm_profile.fan_speed_rpm); + 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) { @@ -529,6 +642,8 @@ static int smu_late_init(void *handle) AMD_PP_TASK_COMPLETE_INIT, false); + smu_restore_dpm_user_profile(smu); + return 0; } @@ -1622,6 +1737,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; } @@ -1656,8 +1777,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); @@ -1906,8 +2032,11 @@ 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) + if (smu->ppt_funcs->set_fan_speed_rpm) { ret = smu->ppt_funcs->set_fan_speed_rpm(smu, speed); + if (!ret && smu->user_dpm_profile.flags != SMU_DPM_USER_PROFILE_RESTORE) + smu->user_dpm_profile.fan_speed_rpm = speed; + } mutex_unlock(&smu->mutex); @@ -1949,8 +2078,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); @@ -2127,11 +2259,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_rpm = 0; + return ret; } -- 2.39.5