#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
#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
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);
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, ¤t_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;
}
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;
.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,
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;
.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,
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;
.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,
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)