mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-15 21:23:23 +00:00
drm/amd/pm: add fan temperature/pwm curve OD setting support for SMU13
Add SMU13 fan temperature/pwm curve OD setting support. Signed-off-by: Evan Quan <evan.quan@amd.com> Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
parent
1cf36599b9
commit
d7bf1b556f
@ -64,6 +64,12 @@ gpu_metrics
|
||||
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
|
||||
:doc: gpu_metrics
|
||||
|
||||
fan_curve
|
||||
---------
|
||||
|
||||
.. kernel-doc:: drivers/gpu/drm/amd/pm/amdgpu_pm.c
|
||||
:doc: fan_curve
|
||||
|
||||
GFXOFF
|
||||
======
|
||||
|
||||
|
@ -113,6 +113,7 @@ enum pp_clock_type {
|
||||
OD_RANGE,
|
||||
OD_VDDGFX_OFFSET,
|
||||
OD_CCLK,
|
||||
OD_FAN_CURVE,
|
||||
};
|
||||
|
||||
enum amd_pp_sensors {
|
||||
@ -186,7 +187,8 @@ enum PP_OD_DPM_TABLE_COMMAND {
|
||||
PP_OD_EDIT_VDDC_CURVE,
|
||||
PP_OD_RESTORE_DEFAULT_TABLE,
|
||||
PP_OD_COMMIT_DPM_TABLE,
|
||||
PP_OD_EDIT_VDDGFX_OFFSET
|
||||
PP_OD_EDIT_VDDGFX_OFFSET,
|
||||
PP_OD_EDIT_FAN_CURVE,
|
||||
};
|
||||
|
||||
struct pp_states_info {
|
||||
|
@ -3383,7 +3383,215 @@ static const struct attribute_group *hwmon_groups[] = {
|
||||
NULL
|
||||
};
|
||||
|
||||
static struct od_feature_set amdgpu_od_set;
|
||||
static int amdgpu_retrieve_od_settings(struct amdgpu_device *adev,
|
||||
enum pp_clock_type od_type,
|
||||
char *buf)
|
||||
{
|
||||
int size = 0;
|
||||
int ret;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
if (adev->in_suspend && !adev->in_runpm)
|
||||
return -EPERM;
|
||||
|
||||
ret = pm_runtime_get_sync(adev->dev);
|
||||
if (ret < 0) {
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
size = amdgpu_dpm_print_clock_levels(adev, od_type, buf);
|
||||
if (size == 0)
|
||||
size = sysfs_emit(buf, "\n");
|
||||
|
||||
pm_runtime_mark_last_busy(adev->dev);
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static int parse_input_od_command_lines(const char *buf,
|
||||
size_t count,
|
||||
u32 *type,
|
||||
long *params,
|
||||
uint32_t *num_of_params)
|
||||
{
|
||||
const char delimiter[3] = {' ', '\n', '\0'};
|
||||
uint32_t parameter_size = 0;
|
||||
char buf_cpy[128] = {0};
|
||||
char *tmp_str, *sub_str;
|
||||
int ret;
|
||||
|
||||
if (count > sizeof(buf_cpy) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(buf_cpy, buf, count);
|
||||
tmp_str = buf_cpy;
|
||||
|
||||
/* skip heading spaces */
|
||||
while (isspace(*tmp_str))
|
||||
tmp_str++;
|
||||
|
||||
switch (*tmp_str) {
|
||||
case 'c':
|
||||
*type = PP_OD_COMMIT_DPM_TABLE;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while ((sub_str = strsep(&tmp_str, delimiter)) != NULL) {
|
||||
if (strlen(sub_str) == 0)
|
||||
continue;
|
||||
|
||||
ret = kstrtol(sub_str, 0, ¶ms[parameter_size]);
|
||||
if (ret)
|
||||
return -EINVAL;
|
||||
parameter_size++;
|
||||
|
||||
while (isspace(*tmp_str))
|
||||
tmp_str++;
|
||||
}
|
||||
|
||||
*num_of_params = parameter_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
amdgpu_distribute_custom_od_settings(struct amdgpu_device *adev,
|
||||
enum PP_OD_DPM_TABLE_COMMAND cmd_type,
|
||||
const char *in_buf,
|
||||
size_t count)
|
||||
{
|
||||
uint32_t parameter_size = 0;
|
||||
long parameter[64];
|
||||
int ret;
|
||||
|
||||
if (amdgpu_in_reset(adev))
|
||||
return -EPERM;
|
||||
if (adev->in_suspend && !adev->in_runpm)
|
||||
return -EPERM;
|
||||
|
||||
ret = parse_input_od_command_lines(in_buf,
|
||||
count,
|
||||
&cmd_type,
|
||||
parameter,
|
||||
¶meter_size);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = pm_runtime_get_sync(adev->dev);
|
||||
if (ret < 0)
|
||||
goto err_out0;
|
||||
|
||||
ret = amdgpu_dpm_odn_edit_dpm_table(adev,
|
||||
cmd_type,
|
||||
parameter,
|
||||
parameter_size);
|
||||
if (ret)
|
||||
goto err_out1;
|
||||
|
||||
if (cmd_type == PP_OD_COMMIT_DPM_TABLE) {
|
||||
ret = amdgpu_dpm_dispatch_task(adev,
|
||||
AMD_PP_TASK_READJUST_POWER_STATE,
|
||||
NULL);
|
||||
if (ret)
|
||||
goto err_out1;
|
||||
}
|
||||
|
||||
pm_runtime_mark_last_busy(adev->dev);
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
|
||||
return count;
|
||||
|
||||
err_out1:
|
||||
pm_runtime_mark_last_busy(adev->dev);
|
||||
err_out0:
|
||||
pm_runtime_put_autosuspend(adev->dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* DOC: fan_curve
|
||||
*
|
||||
* The amdgpu driver provides a sysfs API for checking and adjusting the fan
|
||||
* control curve line.
|
||||
*
|
||||
* Reading back the file shows you the current settings(temperature in Celsius
|
||||
* degree and fan speed in pwm) applied to every anchor point of the curve line
|
||||
* and their permitted ranges if changable.
|
||||
*
|
||||
* Writing a desired string(with the format like "anchor_point_index temperature
|
||||
* fan_speed_in_pwm") to the file, change the settings for the specific anchor
|
||||
* point accordingly.
|
||||
*
|
||||
* When you have finished the editing, write "c" (commit) to the file to commit
|
||||
* your changes.
|
||||
*
|
||||
* There are two fan control modes supported: auto and manual. With auto mode,
|
||||
* PMFW handles the fan speed control(how fan speed reacts to ASIC temperature).
|
||||
* While with manual mode, users can set their own fan curve line as what
|
||||
* described here. Normally the ASIC is booted up with auto mode. Any
|
||||
* settings via this interface will switch the fan control to manual mode
|
||||
* implicitly.
|
||||
*/
|
||||
static ssize_t fan_curve_show(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct od_kobj *container = container_of(kobj, struct od_kobj, kobj);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)container->priv;
|
||||
|
||||
return (ssize_t)amdgpu_retrieve_od_settings(adev, OD_FAN_CURVE, buf);
|
||||
}
|
||||
|
||||
static ssize_t fan_curve_store(struct kobject *kobj,
|
||||
struct kobj_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
struct od_kobj *container = container_of(kobj, struct od_kobj, kobj);
|
||||
struct amdgpu_device *adev = (struct amdgpu_device *)container->priv;
|
||||
|
||||
return (ssize_t)amdgpu_distribute_custom_od_settings(adev,
|
||||
PP_OD_EDIT_FAN_CURVE,
|
||||
buf,
|
||||
count);
|
||||
}
|
||||
|
||||
static umode_t fan_curve_visible(struct amdgpu_device *adev)
|
||||
{
|
||||
umode_t umode = 0000;
|
||||
|
||||
if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE)
|
||||
umode |= S_IRUSR | S_IRGRP | S_IROTH;
|
||||
|
||||
if (adev->pm.od_feature_mask & OD_OPS_SUPPORT_FAN_CURVE_SET)
|
||||
umode |= S_IWUSR;
|
||||
|
||||
return umode;
|
||||
}
|
||||
|
||||
static struct od_feature_set amdgpu_od_set = {
|
||||
.containers = {
|
||||
[0] = {
|
||||
.name = "fan_ctrl",
|
||||
.sub_feature = {
|
||||
[0] = {
|
||||
.name = "fan_curve",
|
||||
.ops = {
|
||||
.is_visible = fan_curve_visible,
|
||||
.show = fan_curve_show,
|
||||
.store = fan_curve_store,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
static void od_kobj_release(struct kobject *kobj)
|
||||
{
|
||||
|
@ -314,6 +314,9 @@ struct config_table_setting
|
||||
uint16_t fclk_average_tau;
|
||||
};
|
||||
|
||||
#define OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE BIT(0)
|
||||
#define OD_OPS_SUPPORT_FAN_CURVE_SET BIT(1)
|
||||
|
||||
struct amdgpu_pm {
|
||||
struct mutex mutex;
|
||||
u32 current_sclk;
|
||||
@ -368,6 +371,7 @@ struct amdgpu_pm {
|
||||
enum amdgpu_runpm_mode rpm_mode;
|
||||
|
||||
struct list_head od_kobj_list;
|
||||
uint32_t od_feature_mask;
|
||||
};
|
||||
|
||||
int amdgpu_dpm_read_sensor(struct amdgpu_device *adev, enum amd_pp_sensors sensor,
|
||||
|
@ -2481,6 +2481,8 @@ static enum smu_clk_type smu_convert_to_smuclk(enum pp_clock_type type)
|
||||
clk_type = SMU_OD_VDDGFX_OFFSET; break;
|
||||
case OD_CCLK:
|
||||
clk_type = SMU_OD_CCLK; break;
|
||||
case OD_FAN_CURVE:
|
||||
clk_type = SMU_OD_FAN_CURVE; break;
|
||||
default:
|
||||
clk_type = SMU_CLK_COUNT; break;
|
||||
}
|
||||
|
@ -280,6 +280,7 @@ enum smu_clk_type {
|
||||
SMU_OD_VDDC_CURVE,
|
||||
SMU_OD_RANGE,
|
||||
SMU_OD_VDDGFX_OFFSET,
|
||||
SMU_OD_FAN_CURVE,
|
||||
SMU_CLK_COUNT,
|
||||
};
|
||||
|
||||
|
@ -101,6 +101,8 @@
|
||||
#define PP_OD_FEATURE_UCLK_FMIN 2
|
||||
#define PP_OD_FEATURE_UCLK_FMAX 3
|
||||
#define PP_OD_FEATURE_GFX_VF_CURVE 4
|
||||
#define PP_OD_FEATURE_FAN_CURVE_TEMP 5
|
||||
#define PP_OD_FEATURE_FAN_CURVE_PWM 6
|
||||
|
||||
#define LINK_SPEED_MAX 3
|
||||
|
||||
@ -1122,6 +1124,14 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
|
||||
od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary;
|
||||
od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary;
|
||||
break;
|
||||
case PP_OD_FEATURE_FAN_CURVE_TEMP:
|
||||
od_min_setting = overdrive_lowerlimits->FanLinearTempPoints;
|
||||
od_max_setting = overdrive_upperlimits->FanLinearTempPoints;
|
||||
break;
|
||||
case PP_OD_FEATURE_FAN_CURVE_PWM:
|
||||
od_min_setting = overdrive_lowerlimits->FanLinearPwmPoints;
|
||||
od_max_setting = overdrive_upperlimits->FanLinearPwmPoints;
|
||||
break;
|
||||
default:
|
||||
od_min_setting = od_max_setting = INT_MAX;
|
||||
break;
|
||||
@ -1341,6 +1351,35 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
|
||||
od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]);
|
||||
break;
|
||||
|
||||
case SMU_OD_FAN_CURVE:
|
||||
if (!smu_v13_0_0_is_od_feature_supported(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_BIT))
|
||||
break;
|
||||
|
||||
size += sysfs_emit_at(buf, size, "OD_FAN_CURVE:\n");
|
||||
for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++)
|
||||
size += sysfs_emit_at(buf, size, "%d: %dC %d%%\n",
|
||||
i,
|
||||
(int)od_table->OverDriveTable.FanLinearTempPoints[i],
|
||||
(int)od_table->OverDriveTable.FanLinearPwmPoints[i]);
|
||||
|
||||
size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
|
||||
smu_v13_0_0_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||
&min_value,
|
||||
&max_value);
|
||||
size += sysfs_emit_at(buf, size, "FAN_CURVE(hotspot temp): %uC %uC\n",
|
||||
min_value, max_value);
|
||||
|
||||
smu_v13_0_0_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||
&min_value,
|
||||
&max_value);
|
||||
size += sysfs_emit_at(buf, size, "FAN_CURVE(fan speed): %u%% %u%%\n",
|
||||
min_value, max_value);
|
||||
|
||||
break;
|
||||
|
||||
case SMU_OD_RANGE:
|
||||
if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
|
||||
!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
|
||||
@ -1551,6 +1590,44 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_FAN_CURVE:
|
||||
if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
|
||||
dev_warn(adev->dev, "Fan curve setting not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (input[0] >= NUM_OD_FAN_MAX_POINTS - 1 ||
|
||||
input[0] < 0)
|
||||
return -EINVAL;
|
||||
|
||||
smu_v13_0_0_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||
&minimum,
|
||||
&maximum);
|
||||
if (input[1] < minimum ||
|
||||
input[1] > maximum) {
|
||||
dev_info(adev->dev, "Fan curve temp setting(%ld) must be within [%d, %d]!\n",
|
||||
input[1], minimum, maximum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smu_v13_0_0_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||
&minimum,
|
||||
&maximum);
|
||||
if (input[2] < minimum ||
|
||||
input[2] > maximum) {
|
||||
dev_info(adev->dev, "Fan curve pwm setting(%ld) must be within [%d, %d]!\n",
|
||||
input[2], minimum, maximum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
od_table->OverDriveTable.FanLinearTempPoints[input[0]] = input[1];
|
||||
od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2];
|
||||
od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
|
||||
break;
|
||||
|
||||
case PP_OD_RESTORE_DEFAULT_TABLE:
|
||||
feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask;
|
||||
memcpy(od_table,
|
||||
@ -1801,6 +1878,16 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
|
||||
return sizeof(struct gpu_metrics_v1_3);
|
||||
}
|
||||
|
||||
static void smu_v13_0_0_set_supported_od_feature_mask(struct smu_context *smu)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
if (smu_v13_0_0_is_od_feature_supported(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_BIT))
|
||||
adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE |
|
||||
OD_OPS_SUPPORT_FAN_CURVE_SET;
|
||||
}
|
||||
|
||||
static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
|
||||
{
|
||||
OverDriveTableExternal_t *od_table =
|
||||
@ -1850,8 +1937,16 @@ static int smu_v13_0_0_set_default_od_settings(struct smu_context *smu)
|
||||
for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
|
||||
user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] =
|
||||
user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i];
|
||||
for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) {
|
||||
user_od_table->OverDriveTable.FanLinearTempPoints[i] =
|
||||
user_od_table_bak.OverDriveTable.FanLinearTempPoints[i];
|
||||
user_od_table->OverDriveTable.FanLinearPwmPoints[i] =
|
||||
user_od_table_bak.OverDriveTable.FanLinearPwmPoints[i];
|
||||
}
|
||||
}
|
||||
|
||||
smu_v13_0_0_set_supported_od_feature_mask(smu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1862,9 +1957,10 @@ static int smu_v13_0_0_restore_user_od_settings(struct smu_context *smu)
|
||||
OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
|
||||
int res;
|
||||
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT |
|
||||
1U << PP_OD_FEATURE_UCLK_BIT |
|
||||
1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT;
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
|
||||
BIT(PP_OD_FEATURE_UCLK_BIT) |
|
||||
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
|
||||
BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
|
||||
res = smu_v13_0_0_upload_overdrive_table(smu, user_od_table);
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
|
||||
if (res == 0)
|
||||
|
@ -77,6 +77,8 @@
|
||||
#define PP_OD_FEATURE_UCLK_FMIN 2
|
||||
#define PP_OD_FEATURE_UCLK_FMAX 3
|
||||
#define PP_OD_FEATURE_GFX_VF_CURVE 4
|
||||
#define PP_OD_FEATURE_FAN_CURVE_TEMP 5
|
||||
#define PP_OD_FEATURE_FAN_CURVE_PWM 6
|
||||
|
||||
#define LINK_SPEED_MAX 3
|
||||
|
||||
@ -1102,6 +1104,14 @@ static void smu_v13_0_7_get_od_setting_limits(struct smu_context *smu,
|
||||
od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary;
|
||||
od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary;
|
||||
break;
|
||||
case PP_OD_FEATURE_FAN_CURVE_TEMP:
|
||||
od_min_setting = overdrive_lowerlimits->FanLinearTempPoints;
|
||||
od_max_setting = overdrive_upperlimits->FanLinearTempPoints;
|
||||
break;
|
||||
case PP_OD_FEATURE_FAN_CURVE_PWM:
|
||||
od_min_setting = overdrive_lowerlimits->FanLinearPwmPoints;
|
||||
od_max_setting = overdrive_upperlimits->FanLinearPwmPoints;
|
||||
break;
|
||||
default:
|
||||
od_min_setting = od_max_setting = INT_MAX;
|
||||
break;
|
||||
@ -1321,6 +1331,35 @@ static int smu_v13_0_7_print_clk_levels(struct smu_context *smu,
|
||||
od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]);
|
||||
break;
|
||||
|
||||
case SMU_OD_FAN_CURVE:
|
||||
if (!smu_v13_0_7_is_od_feature_supported(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_BIT))
|
||||
break;
|
||||
|
||||
size += sysfs_emit_at(buf, size, "OD_FAN_CURVE:\n");
|
||||
for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++)
|
||||
size += sysfs_emit_at(buf, size, "%d: %dC %d%%\n",
|
||||
i,
|
||||
(int)od_table->OverDriveTable.FanLinearTempPoints[i],
|
||||
(int)od_table->OverDriveTable.FanLinearPwmPoints[i]);
|
||||
|
||||
size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
|
||||
smu_v13_0_7_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||
&min_value,
|
||||
&max_value);
|
||||
size += sysfs_emit_at(buf, size, "FAN_CURVE(hotspot temp): %uC %uC\n",
|
||||
min_value, max_value);
|
||||
|
||||
smu_v13_0_7_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||
&min_value,
|
||||
&max_value);
|
||||
size += sysfs_emit_at(buf, size, "FAN_CURVE(fan speed): %u%% %u%%\n",
|
||||
min_value, max_value);
|
||||
|
||||
break;
|
||||
|
||||
case SMU_OD_RANGE:
|
||||
if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
|
||||
!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
|
||||
@ -1531,6 +1570,44 @@ static int smu_v13_0_7_od_edit_dpm_table(struct smu_context *smu,
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_FAN_CURVE:
|
||||
if (!smu_v13_0_7_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
|
||||
dev_warn(adev->dev, "Fan curve setting not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
if (input[0] >= NUM_OD_FAN_MAX_POINTS - 1 ||
|
||||
input[0] < 0)
|
||||
return -EINVAL;
|
||||
|
||||
smu_v13_0_7_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_TEMP,
|
||||
&minimum,
|
||||
&maximum);
|
||||
if (input[1] < minimum ||
|
||||
input[1] > maximum) {
|
||||
dev_info(adev->dev, "Fan curve temp setting(%ld) must be within [%d, %d]!\n",
|
||||
input[1], minimum, maximum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
smu_v13_0_7_get_od_setting_limits(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_PWM,
|
||||
&minimum,
|
||||
&maximum);
|
||||
if (input[2] < minimum ||
|
||||
input[2] > maximum) {
|
||||
dev_info(adev->dev, "Fan curve pwm setting(%ld) must be within [%d, %d]!\n",
|
||||
input[2], minimum, maximum);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
od_table->OverDriveTable.FanLinearTempPoints[input[0]] = input[1];
|
||||
od_table->OverDriveTable.FanLinearPwmPoints[input[0]] = input[2];
|
||||
od_table->OverDriveTable.FanMode = FAN_MODE_MANUAL_LINEAR;
|
||||
od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
|
||||
break;
|
||||
|
||||
case PP_OD_RESTORE_DEFAULT_TABLE:
|
||||
feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask;
|
||||
memcpy(od_table,
|
||||
@ -1776,6 +1853,16 @@ static ssize_t smu_v13_0_7_get_gpu_metrics(struct smu_context *smu,
|
||||
return sizeof(struct gpu_metrics_v1_3);
|
||||
}
|
||||
|
||||
static void smu_v13_0_7_set_supported_od_feature_mask(struct smu_context *smu)
|
||||
{
|
||||
struct amdgpu_device *adev = smu->adev;
|
||||
|
||||
if (smu_v13_0_7_is_od_feature_supported(smu,
|
||||
PP_OD_FEATURE_FAN_CURVE_BIT))
|
||||
adev->pm.od_feature_mask |= OD_OPS_SUPPORT_FAN_CURVE_RETRIEVE |
|
||||
OD_OPS_SUPPORT_FAN_CURVE_SET;
|
||||
}
|
||||
|
||||
static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
|
||||
{
|
||||
OverDriveTableExternal_t *od_table =
|
||||
@ -1825,8 +1912,16 @@ static int smu_v13_0_7_set_default_od_settings(struct smu_context *smu)
|
||||
for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
|
||||
user_od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] =
|
||||
user_od_table_bak.OverDriveTable.VoltageOffsetPerZoneBoundary[i];
|
||||
for (i = 0; i < NUM_OD_FAN_MAX_POINTS - 1; i++) {
|
||||
user_od_table->OverDriveTable.FanLinearTempPoints[i] =
|
||||
user_od_table_bak.OverDriveTable.FanLinearTempPoints[i];
|
||||
user_od_table->OverDriveTable.FanLinearPwmPoints[i] =
|
||||
user_od_table_bak.OverDriveTable.FanLinearPwmPoints[i];
|
||||
}
|
||||
}
|
||||
|
||||
smu_v13_0_7_set_supported_od_feature_mask(smu);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1837,9 +1932,10 @@ static int smu_v13_0_7_restore_user_od_settings(struct smu_context *smu)
|
||||
OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
|
||||
int res;
|
||||
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = 1U << PP_OD_FEATURE_GFXCLK_BIT |
|
||||
1U << PP_OD_FEATURE_UCLK_BIT |
|
||||
1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT;
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = BIT(PP_OD_FEATURE_GFXCLK_BIT) |
|
||||
BIT(PP_OD_FEATURE_UCLK_BIT) |
|
||||
BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT) |
|
||||
BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
|
||||
res = smu_v13_0_7_upload_overdrive_table(smu, user_od_table);
|
||||
user_od_table->OverDriveTable.FeatureCtrlMask = 0;
|
||||
if (res == 0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user