Commit eb3b4251 authored by Arunpravin's avatar Arunpravin Committed by Alex Deucher

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: default avatarArunpravin <Arunpravin.PaneerSelvam@amd.com>
Acked-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Reviewed-by: default avatarLijo Lazar <lijo.lazar@amd.com>
Reviewed-by: default avatarKevin Wang <kevin1.wang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 64dcf2f0
......@@ -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;
......
......@@ -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;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment