drm/amd/pm: correct the fan speed PWM retrieving
authorEvan Quan <evan.quan@amd.com>
Tue, 9 Feb 2021 04:10:43 +0000 (12:10 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 16 Aug 2021 19:35:56 +0000 (15:35 -0400)
The relationship "PWM = RPM / smu->fan_max_rpm" between fan speed
PWM and RPM is not true for SMU11 ASICs. So, we need a new way to
retrieving the fan speed PWM.

Signed-off-by: Evan Quan <evan.quan@amd.com>
Reviewed-by: Lijo Lazar <lijo.lazar@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_offset.h
drivers/gpu/drm/amd/include/asic_reg/thm/thm_11_0_2_sh_mask.h
drivers/gpu/drm/amd/pm/inc/smu_v11_0.h
drivers/gpu/drm/amd/pm/powerplay/hwmgr/vega20_thermal.c
drivers/gpu/drm/amd/pm/swsmu/smu11/arcturus_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/navi10_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/sienna_cichlid_ppt.c
drivers/gpu/drm/amd/pm/swsmu/smu11/smu_v11_0.c

index a485526..eca96ab 100644 (file)
@@ -49,4 +49,7 @@
 #define mmTHM_BACO_CNTL                                                                                0x0081
 #define mmTHM_BACO_CNTL_BASE_IDX                                                                       0
 
+#define mmCG_THERMAL_STATUS                                                                            0x006C
+#define mmCG_THERMAL_STATUS_BASE_IDX                                                                   0
+
 #endif
index d130d92..f2f9eae 100644 (file)
@@ -92,5 +92,8 @@
 #define THM_TCON_THERM_TRIP__RSVD3_MASK                                                                       0x7FFFC000L
 #define THM_TCON_THERM_TRIP__SW_THERM_TP_MASK                                                                 0x80000000L
 
+#define CG_THERMAL_STATUS__FDO_PWM_DUTY__SHIFT                                                                0x9
+#define CG_THERMAL_STATUS__FDO_PWM_DUTY_MASK                                                                  0x0001FE00L
+
 #endif
 
index b9c8a92..ff31be2 100644 (file)
@@ -227,6 +227,9 @@ int smu_v11_0_set_fan_speed_percent(struct smu_context *smu,
 int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
                                uint32_t speed);
 
+int smu_v11_0_get_fan_speed_percent(struct smu_context *smu,
+                                   uint32_t *speed);
+
 int smu_v11_0_set_xgmi_pstate(struct smu_context *smu,
                                     uint32_t pstate);
 
index 269dd7e..43d7549 100644 (file)
@@ -117,18 +117,24 @@ static int vega20_get_current_rpm(struct pp_hwmgr *hwmgr, uint32_t *current_rpm)
 int vega20_fan_ctrl_get_fan_speed_percent(struct pp_hwmgr *hwmgr,
                uint32_t *speed)
 {
-       struct vega20_hwmgr *data = (struct vega20_hwmgr *)(hwmgr->backend);
-       PPTable_t *pp_table = &(data->smc_state_table.pp_table);
-       uint32_t current_rpm, percent = 0;
-       int ret = 0;
+       struct amdgpu_device *adev = hwmgr->adev;
+       uint32_t duty100, duty;
+       uint64_t tmp64;
 
-       ret = vega20_get_current_rpm(hwmgr, &current_rpm);
-       if (ret)
-               return ret;
+       duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
+                               CG_FDO_CTRL1, FMAX_DUTY100);
+       duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
+                               CG_THERMAL_STATUS, FDO_PWM_DUTY);
+
+       if (!duty100)
+               return -EINVAL;
 
-       percent = current_rpm * 100 / pp_table->FanMaximumRpm;
+       tmp64 = (uint64_t)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (uint32_t)tmp64;
 
-       *speed = percent > 100 ? 100 : percent;
+       if (*speed > 100)
+               *speed = 100;
 
        return 0;
 }
index df902d3..cbaea73 100644 (file)
@@ -1162,29 +1162,6 @@ static int arcturus_read_sensor(struct smu_context *smu,
        return ret;
 }
 
-static int arcturus_get_fan_speed_percent(struct smu_context *smu,
-                                         uint32_t *speed)
-{
-       int ret;
-       u32 rpm;
-
-       if (!speed)
-               return -EINVAL;
-
-       switch (smu_v11_0_get_fan_control_mode(smu)) {
-       case AMD_FAN_CTRL_AUTO:
-               ret = arcturus_get_smu_metrics_data(smu,
-                                                   METRICS_CURR_FANSPEED,
-                                                   &rpm);
-               if (!ret && smu->fan_max_rpm)
-                       *speed = rpm * 100 / smu->fan_max_rpm;
-               return ret;
-       default:
-               *speed = smu->user_dpm_profile.fan_speed_percent;
-               return 0;
-       }
-}
-
 static int arcturus_get_fan_parameters(struct smu_context *smu)
 {
        PPTable_t *pptable = smu->smu_table.driver_pptable;
@@ -2270,7 +2247,7 @@ static const struct pptable_funcs arcturus_ppt_funcs = {
        .print_clk_levels = arcturus_print_clk_levels,
        .force_clk_levels = arcturus_force_clk_levels,
        .read_sensor = arcturus_read_sensor,
-       .get_fan_speed_percent = arcturus_get_fan_speed_percent,
+       .get_fan_speed_percent = smu_v11_0_get_fan_speed_percent,
        .get_power_profile_mode = arcturus_get_power_profile_mode,
        .set_power_profile_mode = arcturus_set_power_profile_mode,
        .set_performance_level = arcturus_set_performance_level,
index c748f70..52943ed 100644 (file)
@@ -1671,29 +1671,6 @@ static bool navi10_is_dpm_running(struct smu_context *smu)
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
-static int navi10_get_fan_speed_percent(struct smu_context *smu,
-                                       uint32_t *speed)
-{
-       int ret;
-       u32 rpm;
-
-       if (!speed)
-               return -EINVAL;
-
-       switch (smu_v11_0_get_fan_control_mode(smu)) {
-       case AMD_FAN_CTRL_AUTO:
-               ret = navi1x_get_smu_metrics_data(smu,
-                                                 METRICS_CURR_FANSPEED,
-                                                 &rpm);
-               if (!ret && smu->fan_max_rpm)
-                       *speed = rpm * 100 / smu->fan_max_rpm;
-               return ret;
-       default:
-               *speed = smu->user_dpm_profile.fan_speed_percent;
-               return 0;
-       }
-}
-
 static int navi10_get_fan_parameters(struct smu_context *smu)
 {
        PPTable_t *pptable = smu->smu_table.driver_pptable;
@@ -3227,7 +3204,7 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .display_config_changed = navi10_display_config_changed,
        .notify_smc_display_config = navi10_notify_smc_display_config,
        .is_dpm_running = navi10_is_dpm_running,
-       .get_fan_speed_percent = navi10_get_fan_speed_percent,
+       .get_fan_speed_percent = smu_v11_0_get_fan_speed_percent,
        .get_power_profile_mode = navi10_get_power_profile_mode,
        .set_power_profile_mode = navi10_set_power_profile_mode,
        .set_watermarks_table = navi10_set_watermarks_table,
index 5b73af7..cb60e89 100644 (file)
@@ -1354,29 +1354,6 @@ static bool sienna_cichlid_is_dpm_running(struct smu_context *smu)
        return !!(feature_enabled & SMC_DPM_FEATURE);
 }
 
-static int sienna_cichlid_get_fan_speed_percent(struct smu_context *smu,
-                                               uint32_t *speed)
-{
-       int ret;
-       u32 rpm;
-
-       if (!speed)
-               return -EINVAL;
-
-       switch (smu_v11_0_get_fan_control_mode(smu)) {
-       case AMD_FAN_CTRL_AUTO:
-               ret = sienna_cichlid_get_smu_metrics_data(smu,
-                                                         METRICS_CURR_FANSPEED,
-                                                         &rpm);
-               if (!ret && smu->fan_max_rpm)
-                       *speed = rpm * 100 / smu->fan_max_rpm;
-               return ret;
-       default:
-               *speed = smu->user_dpm_profile.fan_speed_percent;
-               return 0;
-       }
-}
-
 static int sienna_cichlid_get_fan_parameters(struct smu_context *smu)
 {
        uint16_t *table_member;
@@ -3859,7 +3836,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
        .display_config_changed = sienna_cichlid_display_config_changed,
        .notify_smc_display_config = sienna_cichlid_notify_smc_display_config,
        .is_dpm_running = sienna_cichlid_is_dpm_running,
-       .get_fan_speed_percent = sienna_cichlid_get_fan_speed_percent,
+       .get_fan_speed_percent = smu_v11_0_get_fan_speed_percent,
        .get_power_profile_mode = sienna_cichlid_get_power_profile_mode,
        .set_power_profile_mode = sienna_cichlid_set_power_profile_mode,
        .set_watermarks_table = sienna_cichlid_set_watermarks_table,
index 007f84b..1f3230f 100644 (file)
@@ -1263,6 +1263,41 @@ int smu_v11_0_set_fan_speed_rpm(struct smu_context *smu,
        return ret;
 }
 
+int smu_v11_0_get_fan_speed_percent(struct smu_context *smu,
+                                   uint32_t *speed)
+{
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t duty100, duty;
+       uint64_t tmp64;
+
+       /*
+        * For pre Sienna Cichlid ASICs, the 0 RPM may be not correctly
+        * detected via register retrieving. To workaround this, we will
+        * report the fan speed as 0 PWM if user just requested such.
+        */
+       if ((smu->user_dpm_profile.flags & SMU_CUSTOM_FAN_SPEED_PWM)
+            && !smu->user_dpm_profile.fan_speed_percent) {
+               *speed = 0;
+               return 0;
+       }
+
+       duty100 = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_FDO_CTRL1),
+                               CG_FDO_CTRL1, FMAX_DUTY100);
+       duty = REG_GET_FIELD(RREG32_SOC15(THM, 0, mmCG_THERMAL_STATUS),
+                               CG_THERMAL_STATUS, FDO_PWM_DUTY);
+       if (!duty100)
+               return -EINVAL;
+
+       tmp64 = (uint64_t)duty * 100;
+       do_div(tmp64, duty100);
+       *speed = (uint32_t)tmp64;
+
+       if (*speed > 100)
+               *speed = 100;
+
+       return 0;
+}
+
 int
 smu_v11_0_set_fan_control_mode(struct smu_context *smu,
                               uint32_t mode)