mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-04-03 04:59:12 +08:00
drm/amd/pm: enable Sienna Cichlid overdrive support
Enable Sienna Cichlid gfxclk/uclk overdrive support. Signed-off-by: Evan Quan <evan.quan@amd.com> Acked-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
@@ -730,7 +730,8 @@ static ssize_t amdgpu_set_pp_table(struct device *dev,
|
||||
*
|
||||
* - minimum and maximum engine clock labeled OD_SCLK
|
||||
*
|
||||
* - maximum memory clock labeled OD_MCLK
|
||||
* - minimum(not available for Vega20 and Navi1x) and maximum memory
|
||||
* clock labeled OD_MCLK
|
||||
*
|
||||
* - three <frequency, voltage> points labeled OD_VDDC_CURVE.
|
||||
* They can be used to calibrate the sclk voltage curve.
|
||||
|
||||
@@ -913,6 +913,22 @@ static bool sienna_cichlid_is_support_fine_grained_dpm(struct smu_context *smu,
|
||||
return dpm_desc->SnapToDiscrete == 0 ? true : false;
|
||||
}
|
||||
|
||||
static bool sienna_cichlid_is_od_feature_supported(struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODFEATURE_CAP cap)
|
||||
{
|
||||
return od_table->cap[cap];
|
||||
}
|
||||
|
||||
static void sienna_cichlid_get_od_setting_range(struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODSETTING_ID setting,
|
||||
uint32_t *min, uint32_t *max)
|
||||
{
|
||||
if (min)
|
||||
*min = od_table->min[setting];
|
||||
if (max)
|
||||
*max = od_table->max[setting];
|
||||
}
|
||||
|
||||
static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
enum smu_clk_type clk_type, char *buf)
|
||||
{
|
||||
@@ -921,11 +937,15 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
|
||||
struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
|
||||
PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
|
||||
struct smu_11_0_7_overdrive_table *od_settings = smu->od_settings;
|
||||
OverDriveTable_t *od_table =
|
||||
(OverDriveTable_t *)table_context->overdrive_table;
|
||||
int i, size = 0, ret = 0;
|
||||
uint32_t cur_value = 0, value = 0, count = 0;
|
||||
uint32_t freq_values[3] = {0};
|
||||
uint32_t mark_index = 0;
|
||||
uint32_t gen_speed, lane_width;
|
||||
uint32_t min_value, max_value;
|
||||
|
||||
switch (clk_type) {
|
||||
case SMU_GFXCLK:
|
||||
@@ -1001,6 +1021,53 @@ static int sienna_cichlid_print_clk_levels(struct smu_context *smu,
|
||||
(lane_width == dpm_context->dpm_tables.pcie_table.pcie_lane[i]) ?
|
||||
"*" : "");
|
||||
break;
|
||||
case SMU_OD_SCLK:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS))
|
||||
break;
|
||||
|
||||
size += sprintf(buf + size, "OD_SCLK:\n");
|
||||
size += sprintf(buf + size, "0: %uMhz\n1: %uMhz\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
|
||||
break;
|
||||
|
||||
case SMU_OD_MCLK:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS))
|
||||
break;
|
||||
|
||||
size += sprintf(buf + size, "OD_MCLK:\n");
|
||||
size += sprintf(buf + size, "0: %uMhz\n1: %uMHz\n", od_table->UclkFmin, od_table->UclkFmax);
|
||||
break;
|
||||
|
||||
case SMU_OD_RANGE:
|
||||
if (!smu->od_enabled || !od_table || !od_settings)
|
||||
break;
|
||||
|
||||
size = sprintf(buf, "%s:\n", "OD_RANGE");
|
||||
|
||||
if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMIN,
|
||||
&min_value, NULL);
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_GFXCLKFMAX,
|
||||
NULL, &max_value);
|
||||
size += sprintf(buf + size, "SCLK: %7uMhz %10uMhz\n",
|
||||
min_value, max_value);
|
||||
}
|
||||
|
||||
if (sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS)) {
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_UCLKFMIN,
|
||||
&min_value, NULL);
|
||||
sienna_cichlid_get_od_setting_range(od_settings, SMU_11_0_7_ODSETTING_UCLKFMAX,
|
||||
NULL, &max_value);
|
||||
size += sprintf(buf + size, "MCLK: %7uMhz %10uMhz\n",
|
||||
min_value, max_value);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1731,6 +1798,179 @@ static int sienna_cichlid_set_default_od_settings(struct smu_context *smu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_od_setting_check_range(struct smu_context *smu,
|
||||
struct smu_11_0_7_overdrive_table *od_table,
|
||||
enum SMU_11_0_7_ODSETTING_ID setting,
|
||||
uint32_t value)
|
||||
{
|
||||
if (value < od_table->min[setting]) {
|
||||
dev_warn(smu->adev->dev, "OD setting (%d, %d) is less than the minimum allowed (%d)\n",
|
||||
setting, value, od_table->min[setting]);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (value > od_table->max[setting]) {
|
||||
dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n",
|
||||
setting, value, od_table->max[setting]);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_od_edit_dpm_table(struct smu_context *smu,
|
||||
enum PP_OD_DPM_TABLE_COMMAND type,
|
||||
long input[], uint32_t size)
|
||||
{
|
||||
struct smu_table_context *table_context = &smu->smu_table;
|
||||
OverDriveTable_t *od_table =
|
||||
(OverDriveTable_t *)table_context->overdrive_table;
|
||||
struct smu_11_0_7_overdrive_table *od_settings =
|
||||
(struct smu_11_0_7_overdrive_table *)smu->od_settings;
|
||||
enum SMU_11_0_7_ODSETTING_ID freq_setting;
|
||||
uint16_t *freq_ptr;
|
||||
int i, ret = 0;
|
||||
|
||||
if (!smu->od_enabled) {
|
||||
dev_warn(smu->adev->dev, "OverDrive is not enabled!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!smu->od_settings) {
|
||||
dev_err(smu->adev->dev, "OD board limits are not set!\n");
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) {
|
||||
dev_err(smu->adev->dev, "Overdrive table was not initialized!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case PP_OD_EDIT_SCLK_VDDC_TABLE:
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings,
|
||||
SMU_11_0_7_ODCAP_GFXCLK_LIMITS)) {
|
||||
dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 2) {
|
||||
if (i + 2 > size) {
|
||||
dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input[i]) {
|
||||
case 0:
|
||||
if (input[i + 1] > od_table->GfxclkFmax) {
|
||||
dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n",
|
||||
input[i + 1], od_table->GfxclkFmax);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_GFXCLKFMIN;
|
||||
freq_ptr = &od_table->GfxclkFmin;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (input[i + 1] < od_table->GfxclkFmin) {
|
||||
dev_info(smu->adev->dev, "GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n",
|
||||
input[i + 1], od_table->GfxclkFmin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_GFXCLKFMAX;
|
||||
freq_ptr = &od_table->GfxclkFmax;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
|
||||
dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sienna_cichlid_od_setting_check_range(smu, od_settings,
|
||||
freq_setting, input[i + 1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*freq_ptr = (uint16_t)input[i + 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_EDIT_MCLK_VDDC_TABLE:
|
||||
if (!sienna_cichlid_is_od_feature_supported(od_settings, SMU_11_0_7_ODCAP_UCLK_LIMITS)) {
|
||||
dev_warn(smu->adev->dev, "UCLK_LIMITS not supported!\n");
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
|
||||
for (i = 0; i < size; i += 2) {
|
||||
if (i + 2 > size) {
|
||||
dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (input[i]) {
|
||||
case 0:
|
||||
if (input[i + 1] > od_table->UclkFmax) {
|
||||
dev_info(smu->adev->dev, "UclkFmin (%ld) must be <= UclkFmax (%u)!\n",
|
||||
input[i + 1], od_table->UclkFmax);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_UCLKFMIN;
|
||||
freq_ptr = &od_table->UclkFmin;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if (input[i + 1] < od_table->UclkFmin) {
|
||||
dev_info(smu->adev->dev, "UclkFmax (%ld) must be >= UclkFmin (%u)!\n",
|
||||
input[i + 1], od_table->UclkFmin);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
freq_setting = SMU_11_0_7_ODSETTING_UCLKFMAX;
|
||||
freq_ptr = &od_table->UclkFmax;
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[i]);
|
||||
dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = sienna_cichlid_od_setting_check_range(smu, od_settings,
|
||||
freq_setting, input[i + 1]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
*freq_ptr = (uint16_t)input[i + 1];
|
||||
}
|
||||
break;
|
||||
|
||||
case PP_OD_RESTORE_DEFAULT_TABLE:
|
||||
memcpy(table_context->overdrive_table,
|
||||
table_context->boot_overdrive_table,
|
||||
sizeof(OverDriveTable_t));
|
||||
fallthrough;
|
||||
|
||||
case PP_OD_COMMIT_DPM_TABLE:
|
||||
sienna_cichlid_dump_od_table(smu, od_table);
|
||||
|
||||
ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE,
|
||||
0, (void *)od_table, true);
|
||||
if (ret) {
|
||||
dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sienna_cichlid_run_btc(struct smu_context *smu)
|
||||
{
|
||||
return smu_cmn_send_smc_msg(smu, SMU_MSG_RunDcBtc, NULL);
|
||||
@@ -2855,6 +3095,7 @@ static const struct pptable_funcs sienna_cichlid_ppt_funcs = {
|
||||
.get_dpm_ultimate_freq = sienna_cichlid_get_dpm_ultimate_freq,
|
||||
.set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
|
||||
.set_default_od_settings = sienna_cichlid_set_default_od_settings,
|
||||
.od_edit_dpm_table = sienna_cichlid_od_edit_dpm_table,
|
||||
.run_btc = sienna_cichlid_run_btc,
|
||||
.set_power_source = smu_v11_0_set_power_source,
|
||||
.get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
|
||||
|
||||
Reference in New Issue
Block a user