Revert "drm/amd/pm: fix the high voltage and temperature issue"
[linux-2.6-block.git] / drivers / gpu / drm / amd / pm / swsmu / smu13 / smu_v13_0_0_ppt.c
index 0fb6be11a0cc7a611ed4275b37740cf04934cbff..462a0e6aa53e3fef9e62ea1241a4f64233a7d98f 100644 (file)
  */
 #define SUPPORT_ECCTABLE_SMU_13_0_10_VERSION 0x00502200
 
+#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
+
+#define LINK_SPEED_MAX                                 3
+
 static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] = {
        MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                 1),
        MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,               1),
@@ -154,6 +168,8 @@ static struct cmn2asic_msg_mapping smu_v13_0_0_message_map[SMU_MSG_MAX_COUNT] =
        MSG_MAP(AllowGpo,                       PPSMC_MSG_SetGpoAllow,           0),
        MSG_MAP(AllowIHHostInterrupt,           PPSMC_MSG_AllowIHHostInterrupt,       0),
        MSG_MAP(ReenableAcDcInterrupt,          PPSMC_MSG_ReenableAcDcInterrupt,       0),
+       MSG_MAP(DALNotPresent,          PPSMC_MSG_DALNotPresent,       0),
+       MSG_MAP(EnableUCLKShadow,               PPSMC_MSG_EnableUCLKShadow,            0),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
@@ -167,6 +183,7 @@ static struct cmn2asic_mapping smu_v13_0_0_clk_map[SMU_CLK_COUNT] = {
        CLK_MAP(VCLK1,          PPCLK_VCLK_1),
        CLK_MAP(DCLK,           PPCLK_DCLK_0),
        CLK_MAP(DCLK1,          PPCLK_DCLK_1),
+       CLK_MAP(DCEFCLK,        PPCLK_DCFCLK),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_feature_mask_map[SMU_FEATURE_COUNT] = {
@@ -237,6 +254,7 @@ static struct cmn2asic_mapping smu_v13_0_0_table_map[SMU_TABLE_COUNT] = {
        TAB_MAP(I2C_COMMANDS),
        TAB_MAP(ECCINFO),
        TAB_MAP(OVERDRIVE),
+       TAB_MAP(WIFIBAND),
 };
 
 static struct cmn2asic_mapping smu_v13_0_0_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
@@ -280,7 +298,6 @@ smu_v13_0_0_get_allowed_feature_mask(struct smu_context *smu,
                                  uint32_t *feature_mask, uint32_t num)
 {
        struct amdgpu_device *adev = smu->adev;
-       u32 smu_version;
 
        if (num > 2)
                return -EINVAL;
@@ -300,8 +317,7 @@ smu_v13_0_0_get_allowed_feature_mask(struct smu_context *smu,
                *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_DPM_SOCCLK_BIT);
 
        /* PMFW 78.58 contains a critical fix for gfxoff feature */
-       smu_cmn_get_smc_version(smu, NULL, &smu_version);
-       if ((smu_version < 0x004e3a00) ||
+       if ((smu->smc_fw_version < 0x004e3a00) ||
             !(adev->pm.pp_feature & PP_GFXOFF_MASK))
                *(uint64_t *)feature_mask &= ~FEATURE_MASK(FEATURE_GFXOFF_BIT);
 
@@ -332,45 +348,33 @@ static int smu_v13_0_0_check_powerplay_table(struct smu_context *smu)
                table_context->power_play_table;
        struct smu_baco_context *smu_baco = &smu->smu_baco;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
-#if 0
-       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.OverDriveLimitsMin;
-#endif
 
        if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_HARDWAREDC)
                smu->dc_controlled_by_gpio = true;
 
-       if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_BACO ||
-           powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO)
+       if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_BACO) {
                smu_baco->platform_support = true;
 
-       if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO)
-               smu_baco->maco_support = true;
+               if (powerplay_table->platform_caps & SMU_13_0_0_PP_PLATFORM_CAP_MACO)
+                       smu_baco->maco_support = true;
+       }
 
-       /*
-        * We are in the transition to a new OD mechanism.
-        * Disable the OD feature support for SMU13 temporarily.
-        * TODO: get this reverted when new OD mechanism online
-        */
-#if 0
        if (!overdrive_lowerlimits->FeatureCtrlMask ||
            !overdrive_upperlimits->FeatureCtrlMask)
                smu->od_enabled = false;
 
+       table_context->thermal_controller_type =
+               powerplay_table->thermal_controller_type;
+
        /*
         * Instead of having its own buffer space and get overdrive_table copied,
         * smu->od_settings just points to the actual overdrive_table
         */
        smu->od_settings = &powerplay_table->overdrive_table;
-#else
-       smu->od_enabled = false;
-#endif
-
-       table_context->thermal_controller_type =
-               powerplay_table->thermal_controller_type;
 
        smu->adev->pm.no_fan =
                !(pptable->SkuTable.FeaturesToRun[0] & (1 << FEATURE_FAN_CONTROL_BIT));
@@ -496,6 +500,9 @@ static int smu_v13_0_0_tables_init(struct smu_context *smu)
                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_ECCINFO, sizeof(EccInfoTable_t),
                        PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+       SMU_TABLE_INIT(tables, SMU_TABLE_WIFIBAND,
+                      sizeof(WifiBandEntryTable_t), PAGE_SIZE,
+                      AMDGPU_GEM_DOMAIN_VRAM);
 
        smu_table->metrics_table = kzalloc(sizeof(SmuMetricsExternal_t), GFP_KERNEL);
        if (!smu_table->metrics_table)
@@ -698,6 +705,22 @@ static int smu_v13_0_0_set_default_dpm_table(struct smu_context *smu)
                pcie_table->num_of_link_levels++;
        }
 
+       /* dcefclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.dcef_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCN_BIT)) {
+               ret = smu_v13_0_set_single_dpm_table(smu,
+                                                    SMU_DCEFCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dcefclk / 100;
+               dpm_table->dpm_levels[0].enabled = true;
+               dpm_table->min = dpm_table->dpm_levels[0].value;
+               dpm_table->max = dpm_table->dpm_levels[0].value;
+       }
+
        return 0;
 }
 
@@ -785,6 +808,9 @@ static int smu_v13_0_0_get_smu_metrics_data(struct smu_context *smu,
        case METRICS_CURR_FCLK:
                *value = metrics->CurrClock[PPCLK_FCLK];
                break;
+       case METRICS_CURR_DCEFCLK:
+               *value = metrics->CurrClock[PPCLK_DCFCLK];
+               break;
        case METRICS_AVERAGE_GFXCLK:
                if (metrics->AverageGfxActivity <= SMU_13_0_0_BUSY_THRESHOLD)
                        *value = metrics->AverageGfxclkFrequencyPostDs;
@@ -947,7 +973,7 @@ static int smu_v13_0_0_read_sensor(struct smu_context *smu,
                                                       (uint32_t *)data);
                *size = 4;
                break;
-       case AMDGPU_PP_SENSOR_GPU_POWER:
+       case AMDGPU_PP_SENSOR_GPU_AVG_POWER:
                ret = smu_v13_0_0_get_smu_metrics_data(smu,
                                                       METRICS_AVERAGE_SOCKETPOWER,
                                                       (uint32_t *)data);
@@ -991,6 +1017,7 @@ static int smu_v13_0_0_read_sensor(struct smu_context *smu,
                                                       (uint32_t *)data);
                *size = 4;
                break;
+       case AMDGPU_PP_SENSOR_GPU_INPUT_POWER:
        default:
                ret = -EOPNOTSUPP;
                break;
@@ -1037,6 +1064,9 @@ static int smu_v13_0_0_get_current_clk_freq_by_table(struct smu_context *smu,
        case PPCLK_DCLK_1:
                member_type = METRICS_AVERAGE_DCLK1;
                break;
+       case PPCLK_DCFCLK:
+               member_type = METRICS_CURR_DCEFCLK;
+               break;
        default:
                return -EINVAL;
        }
@@ -1058,7 +1088,6 @@ static bool smu_v13_0_0_is_od_feature_supported(struct smu_context *smu,
 
 static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
                                              int od_feature_bit,
-                                             bool lower_boundary,
                                              int32_t *min,
                                              int32_t *max)
 {
@@ -1070,29 +1099,52 @@ static void smu_v13_0_0_get_od_setting_limits(struct smu_context *smu,
        int32_t od_min_setting, od_max_setting;
 
        switch (od_feature_bit) {
-       case PP_OD_FEATURE_GFXCLK_BIT:
-               if (lower_boundary) {
-                       od_min_setting = overdrive_lowerlimits->GfxclkFmin;
-                       od_max_setting = overdrive_upperlimits->GfxclkFmin;
-               } else {
-                       od_min_setting = overdrive_lowerlimits->GfxclkFmax;
-                       od_max_setting = overdrive_upperlimits->GfxclkFmax;
-               }
+       case PP_OD_FEATURE_GFXCLK_FMIN:
+               od_min_setting = overdrive_lowerlimits->GfxclkFmin;
+               od_max_setting = overdrive_upperlimits->GfxclkFmin;
                break;
-       case PP_OD_FEATURE_UCLK_BIT:
-               if (lower_boundary) {
-                       od_min_setting = overdrive_lowerlimits->UclkFmin;
-                       od_max_setting = overdrive_upperlimits->UclkFmin;
-               } else {
-                       od_min_setting = overdrive_lowerlimits->UclkFmax;
-                       od_max_setting = overdrive_upperlimits->UclkFmax;
-               }
+       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_GFX_VF_CURVE_BIT:
+       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;
                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;
+       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;
        }
 
@@ -1188,6 +1240,9 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
        case SMU_DCLK1:
                single_dpm_table = &(dpm_context->dpm_tables.dclk_table);
                break;
+       case SMU_DCEFCLK:
+               single_dpm_table = &(dpm_context->dpm_tables.dcef_table);
+               break;
        default:
                break;
        }
@@ -1201,6 +1256,7 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
        case SMU_VCLK1:
        case SMU_DCLK:
        case SMU_DCLK1:
+       case SMU_DCEFCLK:
                ret = smu_v13_0_0_get_current_clk_freq_by_table(smu, clk_type, &curr_freq);
                if (ret) {
                        dev_err(smu->adev->dev, "Failed to get current clock freq!");
@@ -1296,16 +1352,115 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
                                        od_table->OverDriveTable.UclkFmax);
                break;
 
-       case SMU_OD_VDDC_CURVE:
+       case SMU_OD_VDDGFX_OFFSET:
                if (!smu_v13_0_0_is_od_feature_supported(smu,
                                                         PP_OD_FEATURE_GFX_VF_CURVE_BIT))
                        break;
 
-               size += sysfs_emit_at(buf, size, "OD_VDDC_CURVE:\n");
-               for (i = 0; i < PP_NUM_OD_VF_CURVE_POINTS; i++)
-                       size += sysfs_emit_at(buf, size, "%d: %dmv\n",
+               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_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,
-                                               od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[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_ACOUSTIC_LIMIT:
+               if (!smu_v13_0_0_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_v13_0_0_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_v13_0_0_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_v13_0_0_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_v13_0_0_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_v13_0_0_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_v13_0_0_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_v13_0_0_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:
@@ -1318,13 +1473,11 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
 
                if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFXCLK_BIT)) {
                        smu_v13_0_0_get_od_setting_limits(smu,
-                                                         PP_OD_FEATURE_GFXCLK_BIT,
-                                                         true,
+                                                         PP_OD_FEATURE_GFXCLK_FMIN,
                                                          &min_value,
                                                          NULL);
                        smu_v13_0_0_get_od_setting_limits(smu,
-                                                         PP_OD_FEATURE_GFXCLK_BIT,
-                                                         false,
+                                                         PP_OD_FEATURE_GFXCLK_FMAX,
                                                          NULL,
                                                          &max_value);
                        size += sysfs_emit_at(buf, size, "SCLK: %7uMhz %10uMhz\n",
@@ -1333,13 +1486,11 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
 
                if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_UCLK_BIT)) {
                        smu_v13_0_0_get_od_setting_limits(smu,
-                                                         PP_OD_FEATURE_UCLK_BIT,
-                                                         true,
+                                                         PP_OD_FEATURE_UCLK_FMIN,
                                                          &min_value,
                                                          NULL);
                        smu_v13_0_0_get_od_setting_limits(smu,
-                                                         PP_OD_FEATURE_UCLK_BIT,
-                                                         false,
+                                                         PP_OD_FEATURE_UCLK_FMAX,
                                                          NULL,
                                                          &max_value);
                        size += sysfs_emit_at(buf, size, "MCLK: %7uMhz %10uMhz\n",
@@ -1348,11 +1499,10 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
 
                if (smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) {
                        smu_v13_0_0_get_od_setting_limits(smu,
-                                                         PP_OD_FEATURE_GFX_VF_CURVE_BIT,
-                                                         true,
+                                                         PP_OD_FEATURE_GFX_VF_CURVE,
                                                          &min_value,
                                                          &max_value);
-                       size += sysfs_emit_at(buf, size, "VDDC_CURVE: %7dmv %10dmv\n",
+                       size += sysfs_emit_at(buf, size, "VDDGFX_OFFSET: %7dmv %10dmv\n",
                                              min_value, max_value);
                }
                break;
@@ -1364,6 +1514,60 @@ static int smu_v13_0_0_print_clk_levels(struct smu_context *smu,
        return size;
 }
 
+
+static int smu_v13_0_0_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_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                                         enum PP_OD_DPM_TABLE_COMMAND type,
                                         long input[],
@@ -1373,7 +1577,7 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
        OverDriveTableExternal_t *od_table =
                (OverDriveTableExternal_t *)table_context->overdrive_table;
        struct amdgpu_device *adev = smu->adev;
-       uint32_t offset_of_featurectrlmask;
+       uint32_t offset_of_voltageoffset;
        int32_t minimum, maximum;
        uint32_t feature_ctrlmask;
        int i, ret = 0;
@@ -1394,8 +1598,7 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                        switch (input[i]) {
                        case 0:
                                smu_v13_0_0_get_od_setting_limits(smu,
-                                                                 PP_OD_FEATURE_GFXCLK_BIT,
-                                                                 true,
+                                                                 PP_OD_FEATURE_GFXCLK_FMIN,
                                                                  &minimum,
                                                                  &maximum);
                                if (input[i + 1] < minimum ||
@@ -1411,8 +1614,7 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
 
                        case 1:
                                smu_v13_0_0_get_od_setting_limits(smu,
-                                                                 PP_OD_FEATURE_GFXCLK_BIT,
-                                                                 false,
+                                                                 PP_OD_FEATURE_GFXCLK_FMAX,
                                                                  &minimum,
                                                                  &maximum);
                                if (input[i + 1] < minimum ||
@@ -1457,8 +1659,7 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                        switch (input[i]) {
                        case 0:
                                smu_v13_0_0_get_od_setting_limits(smu,
-                                                                 PP_OD_FEATURE_UCLK_BIT,
-                                                                 true,
+                                                                 PP_OD_FEATURE_UCLK_FMIN,
                                                                  &minimum,
                                                                  &maximum);
                                if (input[i + 1] < minimum ||
@@ -1474,8 +1675,7 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
 
                        case 1:
                                smu_v13_0_0_get_od_setting_limits(smu,
-                                                                 PP_OD_FEATURE_UCLK_BIT,
-                                                                 false,
+                                                                 PP_OD_FEATURE_UCLK_FMAX,
                                                                  &minimum,
                                                                  &maximum);
                                if (input[i + 1] < minimum ||
@@ -1505,40 +1705,167 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                }
                break;
 
-       case PP_OD_EDIT_VDDC_CURVE:
+       case PP_OD_EDIT_VDDGFX_OFFSET:
                if (!smu_v13_0_0_is_od_feature_supported(smu, PP_OD_FEATURE_GFX_VF_CURVE_BIT)) {
-                       dev_warn(adev->dev, "VF curve setting not supported!\n");
+                       dev_warn(adev->dev, "Gfx offset setting not supported!\n");
+                       return -ENOTSUPP;
+               }
+
+               smu_v13_0_0_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_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] >= PP_NUM_OD_VF_CURVE_POINTS ||
+               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_GFX_VF_CURVE_BIT,
-                                                 true,
+                                                 PP_OD_FEATURE_FAN_CURVE_TEMP,
                                                  &minimum,
                                                  &maximum);
                if (input[1] < minimum ||
                    input[1] > maximum) {
-                       dev_info(adev->dev, "Voltage offset (%ld) must be within [%d, %d]!\n",
+                       dev_info(adev->dev, "Fan curve temp setting(%ld) must be within [%d, %d]!\n",
                                 input[1], minimum, maximum);
                        return -EINVAL;
                }
 
-               od_table->OverDriveTable.VoltageOffsetPerZoneBoundary[input[0]] = input[1];
-               od_table->OverDriveTable.FeatureCtrlMask |= 1U << PP_OD_FEATURE_GFX_VF_CURVE_BIT;
+               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_EDIT_ACOUSTIC_LIMIT:
+               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;
+               }
+
+               smu_v13_0_0_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_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;
+               }
+
+               smu_v13_0_0_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_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;
+               }
+
+               smu_v13_0_0_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_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;
+               }
+
+               smu_v13_0_0_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:
-               feature_ctrlmask = od_table->OverDriveTable.FeatureCtrlMask;
-               memcpy(od_table,
+               if (size == 1) {
+                       ret = smu_v13_0_0_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;
+                       od_table->OverDriveTable.FeatureCtrlMask = feature_ctrlmask;
+               }
                fallthrough;
-
        case PP_OD_COMMIT_DPM_TABLE:
                /*
                 * The member below instructs PMFW the settings focused in
@@ -1547,10 +1874,10 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                 * It does not contain actual informations about user's custom
                 * settings. Thus we do not cache it.
                 */
-               offset_of_featurectrlmask = offsetof(OverDriveTable_t, FeatureCtrlMask);
-               if (memcmp((u8 *)od_table + offset_of_featurectrlmask,
-                          table_context->user_overdrive_table + offset_of_featurectrlmask,
-                          sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask)) {
+               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_v13_0_0_dump_od_table(smu, od_table);
 
                        ret = smu_v13_0_0_upload_overdrive_table(smu, od_table);
@@ -1560,9 +1887,9 @@ static int smu_v13_0_0_od_edit_dpm_table(struct smu_context *smu,
                        }
 
                        od_table->OverDriveTable.FeatureCtrlMask = 0;
-                       memcpy(table_context->user_overdrive_table + offset_of_featurectrlmask,
-                              (u8 *)od_table + offset_of_featurectrlmask,
-                              sizeof(OverDriveTableExternal_t) - offset_of_featurectrlmask);
+                       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,
@@ -1698,7 +2025,6 @@ static int smu_v13_0_0_get_thermal_temperature_range(struct smu_context *smu,
        return 0;
 }
 
-#define MAX(a, b)      ((a) > (b) ? (a) : (b))
 static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
                                           void **table)
 {
@@ -1722,12 +2048,12 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
        gpu_metrics->temperature_mem = metrics->AvgTemperature[TEMP_MEM];
        gpu_metrics->temperature_vrgfx = metrics->AvgTemperature[TEMP_VR_GFX];
        gpu_metrics->temperature_vrsoc = metrics->AvgTemperature[TEMP_VR_SOC];
-       gpu_metrics->temperature_vrmem = MAX(metrics->AvgTemperature[TEMP_VR_MEM0],
+       gpu_metrics->temperature_vrmem = max(metrics->AvgTemperature[TEMP_VR_MEM0],
                                             metrics->AvgTemperature[TEMP_VR_MEM1]);
 
        gpu_metrics->average_gfx_activity = metrics->AverageGfxActivity;
        gpu_metrics->average_umc_activity = metrics->AverageUclkActivity;
-       gpu_metrics->average_mm_activity = MAX(metrics->Vcn0ActivityPercentage,
+       gpu_metrics->average_mm_activity = max(metrics->Vcn0ActivityPercentage,
                                               metrics->Vcn1ActivityPercentage);
 
        gpu_metrics->average_socket_power = metrics->AverageSocketPower;
@@ -1765,7 +2091,10 @@ static ssize_t smu_v13_0_0_get_gpu_metrics(struct smu_context *smu,
        gpu_metrics->current_fan_speed = metrics->AvgFanRpm;
 
        gpu_metrics->pcie_link_width = metrics->PcieWidth;
-       gpu_metrics->pcie_link_speed = metrics->PcieRate;
+       if ((metrics->PcieRate - 1) > LINK_SPEED_MAX)
+               gpu_metrics->pcie_link_speed = pcie_gen_to_speed(1);
+       else
+               gpu_metrics->pcie_link_speed = pcie_gen_to_speed(metrics->PcieRate);
 
        gpu_metrics->system_clock_counter = ktime_get_boottime_ns();
 
@@ -1778,6 +2107,24 @@ 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 |
+                                           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_v13_0_0_set_default_od_settings(struct smu_context *smu)
 {
        OverDriveTableExternal_t *od_table =
@@ -1827,8 +2174,24 @@ 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];
+               }
+               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_v13_0_0_set_supported_od_feature_mask(smu);
+
        return 0;
 }
 
@@ -1839,9 +2202,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)
@@ -1927,8 +2291,6 @@ static void smu_v13_0_0_get_unique_id(struct smu_context *smu)
 
 out:
        adev->unique_id = ((uint64_t)upper32 << 32) | lower32;
-       if (adev->serial[0] == '\0')
-               sprintf(adev->serial, "%016llx", adev->unique_id);
 }
 
 static int smu_v13_0_0_get_fan_speed_pwm(struct smu_context *smu,
@@ -1948,7 +2310,7 @@ static int smu_v13_0_0_get_fan_speed_pwm(struct smu_context *smu,
        }
 
        /* Convert the PMFW output which is in percent to pwm(255) based */
-       *speed = MIN(*speed * 255 / 100, 255);
+       *speed = min(*speed * 255 / 100, (uint32_t)255);
 
        return 0;
 }
@@ -1984,16 +2346,18 @@ static int smu_v13_0_0_enable_mgpu_fan_boost(struct smu_context *smu)
 }
 
 static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
-                                      uint32_t *current_power_limit,
-                                      uint32_t *default_power_limit,
-                                      uint32_t *max_power_limit)
+                                               uint32_t *current_power_limit,
+                                               uint32_t *default_power_limit,
+                                               uint32_t *max_power_limit,
+                                               uint32_t *min_power_limit)
 {
        struct smu_table_context *table_context = &smu->smu_table;
        struct smu_13_0_0_powerplay_table *powerplay_table =
                (struct smu_13_0_0_powerplay_table *)table_context->power_play_table;
        PPTable_t *pptable = table_context->driver_pptable;
        SkuTable_t *skutable = &pptable->SkuTable;
-       uint32_t power_limit, od_percent;
+       uint32_t power_limit, od_percent_upper, od_percent_lower;
+       uint32_t msg_limit = skutable->MsgLimits.Power[PPT_THROTTLER_PPT0][POWER_SOURCE_AC];
 
        if (smu_v13_0_get_current_power_limit(smu, &power_limit))
                power_limit = smu->adev->pm.ac_power ?
@@ -2005,16 +2369,25 @@ static int smu_v13_0_0_get_power_limit(struct smu_context *smu,
        if (default_power_limit)
                *default_power_limit = power_limit;
 
-       if (max_power_limit) {
-               if (smu->od_enabled) {
-                       od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+       if (smu->od_enabled) {
+               od_percent_upper = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+               od_percent_lower = le32_to_cpu(powerplay_table->overdrive_table.min[SMU_13_0_0_ODSETTING_POWERPERCENTAGE]);
+       } else {
+               od_percent_upper = 0;
+               od_percent_lower = 100;
+       }
 
-                       dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
+       dev_dbg(smu->adev->dev, "od percent upper:%d, od percent lower:%d (default power: %d)\n",
+                                       od_percent_upper, od_percent_lower, power_limit);
 
-                       power_limit *= (100 + od_percent);
-                       power_limit /= 100;
-               }
-               *max_power_limit = power_limit;
+       if (max_power_limit) {
+               *max_power_limit = msg_limit * (100 + od_percent_upper);
+               *max_power_limit /= 100;
+       }
+
+       if (min_power_limit) {
+               *min_power_limit = power_limit * (100 - od_percent_lower);
+               *min_power_limit /= 100;
        }
 
        return 0;
@@ -2109,6 +2482,7 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
        DpmActivityMonitorCoeffInt_t *activity_monitor =
                &(activity_monitor_external.DpmActivityMonitorCoeffInt);
        int workload_type, ret = 0;
+       u32 workload_mask;
 
        smu->power_profile_mode = input[size];
 
@@ -2162,84 +2536,52 @@ static int smu_v13_0_0_set_power_profile_mode(struct smu_context *smu,
                }
        }
 
-       if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE &&
-               (((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xC8)) ||
-               ((smu->adev->pdev->device == 0x744C) && (smu->adev->pdev->revision == 0xCC)))) {
-               ret = smu_cmn_update_table(smu,
-                                          SMU_TABLE_ACTIVITY_MONITOR_COEFF,
-                                          WORKLOAD_PPLIB_COMPUTE_BIT,
-                                          (void *)(&activity_monitor_external),
-                                          false);
-               if (ret) {
-                       dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
-                       return ret;
-               }
-
-               ret = smu_cmn_update_table(smu,
-                                          SMU_TABLE_ACTIVITY_MONITOR_COEFF,
-                                          WORKLOAD_PPLIB_CUSTOM_BIT,
-                                          (void *)(&activity_monitor_external),
-                                          true);
-               if (ret) {
-                       dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
-                       return ret;
-               }
-
-               workload_type = smu_cmn_to_asic_specific_index(smu,
-                                                      CMN2ASIC_MAPPING_WORKLOAD,
-                                                      PP_SMC_POWER_PROFILE_CUSTOM);
-       } else {
-               /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
-               workload_type = smu_cmn_to_asic_specific_index(smu,
+       /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
+       workload_type = smu_cmn_to_asic_specific_index(smu,
                                                       CMN2ASIC_MAPPING_WORKLOAD,
                                                       smu->power_profile_mode);
-       }
 
        if (workload_type < 0)
                return -EINVAL;
 
+       workload_mask = 1 << workload_type;
+
+       /* Add optimizations for SMU13.0.0/10.  Reuse the power saving profile */
+       if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_COMPUTE) {
+               if ((amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 0) &&
+                       ((smu->adev->pm.fw_version == 0x004e6601) ||
+                       (smu->adev->pm.fw_version >= 0x004e7300))) ||
+                       (amdgpu_ip_version(smu->adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10) &&
+                        smu->adev->pm.fw_version >= 0x00504500)) {
+                       workload_type = smu_cmn_to_asic_specific_index(smu,
+                                                                                                                  CMN2ASIC_MAPPING_WORKLOAD,
+                                                                                                                  PP_SMC_POWER_PROFILE_POWERSAVING);
+                       if (workload_type >= 0)
+                               workload_mask |= 1 << workload_type;
+               }
+       }
+
        return smu_cmn_send_smc_msg_with_param(smu,
                                               SMU_MSG_SetWorkloadMask,
-                                              1 << workload_type,
+                                              workload_mask,
                                               NULL);
 }
 
-static int smu_v13_0_0_baco_enter(struct smu_context *smu)
-{
-       struct smu_baco_context *smu_baco = &smu->smu_baco;
-       struct amdgpu_device *adev = smu->adev;
-
-       if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev))
-               return smu_v13_0_baco_set_armd3_sequence(smu,
-                               smu_baco->maco_support ? BACO_SEQ_BAMACO : BACO_SEQ_BACO);
-       else
-               return smu_v13_0_baco_enter(smu);
-}
-
-static int smu_v13_0_0_baco_exit(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-
-       if (adev->in_runpm && smu_cmn_is_audio_func_enabled(adev)) {
-               /* Wait for PMFW handling for the Dstate change */
-               usleep_range(10000, 11000);
-               return smu_v13_0_baco_set_armd3_sequence(smu, BACO_SEQ_ULPS);
-       } else {
-               return smu_v13_0_baco_exit(smu);
-       }
-}
-
 static bool smu_v13_0_0_is_mode1_reset_supported(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
        u32 smu_version;
+       int ret;
 
        /* SRIOV does not support SMU mode1 reset */
        if (amdgpu_sriov_vf(adev))
                return false;
 
        /* PMFW support is available since 78.41 */
-       smu_cmn_get_smc_version(smu, NULL, &smu_version);
+       ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
+       if (ret)
+               return false;
+
        if (smu_version < 0x004e2900)
                return false;
 
@@ -2430,13 +2772,10 @@ static void smu_v13_0_0_set_mode1_reset_param(struct smu_context *smu,
                                                uint32_t supported_version,
                                                uint32_t *param)
 {
-       uint32_t smu_version;
        struct amdgpu_device *adev = smu->adev;
        struct amdgpu_ras *ras = amdgpu_ras_get_context(adev);
 
-       smu_cmn_get_smc_version(smu, NULL, &smu_version);
-
-       if ((smu_version >= supported_version) &&
+       if ((smu->smc_fw_version >= supported_version) &&
                        ras && atomic_read(&ras->in_recovery))
                /* Set RAS fatal error reset flag */
                *param = 1 << 16;
@@ -2450,7 +2789,7 @@ static int smu_v13_0_0_mode1_reset(struct smu_context *smu)
        uint32_t param;
        struct amdgpu_device *adev = smu->adev;
 
-       switch (adev->ip_versions[MP1_HWIP][0]) {
+       switch (amdgpu_ip_version(adev, MP1_HWIP, 0)) {
        case IP_VERSION(13, 0, 0):
                /* SMU 13_0_0 PMFW supports RAS fatal error reset from 78.77 */
                smu_v13_0_0_set_mode1_reset_param(smu, 0x004e4d00, &param);
@@ -2483,7 +2822,7 @@ static int smu_v13_0_0_mode2_reset(struct smu_context *smu)
        int ret;
        struct amdgpu_device *adev = smu->adev;
 
-       if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
+       if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10))
                ret = smu_cmn_send_smc_msg(smu, SMU_MSG_Mode2Reset, NULL);
        else
                return -EOPNOTSUPP;
@@ -2495,7 +2834,7 @@ static int smu_v13_0_0_enable_gfx_features(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
 
-       if (adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10))
+       if (amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10))
                return smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_EnableAllSmuFeatures,
                                                                                   FEATURE_PWR_GFX, NULL);
        else
@@ -2552,15 +2891,10 @@ static int smu_v13_0_0_send_bad_mem_channel_flag(struct smu_context *smu,
 static int smu_v13_0_0_check_ecc_table_support(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
-       uint32_t if_version = 0xff, smu_version = 0xff;
        int ret = 0;
 
-       ret = smu_cmn_get_smc_version(smu, &if_version, &smu_version);
-       if (ret)
-               return -EOPNOTSUPP;
-
-       if ((adev->ip_versions[MP1_HWIP][0] == IP_VERSION(13, 0, 10)) &&
-               (smu_version >= SUPPORT_ECCTABLE_SMU_13_0_10_VERSION))
+       if ((amdgpu_ip_version(adev, MP1_HWIP, 0) == IP_VERSION(13, 0, 10)) &&
+               (smu->smc_fw_version >= SUPPORT_ECCTABLE_SMU_13_0_10_VERSION))
                return ret;
        else
                return -EOPNOTSUPP;
@@ -2607,6 +2941,69 @@ static ssize_t smu_v13_0_0_get_ecc_info(struct smu_context *smu,
        return ret;
 }
 
+static bool smu_v13_0_0_wbrf_support_check(struct smu_context *smu)
+{
+       struct amdgpu_device *adev = smu->adev;
+
+       switch (adev->ip_versions[MP1_HWIP][0]) {
+       case IP_VERSION(13, 0, 0):
+               return smu->smc_fw_version >= 0x004e6300;
+       case IP_VERSION(13, 0, 10):
+               return smu->smc_fw_version >= 0x00503300;
+       default:
+               return false;
+       }
+}
+
+static int smu_v13_0_0_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;
+       SkuTable_t *skutable = &pptable->SkuTable;
+       uint32_t msg_limit = 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_v13_0_0_upload_overdrive_table(smu, od_table);
+                       if (ret) {
+                               dev_err(smu->adev->dev, "Failed to upload overdrive table!\n");
+                               return ret;
+                       }
+               }
+               return smu_v13_0_set_power_limit(smu, limit_type, limit);
+       } else if (smu->od_enabled) {
+               ret = smu_v13_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_v13_0_0_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_v13_0_0_ppt_funcs = {
        .get_allowed_feature_mask = smu_v13_0_0_get_allowed_feature_mask,
        .set_default_dpm_table = smu_v13_0_0_set_default_dpm_table,
@@ -2661,7 +3058,7 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .set_fan_control_mode = smu_v13_0_set_fan_control_mode,
        .enable_mgpu_fan_boost = smu_v13_0_0_enable_mgpu_fan_boost,
        .get_power_limit = smu_v13_0_0_get_power_limit,
-       .set_power_limit = smu_v13_0_set_power_limit,
+       .set_power_limit = smu_v13_0_0_set_power_limit,
        .set_power_source = smu_v13_0_set_power_source,
        .get_power_profile_mode = smu_v13_0_0_get_power_profile_mode,
        .set_power_profile_mode = smu_v13_0_0_set_power_profile_mode,
@@ -2672,10 +3069,8 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .deep_sleep_control = smu_v13_0_deep_sleep_control,
        .gfx_ulv_control = smu_v13_0_gfx_ulv_control,
        .baco_is_support = smu_v13_0_baco_is_support,
-       .baco_get_state = smu_v13_0_baco_get_state,
-       .baco_set_state = smu_v13_0_baco_set_state,
-       .baco_enter = smu_v13_0_0_baco_enter,
-       .baco_exit = smu_v13_0_0_baco_exit,
+       .baco_enter = smu_v13_0_baco_enter,
+       .baco_exit = smu_v13_0_baco_exit,
        .mode1_reset_is_support = smu_v13_0_0_is_mode1_reset_supported,
        .mode1_reset = smu_v13_0_0_mode1_reset,
        .mode2_reset = smu_v13_0_0_mode2_reset,
@@ -2686,6 +3081,10 @@ static const struct pptable_funcs smu_v13_0_0_ppt_funcs = {
        .send_hbm_bad_channel_flag = smu_v13_0_0_send_bad_mem_channel_flag,
        .gpo_control = smu_v13_0_gpo_control,
        .get_ecc_info = smu_v13_0_0_get_ecc_info,
+       .notify_display_change = smu_v13_0_notify_display_change,
+       .is_asic_wbrf_supported = smu_v13_0_0_wbrf_support_check,
+       .enable_uclk_shadow = smu_v13_0_enable_uclk_shadow,
+       .set_wbrf_exclusion_ranges = smu_v13_0_set_wbrf_exclusion_ranges,
 };
 
 void smu_v13_0_0_set_ppt_funcs(struct smu_context *smu)