Sapphire Vega 64 Nitro+ is too noisy at idle, frequently switching between zero-rpm mode and 1200 RPM. As pwm1_min is currently always 0 (and thus completely useless), I: - Made it writable so I can adjust min fan speed for "automatic" fan control - Changed amdgpu_hwmon_get_pwm1_min to return the value from fan configuration table instead of 0 Probably pwm1_auto_point#_pwm and pwm1_auto_point#_temp are a better interface to configure the fan curve, but for me it is not clear how zero-rpm mode and parameters like FanThrottlingRpm should map to it. Signed-off-by: Aleksandr Mezin <mezin.alexander at gmail.com> --- drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c | 37 +++++++++++++++++- .../gpu/drm/amd/include/kgd_pp_interface.h | 2 + drivers/gpu/drm/amd/powerplay/amd_powerplay.c | 39 +++++++++++++++++++ .../drm/amd/powerplay/hwmgr/vega10_hwmgr.c | 2 + .../drm/amd/powerplay/hwmgr/vega10_thermal.c | 23 +++++++++++ .../drm/amd/powerplay/hwmgr/vega10_thermal.h | 4 ++ drivers/gpu/drm/amd/powerplay/inc/hwmgr.h | 2 + 7 files changed, 107 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c index 8f98629fbe59..588f4b4fdc76 100644 --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_pm.c @@ -1057,7 +1057,40 @@ static ssize_t amdgpu_hwmon_get_pwm1_min(struct device *dev, struct device_attribute *attr, char *buf) { - return sprintf(buf, "%i\n", 0); + struct amdgpu_device *adev = dev_get_drvdata(dev); + void *handle = adev->powerplay.pp_handle; + int err; + u16 value = 0; + + if (adev->powerplay.pp_funcs->get_min_fan_pwm) { + err = adev->powerplay.pp_funcs->get_min_fan_pwm(handle, &value); + if (err) + return err; + } + + return sprintf(buf, "%u\n", (unsigned int)value); +} + +static ssize_t amdgpu_hwmon_set_pwm1_min(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct amdgpu_device *adev = dev_get_drvdata(dev); + void *handle = adev->powerplay.pp_handle; + int err; + u16 value; + + err = kstrtou16(buf, 10, &value); + if (err) + return err; + + if (adev->powerplay.pp_funcs->set_min_fan_pwm) { + err = adev->powerplay.pp_funcs->set_min_fan_pwm(handle, value); + if (err) + return err; + } + + return count; } static ssize_t amdgpu_hwmon_get_pwm1_max(struct device *dev, @@ -1371,7 +1404,7 @@ static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NU static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, amdgpu_hwmon_show_temp_thresh, NULL, 1); static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1, amdgpu_hwmon_set_pwm1, 0); static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1_enable, amdgpu_hwmon_set_pwm1_enable, 0); -static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, amdgpu_hwmon_get_pwm1_min, NULL, 0); +static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO | S_IWUSR, amdgpu_hwmon_get_pwm1_min, amdgpu_hwmon_set_pwm1_min, 0); static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, amdgpu_hwmon_get_pwm1_max, NULL, 0); static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, amdgpu_hwmon_get_fan1_input, NULL, 0); static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, amdgpu_hwmon_show_vddgfx, NULL, 0); diff --git a/drivers/gpu/drm/amd/include/kgd_pp_interface.h b/drivers/gpu/drm/amd/include/kgd_pp_interface.h index 6a41b81c7325..e421a6752d01 100644 --- a/drivers/gpu/drm/amd/include/kgd_pp_interface.h +++ b/drivers/gpu/drm/amd/include/kgd_pp_interface.h @@ -269,6 +269,8 @@ struct amd_pm_funcs { int (*get_display_mode_validation_clocks)(void *handle, struct amd_pp_simple_clock_info *clocks); int (*notify_smu_enable_pwe)(void *handle); + int (*set_min_fan_pwm)(void *handle, u16 value); + int (*get_min_fan_pwm)(void *handle, u16 *value); }; #endif diff --git a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c index 7a646f94b478..f3c4b0b937e3 100644 --- a/drivers/gpu/drm/amd/powerplay/amd_powerplay.c +++ b/drivers/gpu/drm/amd/powerplay/amd_powerplay.c @@ -522,6 +522,43 @@ static uint32_t pp_dpm_get_fan_control_mode(void *handle) return mode; } +static int pp_dpm_set_min_fan_pwm(void *handle, uint16_t value) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL; + + if (hwmgr->hwmgr_func->set_min_fan_pwm == NULL) { + pr_info("%s was not implemented.\n", __func__); + return 0; + } + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->set_min_fan_pwm(hwmgr, value); + mutex_unlock(&hwmgr->smu_lock); + return ret; +} + +static int pp_dpm_get_min_fan_pwm(void *handle, uint16_t *value) +{ + struct pp_hwmgr *hwmgr = handle; + int ret = 0; + + if (!hwmgr || !hwmgr->pm_en) + return -EINVAL; + + if (hwmgr->hwmgr_func->get_min_fan_pwm == NULL) { + *value = 0; + return 0; + } + + mutex_lock(&hwmgr->smu_lock); + ret = hwmgr->hwmgr_func->get_min_fan_pwm(hwmgr, value); + mutex_unlock(&hwmgr->smu_lock); + return ret; +} + static int pp_dpm_set_fan_speed_percent(void *handle, uint32_t percent) { struct pp_hwmgr *hwmgr = handle; @@ -1269,4 +1306,6 @@ static const struct amd_pm_funcs pp_dpm_funcs = { .display_clock_voltage_request = pp_display_clock_voltage_request, .get_display_mode_validation_clocks = pp_get_display_mode_validation_clocks, .notify_smu_enable_pwe = pp_notify_smu_enable_pwe, + .set_min_fan_pwm = pp_dpm_set_min_fan_pwm, + .get_min_fan_pwm = pp_dpm_get_min_fan_pwm, }; diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c index fb86c24394ff..6d766949ff26 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_hwmgr.c @@ -4913,6 +4913,8 @@ static const struct pp_hwmgr_func vega10_hwmgr_funcs = { .set_power_profile_mode = vega10_set_power_profile_mode, .set_power_limit = vega10_set_power_limit, .odn_edit_dpm_table = vega10_odn_edit_dpm_table, + .get_min_fan_pwm = vega10_fan_ctrl_get_min_pwm, + .set_min_fan_pwm = vega10_fan_ctrl_set_min_pwm, }; int vega10_enable_smc_features(struct pp_hwmgr *hwmgr, diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c index aa044c1955fe..28ebea24576b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.c @@ -616,3 +616,26 @@ int vega10_thermal_ctrl_uninitialize_thermal_controller(struct pp_hwmgr *hwmgr) } return 0; } + +int vega10_fan_ctrl_get_min_pwm(struct pp_hwmgr *hwmgr, uint16_t *value) +{ + struct vega10_hwmgr *data = hwmgr->backend; + PPTable_t *table = &(data->smc_state_table.pp_table); + + *value = table->FanPwmMin; + return 0; +} + +int vega10_fan_ctrl_set_min_pwm(struct pp_hwmgr *hwmgr, uint16_t value) +{ + struct vega10_hwmgr *data = hwmgr->backend; + PPTable_t *table = &(data->smc_state_table.pp_table); + + if (value > 255) + value = 255; + + table->FanPwmMin = value; + hwmgr->thermal_controller.advanceFanControlParameters.usPWMMin = value * 100 / 255; + + return smum_send_msg_to_smc_with_parameter(hwmgr, PPSMC_MSG_SetFanMinPwm, table->FanPwmMin); +} diff --git a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h index 21e7c4dfa2ca..bce15e293e6b 100644 --- a/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h +++ b/drivers/gpu/drm/amd/powerplay/hwmgr/vega10_thermal.h @@ -73,6 +73,10 @@ extern int vega10_thermal_disable_alert(struct pp_hwmgr *hwmgr); extern int vega10_fan_ctrl_start_smc_fan_control(struct pp_hwmgr *hwmgr); extern int vega10_start_thermal_controller(struct pp_hwmgr *hwmgr, struct PP_TemperatureRange *range); +extern int vega10_fan_ctrl_get_min_pwm(struct pp_hwmgr *hwmgr, + uint16_t *value); +extern int vega10_fan_ctrl_set_min_pwm(struct pp_hwmgr *hwmgr, + uint16_t value); #endif diff --git a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h index d3d96260f440..f104b8212e89 100644 --- a/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h +++ b/drivers/gpu/drm/amd/powerplay/inc/hwmgr.h @@ -328,6 +328,8 @@ struct pp_hwmgr_func { int (*set_power_limit)(struct pp_hwmgr *hwmgr, uint32_t n); int (*powergate_mmhub)(struct pp_hwmgr *hwmgr); int (*smus_notify_pwe)(struct pp_hwmgr *hwmgr); + int (*get_min_fan_pwm)(struct pp_hwmgr *hwmgr, uint16_t *value); + int (*set_min_fan_pwm)(struct pp_hwmgr *hwmgr, uint16_t value); }; struct pp_table_func { -- 2.18.0