[PATCH] drm/amd/pm: add overdrive support on smu v14.0.2/3

Wang, Yang(Kevin) KevinYang.Wang at amd.com
Tue Jul 30 02:09:18 UTC 2024


[AMD Official Use Only - AMD Internal Distribution Only]

Some comments inline.
After fixed, the patch is

Reviewed-by: Yang Wang <kevinyang.wang at amd.com>

Best Regards,
Kevin

-----Original Message-----
From: Kenneth Feng <kenneth.feng at amd.com>
Sent: Tuesday, July 30, 2024 9:45 AM
To: amd-gfx at lists.freedesktop.org
Cc: Wang, Yang(Kevin) <KevinYang.Wang at amd.com>; Feng, Kenneth <Kenneth.Feng at amd.com>
Subject: [PATCH] drm/amd/pm: add overdrive support on smu v14.0.2/3

add overdrive support on smu v14.0.2/3

Signed-off-by: Kenneth Feng <kenneth.feng at amd.com>
---
 .../gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c    |  11 +-
 .../drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c  | 888 +++++++++++++++++-
 2 files changed, 896 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
index 09973615f210..865e916fc425 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0.c
@@ -452,17 +452,26 @@ int smu_v14_0_init_smc_tables(struct smu_context *smu)
                        ret = -ENOMEM;
                        goto err3_out;
                }
+
+               smu_table->user_overdrive_table =
+                       kzalloc(tables[SMU_TABLE_OVERDRIVE].size, GFP_KERNEL);
+               if (!smu_table->user_overdrive_table) {
+                       ret = -ENOMEM;
+                       goto err4_out;
+               }
        }

        smu_table->combo_pptable =
                kzalloc(tables[SMU_TABLE_COMBO_PPTABLE].size, GFP_KERNEL);
        if (!smu_table->combo_pptable) {
                ret = -ENOMEM;
-               goto err4_out;
+               goto err5_out;
        }

        return 0;

+err5_out:
+       kfree(smu_table->user_overdrive_table);
 err4_out:
        kfree(smu_table->boot_overdrive_table);
 err3_out:
diff --git a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
index e1a27903c80a..85cf450d4df1 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/smu14/smu_v14_0_2_ppt.c
@@ -68,6 +68,18 @@
 #define DEBUGSMC_MSG_Mode1Reset        2
 #define LINK_SPEED_MAX                                 3

+#define PP_OD_FEATURE_GFXCLK_FMIN                      0
+#define PP_OD_FEATURE_GFXCLK_FMAX                      1
+#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 PP_OD_FEATURE_FAN_ACOUSTIC_LIMIT               7
+#define PP_OD_FEATURE_FAN_ACOUSTIC_TARGET              8
+#define PP_OD_FEATURE_FAN_TARGET_TEMPERATURE           9
+#define PP_OD_FEATURE_FAN_MINIMUM_PWM                  10
+
 static struct cmn2asic_msg_mapping smu_v14_0_2_message_map[SMU_MSG_MAX_COUNT] = {
        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                 1),
        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,               1),
@@ -204,6 +216,7 @@ static struct cmn2asic_mapping smu_v14_0_2_table_map[SMU_TABLE_COUNT] = {
        [SMU_TABLE_COMBO_PPTABLE] = {1, TABLE_COMBO_PPTABLE},
        TAB_MAP(I2C_COMMANDS),
        TAB_MAP(ECCINFO),
+       TAB_MAP(OVERDRIVE),
 };

 static struct cmn2asic_mapping smu_v14_0_2_pwr_src_map[SMU_POWER_SOURCE_COUNT] = { @@ -1029,16 +1042,97 @@ static int smu_v14_0_2_get_current_clk_freq_by_table(struct smu_context *smu,
                                                value);
 }

+static bool smu_v14_0_2_is_od_feature_supported(struct smu_context *smu,
+                                               int od_feature_bit)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       const OverDriveLimits_t * const overdrive_upperlimits =
+                               &pptable->SkuTable.OverDriveLimitsBasicMax;
+
+       return overdrive_upperlimits->FeatureCtrlMask & (1U <<
+od_feature_bit); }
+
+static void smu_v14_0_2_get_od_setting_limits(struct smu_context *smu,
+                                             int od_feature_bit,
+                                             int32_t *min,
+                                             int32_t *max)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       const OverDriveLimits_t * const overdrive_upperlimits =
+                               &pptable->SkuTable.OverDriveLimitsBasicMax;
+       const OverDriveLimits_t * const overdrive_lowerlimits =
+                               &pptable->SkuTable.OverDriveLimitsBasicMin;
+       int32_t od_min_setting, od_max_setting;
+
+       switch (od_feature_bit) {
+       case PP_OD_FEATURE_GFXCLK_FMIN:
+               od_min_setting = overdrive_lowerlimits->GfxclkFmin;
+               od_max_setting = overdrive_upperlimits->GfxclkFmin;
+               break;
+       case PP_OD_FEATURE_GFXCLK_FMAX:
+               od_min_setting = overdrive_lowerlimits->GfxclkFmax;
+               od_max_setting = overdrive_upperlimits->GfxclkFmax;
+               break;
+       case PP_OD_FEATURE_UCLK_FMIN:
+               od_min_setting = overdrive_lowerlimits->UclkFmin;
+               od_max_setting = overdrive_upperlimits->UclkFmin;
+               break;
+       case PP_OD_FEATURE_UCLK_FMAX:
+               od_min_setting = overdrive_lowerlimits->UclkFmax;
+               od_max_setting = overdrive_upperlimits->UclkFmax;
+               break;
+       case PP_OD_FEATURE_GFX_VF_CURVE:
+               od_min_setting = overdrive_lowerlimits->VoltageOffsetPerZoneBoundary[0];
+               od_max_setting = overdrive_upperlimits->VoltageOffsetPerZoneBoundary[0];
+               break;
+       case PP_OD_FEATURE_FAN_CURVE_TEMP:
+               od_min_setting = overdrive_lowerlimits->FanLinearTempPoints[0];
+               od_max_setting = overdrive_upperlimits->FanLinearTempPoints[0];
+               break;
+       case PP_OD_FEATURE_FAN_CURVE_PWM:
+               od_min_setting = overdrive_lowerlimits->FanLinearPwmPoints[0];
+               od_max_setting = overdrive_upperlimits->FanLinearPwmPoints[0];
+               break;
+       case PP_OD_FEATURE_FAN_ACOUSTIC_LIMIT:
+               od_min_setting = overdrive_lowerlimits->AcousticLimitRpmThreshold;
+               od_max_setting = overdrive_upperlimits->AcousticLimitRpmThreshold;
+               break;
+       case PP_OD_FEATURE_FAN_ACOUSTIC_TARGET:
+               od_min_setting = overdrive_lowerlimits->AcousticTargetRpmThreshold;
+               od_max_setting = overdrive_upperlimits->AcousticTargetRpmThreshold;
+               break;
+       case PP_OD_FEATURE_FAN_TARGET_TEMPERATURE:
+               od_min_setting = overdrive_lowerlimits->FanTargetTemperature;
+               od_max_setting = overdrive_upperlimits->FanTargetTemperature;
+               break;
+       case PP_OD_FEATURE_FAN_MINIMUM_PWM:
+               od_min_setting = overdrive_lowerlimits->FanMinimumPwm;
+               od_max_setting = overdrive_upperlimits->FanMinimumPwm;
+               break;
+       default:
+               od_min_setting = od_max_setting = INT_MAX;
+               break;
+       }
+
+       if (min)
+               *min = od_min_setting;
+       if (max)
+               *max = od_max_setting;
+}
+
 static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
                                        enum smu_clk_type clk_type,
                                        char *buf)
 {
        struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
        struct smu_14_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
        struct smu_14_0_dpm_table *single_dpm_table;
        struct smu_14_0_pcie_table *pcie_table;
        uint32_t gen_speed, lane_width;
        int i, curr_freq, size = 0;
+       int32_t min_value, max_value;
        int ret = 0;

        smu_cmn_get_sysfs_buf(&buf, &size);
@@ -1159,6 +1253,183 @@ static int smu_v14_0_2_print_clk_levels(struct smu_context *smu,
                                        "*" : "");
                break;

+       case SMU_OD_SCLK:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_GFXCLK_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "OD_SCLK:\n");
+               size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMhz\n",
+                                       od_table->OverDriveTable.GfxclkFmin,
+                                       od_table->OverDriveTable.GfxclkFmax);
+               break;
+
+       case SMU_OD_MCLK:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_UCLK_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "OD_MCLK:\n");
+               size += sysfs_emit_at(buf, size, "0: %uMhz\n1: %uMHz\n",
+                                       od_table->OverDriveTable.UclkFmin,
+                                       od_table->OverDriveTable.UclkFmax);
+               break;
+
+       case SMU_OD_VDDGFX_OFFSET:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_GFX_VF_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "OD_VDDGFX_OFFSET:\n");
+               size += sysfs_emit_at(buf, size, "%dmV\n",
+                                     od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[0]);
+               break;
+
+       case SMU_OD_FAN_CURVE:
+               if (!smu_v14_0_2_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_v14_0_2_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_v14_0_2_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_ACOUSTIC_LIMIT:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_FAN_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "OD_ACOUSTIC_LIMIT:\n");
+               size += sysfs_emit_at(buf, size, "%d\n",
+                                       (int)od_table->OverDriveTable.AcousticLimitRpmThreshold);
+
+               size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_ACOUSTIC_LIMIT,
+                                                 &min_value,
+                                                 &max_value);
+               size += sysfs_emit_at(buf, size, "ACOUSTIC_LIMIT: %u %u\n",
+                                     min_value, max_value);
+               break;
+
+       case SMU_OD_ACOUSTIC_TARGET:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_FAN_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "OD_ACOUSTIC_TARGET:\n");
+               size += sysfs_emit_at(buf, size, "%d\n",
+                                       (int)od_table->OverDriveTable.AcousticTargetRpmThreshold);
+
+               size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_ACOUSTIC_TARGET,
+                                                 &min_value,
+                                                 &max_value);
+               size += sysfs_emit_at(buf, size, "ACOUSTIC_TARGET: %u %u\n",
+                                     min_value, max_value);
+               break;
+
+       case SMU_OD_FAN_TARGET_TEMPERATURE:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_FAN_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "FAN_TARGET_TEMPERATURE:\n");
+               size += sysfs_emit_at(buf, size, "%d\n",
+                                       (int)od_table->OverDriveTable.FanTargetTemperature);
+
+               size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_TARGET_TEMPERATURE,
+                                                 &min_value,
+                                                 &max_value);
+               size += sysfs_emit_at(buf, size, "TARGET_TEMPERATURE: %u %u\n",
+                                     min_value, max_value);
+               break;
+
+       case SMU_OD_FAN_MINIMUM_PWM:
+               if (!smu_v14_0_2_is_od_feature_supported(smu,
+                                                        PP_OD_FEATURE_FAN_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "FAN_MINIMUM_PWM:\n");
+               size += sysfs_emit_at(buf, size, "%d\n",
+                                       (int)od_table->OverDriveTable.FanMinimumPwm);
+
+               size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_MINIMUM_PWM,
+                                                 &min_value,
+                                                 &max_value);
+               size += sysfs_emit_at(buf, size, "MINIMUM_PWM: %u %u\n",
+                                     min_value, max_value);
+               break;
+
+       case SMU_OD_RANGE:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT) &&
+                   !smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT) &&
+                   !smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT))
+                       break;
+
+               size += sysfs_emit_at(buf, size, "%s:\n", "OD_RANGE");
+
+               if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) {
+                       smu_v14_0_2_get_od_setting_limits(smu,
+                                                         PP_OD_FEATURE_GFXCLK_FMIN,
+                                                         &min_value,
+                                                         NULL);
+                       smu_v14_0_2_get_od_setting_limits(smu,
+                                                         PP_OD_FEATURE_GFXCLK_FMAX,
+                                                         NULL,
+                                                         &max_value);
+                       size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
+                                             min_value, max_value);
+               }
+
+               if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) {
+                       smu_v14_0_2_get_od_setting_limits(smu,
+                                                         PP_OD_FEATURE_UCLK_FMIN,
+                                                         &min_value,
+                                                         NULL);
+                       smu_v14_0_2_get_od_setting_limits(smu,
+                                                         PP_OD_FEATURE_UCLK_FMAX,
+                                                         NULL,
+                                                         &max_value);
+                       size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n",
+                                             min_value, max_value);
+               }
+
+               if (smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) {
+                       smu_v14_0_2_get_od_setting_limits(smu,
+                                                         PP_OD_FEATURE_GFX_VF_CURVE,
+                                                         &min_value,
+                                                         &max_value);
+                       size += sysfs_emit_at(buf, size, "VDDGFX_OFFSET: %7dmv %10dmv\n",
+                                             min_value, max_value);
+               }
+               break;
+
        default:
                break;
        }
@@ -1400,7 +1671,27 @@ static int smu_v14_0_2_get_power_limit(struct smu_context *smu,
                                       uint32_t *max_power_limit,
                                       uint32_t *min_power_limit)
 {
-       // TODO
+       struct smu_table_context *table_context = &smu->smu_table;
+       PPTable_t *pptable = table_context->driver_pptable;
+       CustomSkuTable_t *skutable = &pptable->CustomSkuTable;
+       uint32_t power_limit;
+       uint32_t msg_limit =
+pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+
+       if (smu_v14_0_get_current_power_limit(smu, &power_limit))
+               power_limit = smu->adev->pm.ac_power ?
+                             skutable->SocketPowerLimitAc[PPT_THROTTLER_PPT0] :
+                             skutable->SocketPowerLimitDc[PPT_THROTTLER_PPT0];
+
+       if (current_power_limit)
+               *current_power_limit = power_limit;
+       if (default_power_limit)
+               *default_power_limit = power_limit;
+
+       if (max_power_limit)
+               *max_power_limit = msg_limit;
+
+       if (min_power_limit)
+               *min_power_limit = 0;

        return 0;
 }
@@ -1950,6 +2241,596 @@ static ssize_t smu_v14_0_2_get_gpu_metrics(struct smu_context *smu,
        return sizeof(struct gpu_metrics_v1_3);  }

+static void smu_v14_0_2_dump_od_table(struct smu_context *smu,
+                                     OverDriveTableExternal_t *od_table) {
+       struct amdgpu_device *adev = smu->adev;
+
+       dev_dbg(adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->OverDriveTable.GfxclkFmin,
+                                                    od_table->OverDriveTable.GfxclkFmax);
+       dev_dbg(adev->dev, "OD: Uclk: (%d, %d)\n", od_table->OverDriveTable.UclkFmin,
+                                                  od_table->OverDriveTable.UclkFmax);
+}
+
+static int smu_v14_0_2_upload_overdrive_table(struct smu_context *smu,
+                                             OverDriveTableExternal_t *od_table) {
+       int ret = 0;
+
+       ret = smu_cmn_update_table(smu,
+                                  SMU_TABLE_OVERDRIVE,
+                                  0,
+                                  (void *)od_table,
+                                  true);
+       if (ret)
+               dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+
+       return ret;
+}
+
+static void smu_v14_0_2_set_supported_od_feature_mask(struct
+smu_context *smu) {
+       struct amdgpu_device *adev = smu->adev;
+
+       if (smu_v14_0_2_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 |
+                                           OD_OPS_SUPPORT_ACOUSTIC_LIMIT_THRESHOLD_RETRIEVE |
+                                           OD_OPS_SUPPORT_ACOUSTIC_LIMIT_THRESHOLD_SET |
+                                           OD_OPS_SUPPORT_ACOUSTIC_TARGET_THRESHOLD_RETRIEVE |
+                                           OD_OPS_SUPPORT_ACOUSTIC_TARGET_THRESHOLD_SET |
+                                           OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_RETRIEVE |
+                                           OD_OPS_SUPPORT_FAN_TARGET_TEMPERATURE_SET |
+                                           OD_OPS_SUPPORT_FAN_MINIMUM_PWM_RETRIEVE |
+                                           OD_OPS_SUPPORT_FAN_MINIMUM_PWM_SET;
+}
+
+static int smu_v14_0_2_get_overdrive_table(struct smu_context *smu,
+                                          OverDriveTableExternal_t *od_table) {
+       int ret = 0;
[kevin]:
Initialization is unnecessary, and same problem on the other place, better fixes it before submitting.
+
+       ret = smu_cmn_update_table(smu,
+                                  SMU_TABLE_OVERDRIVE,
+                                  0,
+                                  (void *)od_table,
+                                  false);
+       if (ret)
+               dev_err(smu->adev->dev, "Failed to get overdrive table!\n");
+
+       return ret;
+}
+
+static int smu_v14_0_2_set_default_od_settings(struct smu_context *smu)
+{
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)smu->smu_table.overdrive_table;
+       OverDriveTableExternal_t *boot_od_table =
+               (OverDriveTableExternal_t *)smu->smu_table.boot_overdrive_table;
+       OverDriveTableExternal_t *user_od_table =
+               (OverDriveTableExternal_t *)smu->smu_table.user_overdrive_table;
+       OverDriveTableExternal_t user_od_table_bak;
+       int ret = 0;
+       int i;
[Kevin]:
It is better making the same type variables in the same line.

Reviewed-by: Yang Wang <kevinyang.wang at amd.com>

Best Regards,
Kevin

+
+       ret = smu_v14_0_2_get_overdrive_table(smu, boot_od_table);
+       if (ret)
+               return ret;
+
+       smu_v14_0_2_dump_od_table(smu, boot_od_table);
+
+       memcpy(od_table,
+              boot_od_table,
+              sizeof(OverDriveTableExternal_t));
+
+       /*
+        * For S3/S4/Runpm resume, we need to setup those overdrive tables again,
+        * but we have to preserve user defined values in "user_od_table".
+        */
+       if (!smu->adev->in_suspend) {
+               memcpy(user_od_table,
+                      boot_od_table,
+                      sizeof(OverDriveTableExternal_t));
+               smu->user_dpm_profile.user_od = false;
+       } else if (smu->user_dpm_profile.user_od) {
+               memcpy(&user_od_table_bak,
+                      user_od_table,
+                      sizeof(OverDriveTableExternal_t));
+               memcpy(user_od_table,
+                      boot_od_table,
+                      sizeof(OverDriveTableExternal_t));
+               user_od_table->OverDriveTable.GfxclkFmin =
+                               user_od_table_bak.OverDriveTable.GfxclkFmin;
+               user_od_table->OverDriveTable.GfxclkFmax =
+                               user_od_table_bak.OverDriveTable.GfxclkFmax;
+               user_od_table->OverDriveTable.UclkFmin =
+                               user_od_table_bak.OverDriveTable.UclkFmin;
+               user_od_table->OverDriveTable.UclkFmax =
+                               user_od_table_bak.OverDriveTable.UclkFmax;
+               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];
+               }
+               user_od_table->OverDriveTable.AcousticLimitRpmThreshold =
+                       user_od_table_bak.OverDriveTable.AcousticLimitRpmThreshold;
+               user_od_table->OverDriveTable.AcousticTargetRpmThreshold =
+                       user_od_table_bak.OverDriveTable.AcousticTargetRpmThreshold;
+               user_od_table->OverDriveTable.FanTargetTemperature =
+                       user_od_table_bak.OverDriveTable.FanTargetTemperature;
+               user_od_table->OverDriveTable.FanMinimumPwm =
+                       user_od_table_bak.OverDriveTable.FanMinimumPwm;
+       }
+
+       smu_v14_0_2_set_supported_od_feature_mask(smu);
+
+       return 0;
+}
+
+static int smu_v14_0_2_restore_user_od_settings(struct smu_context
+*smu) {
+       struct smu_table_context *table_context = &smu->smu_table;
+       OverDriveTableExternal_t *od_table = table_context->overdrive_table;
+       OverDriveTableExternal_t *user_od_table = table_context->user_overdrive_table;
+       int res;
+
+       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_v14_0_2_upload_overdrive_table(smu, user_od_table);
+       user_od_table->OverDriveTable.FeatureCtrlMask = 0;
+       if (res == 0)
+               memcpy(od_table, user_od_table, sizeof(OverDriveTableExternal_t));
+
+       return res;
+}
+
+static int smu_v14_0_2_od_restore_table_single(struct smu_context *smu,
+long input) {
+       struct smu_table_context *table_context = &smu->smu_table;
+       OverDriveTableExternal_t *boot_overdrive_table =
+               (OverDriveTableExternal_t *)table_context->boot_overdrive_table;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)table_context->overdrive_table;
+       struct amdgpu_device *adev = smu->adev;
+       int i;
+
+       switch (input) {
+       case PP_OD_EDIT_FAN_CURVE:
+               for (i = 0; i < NUM_OD_FAN_MAX_POINTS; i++) {
+                       od_table->OverDriveTable.FanLinearTempPoints[i] =
+                                       boot_overdrive_table->OverDriveTable.FanLinearTempPoints[i];
+                       od_table->OverDriveTable.FanLinearPwmPoints[i] =
+                                       boot_overdrive_table->OverDriveTable.FanLinearPwmPoints[i];
+               }
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+       case PP_OD_EDIT_ACOUSTIC_LIMIT:
+               od_table->OverDriveTable.AcousticLimitRpmThreshold =
+                                       boot_overdrive_table->OverDriveTable.AcousticLimitRpmThreshold;
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+       case PP_OD_EDIT_ACOUSTIC_TARGET:
+               od_table->OverDriveTable.AcousticTargetRpmThreshold =
+                                       boot_overdrive_table->OverDriveTable.AcousticTargetRpmThreshold;
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+       case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
+               od_table->OverDriveTable.FanTargetTemperature =
+                                       boot_overdrive_table->OverDriveTable.FanTargetTemperature;
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+       case PP_OD_EDIT_FAN_MINIMUM_PWM:
+               od_table->OverDriveTable.FanMinimumPwm =
+                                       boot_overdrive_table->OverDriveTable.FanMinimumPwm;
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+       default:
+               dev_info(adev->dev, "Invalid table index: %ld\n", input);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int smu_v14_0_2_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;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)table_context->overdrive_table;
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t offset_of_voltageoffset;
+       int32_t minimum, maximum;
+       uint32_t feature_ctrlmask;
+       int i, ret = 0;
+
+       switch (type) {
+       case PP_OD_EDIT_SCLK_VDDC_TABLE:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) {
+                       dev_warn(adev->dev, "GFXCLK_LIMITS setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               for (i = 0; i < size; i += 2) {
+                       if (i + 2 > size) {
+                               dev_info(adev->dev, "invalid number of input parameters %d\n", size);
+                               return -EINVAL;
+                       }
+
+                       switch (input[i]) {
+                       case 0:
+                               smu_v14_0_2_get_od_setting_limits(smu,
+                                                                 PP_OD_FEATURE_GFXCLK_FMIN,
+                                                                 &minimum,
+                                                                 &maximum);
+                               if (input[i + 1] < minimum ||
+                                   input[i + 1] > maximum) {
+                                       dev_info(adev->dev, "GfxclkFmin (%ld) must be within [%u, %u]!\n",
+                                               input[i + 1], minimum, maximum);
+                                       return -EINVAL;
+                               }
+
+                               od_table->OverDriveTable.GfxclkFmin = input[i + 1];
+                               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
+                               break;
+
+                       case 1:
+                               smu_v14_0_2_get_od_setting_limits(smu,
+                                                                 PP_OD_FEATURE_GFXCLK_FMAX,
+                                                                 &minimum,
+                                                                 &maximum);
+                               if (input[i + 1] < minimum ||
+                                   input[i + 1] > maximum) {
+                                       dev_info(adev->dev, "GfxclkFmax (%ld) must be within [%u, %u]!\n",
+                                               input[i + 1], minimum, maximum);
+                                       return -EINVAL;
+                               }
+
+                               od_table->OverDriveTable.GfxclkFmax = input[i + 1];
+                               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFXCLK_BIT;
+                               break;
+
+                       default:
+                               dev_info(adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
+                               dev_info(adev->dev, "Supported indices: [0:min,1:max]\n");
+                               return -EINVAL;
+                       }
+               }
+
+               if (od_table->OverDriveTable.GfxclkFmin > od_table->OverDriveTable.GfxclkFmax) {
+                       dev_err(adev->dev,
+                               "Invalid setting: GfxclkFmin(%u) is bigger than GfxclkFmax(%u)\n",
+                               (uint32_t)od_table->OverDriveTable.GfxclkFmin,
+                               (uint32_t)od_table->OverDriveTable.GfxclkFmax);
+                       return -EINVAL;
+               }
+               break;
+
+       case PP_OD_EDIT_MCLK_VDDC_TABLE:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) {
+                       dev_warn(adev->dev, "UCLK_LIMITS setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               for (i = 0; i < size; i += 2) {
+                       if (i + 2 > size) {
+                               dev_info(adev->dev, "invalid number of input parameters %d\n", size);
+                               return -EINVAL;
+                       }
+
+                       switch (input[i]) {
+                       case 0:
+                               smu_v14_0_2_get_od_setting_limits(smu,
+                                                                 PP_OD_FEATURE_UCLK_FMIN,
+                                                                 &minimum,
+                                                                 &maximum);
+                               if (input[i + 1] < minimum ||
+                                   input[i + 1] > maximum) {
+                                       dev_info(adev->dev, "UclkFmin (%ld) must be within [%u, %u]!\n",
+                                               input[i + 1], minimum, maximum);
+                                       return -EINVAL;
+                               }
+
+                               od_table->OverDriveTable.UclkFmin = input[i + 1];
+                               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT;
+                               break;
+
+                       case 1:
+                               smu_v14_0_2_get_od_setting_limits(smu,
+                                                                 PP_OD_FEATURE_UCLK_FMAX,
+                                                                 &minimum,
+                                                                 &maximum);
+                               if (input[i + 1] < minimum ||
+                                   input[i + 1] > maximum) {
+                                       dev_info(adev->dev, "UclkFmax (%ld) must be within [%u, %u]!\n",
+                                               input[i + 1], minimum, maximum);
+                                       return -EINVAL;
+                               }
+
+                               od_table->OverDriveTable.UclkFmax = input[i + 1];
+                               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_UCLK_BIT;
+                               break;
+
+                       default:
+                               dev_info(adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[i]);
+                               dev_info(adev->dev, "Supported indices: [0:min,1:max]\n");
+                               return -EINVAL;
+                       }
+               }
+
+               if (od_table->OverDriveTable.UclkFmin > od_table->OverDriveTable.UclkFmax) {
+                       dev_err(adev->dev,
+                               "Invalid setting: UclkFmin(%u) is bigger than UclkFmax(%u)\n",
+                               (uint32_t)od_table->OverDriveTable.UclkFmin,
+                               (uint32_t)od_table->OverDriveTable.UclkFmax);
+                       return -EINVAL;
+               }
+               break;
+
+       case PP_OD_EDIT_VDDGFX_OFFSET:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) {
+                       dev_warn(adev->dev, "Gfx offset setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_GFX_VF_CURVE,
+                                                 &minimum,
+                                                 &maximum);
+               if (input[0] < minimum ||
+                   input[0] > maximum) {
+                       dev_info(adev->dev, "Voltage offset (%ld) must be within [%d, %d]!\n",
+                                input[0], minimum, maximum);
+                       return -EINVAL;
+               }
+
+               for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
+                       od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[i] = input[0];
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_GFX_VF_CURVE_BIT);
+               break;
+
+       case PP_OD_EDIT_FAN_CURVE:
+               if (!smu_v14_0_2_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_v14_0_2_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_v14_0_2_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_EDIT_ACOUSTIC_LIMIT:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
+                       dev_warn(adev->dev, "Fan curve setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_ACOUSTIC_LIMIT,
+                                                 &minimum,
+                                                 &maximum);
+               if (input[0] < minimum ||
+                   input[0] > maximum) {
+                       dev_info(adev->dev, "acoustic limit threshold setting(%ld) must be within [%d, %d]!\n",
+                                input[0], minimum, maximum);
+                       return -EINVAL;
+               }
+
+               od_table->OverDriveTable.AcousticLimitRpmThreshold = input[0];
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+
+       case PP_OD_EDIT_ACOUSTIC_TARGET:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
+                       dev_warn(adev->dev, "Fan curve setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_ACOUSTIC_TARGET,
+                                                 &minimum,
+                                                 &maximum);
+               if (input[0] < minimum ||
+                   input[0] > maximum) {
+                       dev_info(adev->dev, "acoustic target threshold setting(%ld) must be within [%d, %d]!\n",
+                                input[0], minimum, maximum);
+                       return -EINVAL;
+               }
+
+               od_table->OverDriveTable.AcousticTargetRpmThreshold = input[0];
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+
+       case PP_OD_EDIT_FAN_TARGET_TEMPERATURE:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
+                       dev_warn(adev->dev, "Fan curve setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_TARGET_TEMPERATURE,
+                                                 &minimum,
+                                                 &maximum);
+               if (input[0] < minimum ||
+                   input[0] > maximum) {
+                       dev_info(adev->dev, "fan target temperature setting(%ld) must be within [%d, %d]!\n",
+                                input[0], minimum, maximum);
+                       return -EINVAL;
+               }
+
+               od_table->OverDriveTable.FanTargetTemperature = input[0];
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+
+       case PP_OD_EDIT_FAN_MINIMUM_PWM:
+               if (!smu_v14_0_2_is_od_feature_supported(smu, PP_OD_FEATURE_FAN_CURVE_BIT)) {
+                       dev_warn(adev->dev, "Fan curve setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v14_0_2_get_od_setting_limits(smu,
+                                                 PP_OD_FEATURE_FAN_MINIMUM_PWM,
+                                                 &minimum,
+                                                 &maximum);
+               if (input[0] < minimum ||
+                   input[0] > maximum) {
+                       dev_info(adev->dev, "fan minimum pwm setting(%ld) must be within [%d, %d]!\n",
+                                input[0], minimum, maximum);
+                       return -EINVAL;
+               }
+
+               od_table->OverDriveTable.FanMinimumPwm = input[0];
+               od_table->OverDriveTable.FanMode = FAN_MODE_AUTO;
+               od_table->OverDriveTable.FeatureCtrlMask |= BIT(PP_OD_FEATURE_FAN_CURVE_BIT);
+               break;
+
+       case PP_OD_RESTORE_DEFAULT_TABLE:
+               if (size == 1) {
+                       ret = smu_v14_0_2_od_restore_table_single(smu, input[0]);
+                       if (ret)
+                               return ret;
+               } else {
+                       feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask;
+                       memcpy(od_table,
+                      table_context->boot_overdrive_table,
+                      sizeof(OverDriveTableExternal_t));
+                       od_table->OverDriveTable.FeatureCtrlMask = feature_ctrlmask;
+               }
+               fallthrough;
+       case PP_OD_COMMIT_DPM_TABLE:
+               /*
+                * The member below instructs PMFW the settings focused in
+                * this single operation.
+                * `uint32_t FeatureCtrlMask;`
+                * It does not contain actual informations about user's custom
+                * settings. Thus we do not cache it.
+                */
+               offset_of_voltageoffset = offsetof(OverDriveTable_t, VoltageOffsetPerZoneBoundary);
+               if (memcmp((u8 *)od_table + offset_of_voltageoffset,
+                          table_context->user_overdrive_table + offset_of_voltageoffset,
+                          sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset)) {
+                       smu_v14_0_2_dump_od_table(smu, od_table);
+
+                       ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+                       if (ret) {
+                               dev_err(adev->dev, "Failed to upload overdrive table!\n");
+                               return ret;
+                       }
+
+                       od_table->OverDriveTable.FeatureCtrlMask = 0;
+                       memcpy(table_context->user_overdrive_table + offset_of_voltageoffset,
+                              (u8 *)od_table + offset_of_voltageoffset,
+                              sizeof(OverDriveTableExternal_t) - offset_of_voltageoffset);
+
+                       if (!memcmp(table_context->user_overdrive_table,
+                                   table_context->boot_overdrive_table,
+                                   sizeof(OverDriveTableExternal_t)))
+                               smu->user_dpm_profile.user_od = false;
+                       else
+                               smu->user_dpm_profile.user_od = true;
+               }
+               break;
+
+       default:
+               return -ENOSYS;
+       }
+
+       return ret;
+}
+
+static int smu_v14_0_2_set_power_limit(struct smu_context *smu,
+                                      enum smu_ppt_limit_type limit_type,
+                                      uint32_t limit)
+{
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
+       uint32_t msg_limit = pptable->SkuTable.MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
+       struct smu_table_context *table_context = &smu->smu_table;
+       OverDriveTableExternal_t *od_table =
+               (OverDriveTableExternal_t *)table_context->overdrive_table;
+       int ret = 0;
+
+       if (limit_type != SMU_DEFAULT_PPT_LIMIT)
+               return -EINVAL;
+
+       if (limit <= msg_limit) {
+               if (smu->current_power_limit > msg_limit) {
+                       od_table->OverDriveTable.Ppt = 0;
+                       od_table->OverDriveTable.FeatureCtrlMask |= 1U <<
+PP_OD_FEATURE_PPT_BIT;
+
+                       ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+                       if (ret) {
+                               dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                               return ret;
+                       }
+               }
+               return smu_v14_0_set_power_limit(smu, limit_type, limit);
+       } else if (smu->od_enabled) {
+               ret = smu_v14_0_set_power_limit(smu, limit_type, msg_limit);
+               if (ret)
+                       return ret;
+
+               od_table->OverDriveTable.Ppt = (limit * 100) / msg_limit - 100;
+               od_table->OverDriveTable.FeatureCtrlMask |= 1U <<
+PP_OD_FEATURE_PPT_BIT;
+
+               ret = smu_v14_0_2_upload_overdrive_table(smu, od_table);
+               if (ret) {
+                 dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                 return ret;
+               }
+
+               smu->current_power_limit = limit;
+       } else {
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
        .get_allowed_feature_mask = smu_v14_0_2_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v14_0_2_set_default_dpm_table,
@@ -1988,13 +2869,16 @@ static const struct pptable_funcs smu_v14_0_2_ppt_funcs = {
        .notify_memory_pool_location = smu_v14_0_notify_memory_pool_location,
        .get_gpu_metrics = smu_v14_0_2_get_gpu_metrics,
        .set_soft_freq_limited_range = smu_v14_0_set_soft_freq_limited_range,
+       .set_default_od_settings = smu_v14_0_2_set_default_od_settings,
+       .restore_user_od_settings = smu_v14_0_2_restore_user_od_settings,
+       .od_edit_dpm_table = smu_v14_0_2_od_edit_dpm_table,
        .init_pptable_microcode = smu_v14_0_init_pptable_microcode,
        .populate_umd_state_clk = smu_v14_0_2_populate_umd_state_clk,
        .set_performance_level = smu_v14_0_set_performance_level,
        .gfx_off_control = smu_v14_0_gfx_off_control,
        .get_unique_id = smu_v14_0_2_get_unique_id,
        .get_power_limit = smu_v14_0_2_get_power_limit,
-       .set_power_limit = smu_v14_0_set_power_limit,
+       .set_power_limit = smu_v14_0_2_set_power_limit,
        .set_power_source = smu_v14_0_set_power_source,
        .get_power_profile_mode = smu_v14_0_2_get_power_profile_mode,
        .set_power_profile_mode = smu_v14_0_2_set_power_profile_mode,
--
2.34.1



More information about the amd-gfx mailing list