]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
drm/amd/pm: store and reinstate swsmu user power configurations
authorArunpravin <Arunpravin.PaneerSelvam@amd.com>
Tue, 19 Jan 2021 18:17:32 +0000 (23:47 +0530)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 25 Jan 2021 22:47:00 +0000 (17:47 -0500)
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 <Arunpravin.PaneerSelvam@amd.com>
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Reviewed-by: Kevin Wang <kevin1.wang@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/inc/amdgpu_smu.h
drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c

index a087e00382e61ab9d6b5cb814de010775bd22f12..631a36a75ae33ce13ca7676c5a58c2fe62304c4f 100644 (file)
@@ -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;
index 7fe61ad3ed105178c961e34e9f0b38cd1337a3fd..f958b02f9317b8eb85ea3b6e15b14a3899a73bed 100644 (file)
@@ -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;
 }