drm/amd/powerplay: update swSMU VCN/JPEG PG logics
[linux-2.6-microblaze.git] / drivers / gpu / drm / amd / powerplay / navi10_ppt.c
index 0c9be86..82659b7 100644 (file)
  *
  */
 
+#define SWSMU_CODE_LAYER_L2
+
 #include <linux/firmware.h>
 #include <linux/pci.h>
+#include <linux/i2c.h>
 #include "amdgpu.h"
 #include "amdgpu_smu.h"
-#include "smu_internal.h"
 #include "atomfirmware.h"
 #include "amdgpu_atomfirmware.h"
+#include "amdgpu_atombios.h"
 #include "soc15_common.h"
 #include "smu_v11_0.h"
 #include "smu11_driver_if_navi10.h"
 #include "smu_v11_0_ppsmc.h"
 #include "nbio/nbio_2_3_offset.h"
 #include "nbio/nbio_2_3_sh_mask.h"
+#include "thm/thm_11_0_2_offset.h"
+#include "thm/thm_11_0_2_sh_mask.h"
 
 #include "asic_reg/mp/mp_11_0_sh_mask.h"
+#include "smu_cmn.h"
+
+/*
+ * DO NOT use these for err/warn/info/debug messages.
+ * Use dev_err, dev_warn, dev_info and dev_dbg instead.
+ * They are more MGPU friendly.
+ */
+#undef pr_err
+#undef pr_warn
+#undef pr_info
+#undef pr_debug
+
+#define to_amdgpu_device(x) (container_of(x, struct amdgpu_device, pm.smu_i2c))
 
 #define FEATURE_MASK(feature) (1ULL << feature)
 #define SMC_DPM_FEATURE ( \
        FEATURE_MASK(FEATURE_DPM_LINK_BIT)       | \
        FEATURE_MASK(FEATURE_DPM_DCEFCLK_BIT))
 
-#define MSG_MAP(msg, index) \
-       [SMU_MSG_##msg] = {1, (index)}
-
-static struct smu_11_0_cmn2aisc_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
-       MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage),
-       MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion),
-       MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion),
-       MSG_MAP(SetAllowedFeaturesMaskLow,      PPSMC_MSG_SetAllowedFeaturesMaskLow),
-       MSG_MAP(SetAllowedFeaturesMaskHigh,     PPSMC_MSG_SetAllowedFeaturesMaskHigh),
-       MSG_MAP(EnableAllSmuFeatures,           PPSMC_MSG_EnableAllSmuFeatures),
-       MSG_MAP(DisableAllSmuFeatures,          PPSMC_MSG_DisableAllSmuFeatures),
-       MSG_MAP(EnableSmuFeaturesLow,           PPSMC_MSG_EnableSmuFeaturesLow),
-       MSG_MAP(EnableSmuFeaturesHigh,          PPSMC_MSG_EnableSmuFeaturesHigh),
-       MSG_MAP(DisableSmuFeaturesLow,          PPSMC_MSG_DisableSmuFeaturesLow),
-       MSG_MAP(DisableSmuFeaturesHigh,         PPSMC_MSG_DisableSmuFeaturesHigh),
-       MSG_MAP(GetEnabledSmuFeaturesLow,       PPSMC_MSG_GetEnabledSmuFeaturesLow),
-       MSG_MAP(GetEnabledSmuFeaturesHigh,      PPSMC_MSG_GetEnabledSmuFeaturesHigh),
-       MSG_MAP(SetWorkloadMask,                PPSMC_MSG_SetWorkloadMask),
-       MSG_MAP(SetPptLimit,                    PPSMC_MSG_SetPptLimit),
-       MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh),
-       MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow),
-       MSG_MAP(SetToolsDramAddrHigh,           PPSMC_MSG_SetToolsDramAddrHigh),
-       MSG_MAP(SetToolsDramAddrLow,            PPSMC_MSG_SetToolsDramAddrLow),
-       MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram),
-       MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu),
-       MSG_MAP(UseDefaultPPTable,              PPSMC_MSG_UseDefaultPPTable),
-       MSG_MAP(UseBackupPPTable,               PPSMC_MSG_UseBackupPPTable),
-       MSG_MAP(RunBtc,                         PPSMC_MSG_RunBtc),
-       MSG_MAP(EnterBaco,                      PPSMC_MSG_EnterBaco),
-       MSG_MAP(SetSoftMinByFreq,               PPSMC_MSG_SetSoftMinByFreq),
-       MSG_MAP(SetSoftMaxByFreq,               PPSMC_MSG_SetSoftMaxByFreq),
-       MSG_MAP(SetHardMinByFreq,               PPSMC_MSG_SetHardMinByFreq),
-       MSG_MAP(SetHardMaxByFreq,               PPSMC_MSG_SetHardMaxByFreq),
-       MSG_MAP(GetMinDpmFreq,                  PPSMC_MSG_GetMinDpmFreq),
-       MSG_MAP(GetMaxDpmFreq,                  PPSMC_MSG_GetMaxDpmFreq),
-       MSG_MAP(GetDpmFreqByIndex,              PPSMC_MSG_GetDpmFreqByIndex),
-       MSG_MAP(SetMemoryChannelConfig,         PPSMC_MSG_SetMemoryChannelConfig),
-       MSG_MAP(SetGeminiMode,                  PPSMC_MSG_SetGeminiMode),
-       MSG_MAP(SetGeminiApertureHigh,          PPSMC_MSG_SetGeminiApertureHigh),
-       MSG_MAP(SetGeminiApertureLow,           PPSMC_MSG_SetGeminiApertureLow),
-       MSG_MAP(OverridePcieParameters,         PPSMC_MSG_OverridePcieParameters),
-       MSG_MAP(SetMinDeepSleepDcefclk,         PPSMC_MSG_SetMinDeepSleepDcefclk),
-       MSG_MAP(ReenableAcDcInterrupt,          PPSMC_MSG_ReenableAcDcInterrupt),
-       MSG_MAP(NotifyPowerSource,              PPSMC_MSG_NotifyPowerSource),
-       MSG_MAP(SetUclkFastSwitch,              PPSMC_MSG_SetUclkFastSwitch),
-       MSG_MAP(SetVideoFps,                    PPSMC_MSG_SetVideoFps),
-       MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload),
-       MSG_MAP(DramLogSetDramAddrHigh,         PPSMC_MSG_DramLogSetDramAddrHigh),
-       MSG_MAP(DramLogSetDramAddrLow,          PPSMC_MSG_DramLogSetDramAddrLow),
-       MSG_MAP(DramLogSetDramSize,             PPSMC_MSG_DramLogSetDramSize),
-       MSG_MAP(ConfigureGfxDidt,               PPSMC_MSG_ConfigureGfxDidt),
-       MSG_MAP(NumOfDisplays,                  PPSMC_MSG_NumOfDisplays),
-       MSG_MAP(SetSystemVirtualDramAddrHigh,   PPSMC_MSG_SetSystemVirtualDramAddrHigh),
-       MSG_MAP(SetSystemVirtualDramAddrLow,    PPSMC_MSG_SetSystemVirtualDramAddrLow),
-       MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff),
-       MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff),
-       MSG_MAP(GetPptLimit,                    PPSMC_MSG_GetPptLimit),
-       MSG_MAP(GetDcModeMaxDpmFreq,            PPSMC_MSG_GetDcModeMaxDpmFreq),
-       MSG_MAP(GetDebugData,                   PPSMC_MSG_GetDebugData),
-       MSG_MAP(ExitBaco,                       PPSMC_MSG_ExitBaco),
-       MSG_MAP(PrepareMp1ForReset,             PPSMC_MSG_PrepareMp1ForReset),
-       MSG_MAP(PrepareMp1ForShutdown,          PPSMC_MSG_PrepareMp1ForShutdown),
-       MSG_MAP(PowerUpVcn,             PPSMC_MSG_PowerUpVcn),
-       MSG_MAP(PowerDownVcn,           PPSMC_MSG_PowerDownVcn),
-       MSG_MAP(PowerUpJpeg,            PPSMC_MSG_PowerUpJpeg),
-       MSG_MAP(PowerDownJpeg,          PPSMC_MSG_PowerDownJpeg),
-       MSG_MAP(BacoAudioD3PME,         PPSMC_MSG_BacoAudioD3PME),
-       MSG_MAP(ArmD3,                  PPSMC_MSG_ArmD3),
-       MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange),
-       MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange),
-       MSG_MAP(GetVoltageByDpm,                     PPSMC_MSG_GetVoltageByDpm),
-       MSG_MAP(GetVoltageByDpmOverdrive,            PPSMC_MSG_GetVoltageByDpmOverdrive),
+static struct cmn2asic_msg_mapping navi10_message_map[SMU_MSG_MAX_COUNT] = {
+       MSG_MAP(TestMessage,                    PPSMC_MSG_TestMessage,                  1),
+       MSG_MAP(GetSmuVersion,                  PPSMC_MSG_GetSmuVersion,                1),
+       MSG_MAP(GetDriverIfVersion,             PPSMC_MSG_GetDriverIfVersion,           1),
+       MSG_MAP(SetAllowedFeaturesMaskLow,      PPSMC_MSG_SetAllowedFeaturesMaskLow,    0),
+       MSG_MAP(SetAllowedFeaturesMaskHigh,     PPSMC_MSG_SetAllowedFeaturesMaskHigh,   0),
+       MSG_MAP(EnableAllSmuFeatures,           PPSMC_MSG_EnableAllSmuFeatures,         0),
+       MSG_MAP(DisableAllSmuFeatures,          PPSMC_MSG_DisableAllSmuFeatures,        0),
+       MSG_MAP(EnableSmuFeaturesLow,           PPSMC_MSG_EnableSmuFeaturesLow,         1),
+       MSG_MAP(EnableSmuFeaturesHigh,          PPSMC_MSG_EnableSmuFeaturesHigh,        1),
+       MSG_MAP(DisableSmuFeaturesLow,          PPSMC_MSG_DisableSmuFeaturesLow,        1),
+       MSG_MAP(DisableSmuFeaturesHigh,         PPSMC_MSG_DisableSmuFeaturesHigh,       1),
+       MSG_MAP(GetEnabledSmuFeaturesLow,       PPSMC_MSG_GetEnabledSmuFeaturesLow,     1),
+       MSG_MAP(GetEnabledSmuFeaturesHigh,      PPSMC_MSG_GetEnabledSmuFeaturesHigh,    1),
+       MSG_MAP(SetWorkloadMask,                PPSMC_MSG_SetWorkloadMask,              1),
+       MSG_MAP(SetPptLimit,                    PPSMC_MSG_SetPptLimit,                  0),
+       MSG_MAP(SetDriverDramAddrHigh,          PPSMC_MSG_SetDriverDramAddrHigh,        0),
+       MSG_MAP(SetDriverDramAddrLow,           PPSMC_MSG_SetDriverDramAddrLow,         0),
+       MSG_MAP(SetToolsDramAddrHigh,           PPSMC_MSG_SetToolsDramAddrHigh,         0),
+       MSG_MAP(SetToolsDramAddrLow,            PPSMC_MSG_SetToolsDramAddrLow,          0),
+       MSG_MAP(TransferTableSmu2Dram,          PPSMC_MSG_TransferTableSmu2Dram,        0),
+       MSG_MAP(TransferTableDram2Smu,          PPSMC_MSG_TransferTableDram2Smu,        0),
+       MSG_MAP(UseDefaultPPTable,              PPSMC_MSG_UseDefaultPPTable,            0),
+       MSG_MAP(UseBackupPPTable,               PPSMC_MSG_UseBackupPPTable,             0),
+       MSG_MAP(RunBtc,                         PPSMC_MSG_RunBtc,                       0),
+       MSG_MAP(EnterBaco,                      PPSMC_MSG_EnterBaco,                    0),
+       MSG_MAP(SetSoftMinByFreq,               PPSMC_MSG_SetSoftMinByFreq,             0),
+       MSG_MAP(SetSoftMaxByFreq,               PPSMC_MSG_SetSoftMaxByFreq,             0),
+       MSG_MAP(SetHardMinByFreq,               PPSMC_MSG_SetHardMinByFreq,             1),
+       MSG_MAP(SetHardMaxByFreq,               PPSMC_MSG_SetHardMaxByFreq,             0),
+       MSG_MAP(GetMinDpmFreq,                  PPSMC_MSG_GetMinDpmFreq,                1),
+       MSG_MAP(GetMaxDpmFreq,                  PPSMC_MSG_GetMaxDpmFreq,                1),
+       MSG_MAP(GetDpmFreqByIndex,              PPSMC_MSG_GetDpmFreqByIndex,            1),
+       MSG_MAP(SetMemoryChannelConfig,         PPSMC_MSG_SetMemoryChannelConfig,       0),
+       MSG_MAP(SetGeminiMode,                  PPSMC_MSG_SetGeminiMode,                0),
+       MSG_MAP(SetGeminiApertureHigh,          PPSMC_MSG_SetGeminiApertureHigh,        0),
+       MSG_MAP(SetGeminiApertureLow,           PPSMC_MSG_SetGeminiApertureLow,         0),
+       MSG_MAP(OverridePcieParameters,         PPSMC_MSG_OverridePcieParameters,       0),
+       MSG_MAP(SetMinDeepSleepDcefclk,         PPSMC_MSG_SetMinDeepSleepDcefclk,       0),
+       MSG_MAP(ReenableAcDcInterrupt,          PPSMC_MSG_ReenableAcDcInterrupt,        0),
+       MSG_MAP(NotifyPowerSource,              PPSMC_MSG_NotifyPowerSource,            0),
+       MSG_MAP(SetUclkFastSwitch,              PPSMC_MSG_SetUclkFastSwitch,            0),
+       MSG_MAP(SetVideoFps,                    PPSMC_MSG_SetVideoFps,                  0),
+       MSG_MAP(PrepareMp1ForUnload,            PPSMC_MSG_PrepareMp1ForUnload,          1),
+       MSG_MAP(DramLogSetDramAddrHigh,         PPSMC_MSG_DramLogSetDramAddrHigh,       0),
+       MSG_MAP(DramLogSetDramAddrLow,          PPSMC_MSG_DramLogSetDramAddrLow,        0),
+       MSG_MAP(DramLogSetDramSize,             PPSMC_MSG_DramLogSetDramSize,           0),
+       MSG_MAP(ConfigureGfxDidt,               PPSMC_MSG_ConfigureGfxDidt,             0),
+       MSG_MAP(NumOfDisplays,                  PPSMC_MSG_NumOfDisplays,                0),
+       MSG_MAP(SetSystemVirtualDramAddrHigh,   PPSMC_MSG_SetSystemVirtualDramAddrHigh, 0),
+       MSG_MAP(SetSystemVirtualDramAddrLow,    PPSMC_MSG_SetSystemVirtualDramAddrLow,  0),
+       MSG_MAP(AllowGfxOff,                    PPSMC_MSG_AllowGfxOff,                  0),
+       MSG_MAP(DisallowGfxOff,                 PPSMC_MSG_DisallowGfxOff,               0),
+       MSG_MAP(GetPptLimit,                    PPSMC_MSG_GetPptLimit,                  0),
+       MSG_MAP(GetDcModeMaxDpmFreq,            PPSMC_MSG_GetDcModeMaxDpmFreq,          1),
+       MSG_MAP(GetDebugData,                   PPSMC_MSG_GetDebugData,                 0),
+       MSG_MAP(ExitBaco,                       PPSMC_MSG_ExitBaco,                     0),
+       MSG_MAP(PrepareMp1ForReset,             PPSMC_MSG_PrepareMp1ForReset,           0),
+       MSG_MAP(PrepareMp1ForShutdown,          PPSMC_MSG_PrepareMp1ForShutdown,        0),
+       MSG_MAP(PowerUpVcn,                     PPSMC_MSG_PowerUpVcn,                   0),
+       MSG_MAP(PowerDownVcn,                   PPSMC_MSG_PowerDownVcn,                 0),
+       MSG_MAP(PowerUpJpeg,                    PPSMC_MSG_PowerUpJpeg,                  0),
+       MSG_MAP(PowerDownJpeg,                  PPSMC_MSG_PowerDownJpeg,                0),
+       MSG_MAP(BacoAudioD3PME,                 PPSMC_MSG_BacoAudioD3PME,               0),
+       MSG_MAP(ArmD3,                          PPSMC_MSG_ArmD3,                        0),
+       MSG_MAP(DAL_DISABLE_DUMMY_PSTATE_CHANGE,PPSMC_MSG_DALDisableDummyPstateChange,  0),
+       MSG_MAP(DAL_ENABLE_DUMMY_PSTATE_CHANGE, PPSMC_MSG_DALEnableDummyPstateChange,   0),
+       MSG_MAP(GetVoltageByDpm,                PPSMC_MSG_GetVoltageByDpm,              0),
+       MSG_MAP(GetVoltageByDpmOverdrive,       PPSMC_MSG_GetVoltageByDpmOverdrive,     0),
 };
 
-static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = {
+static struct cmn2asic_mapping navi10_clk_map[SMU_CLK_COUNT] = {
        CLK_MAP(GFXCLK, PPCLK_GFXCLK),
        CLK_MAP(SCLK,   PPCLK_GFXCLK),
        CLK_MAP(SOCCLK, PPCLK_SOCCLK),
@@ -140,7 +155,7 @@ static struct smu_11_0_cmn2aisc_mapping navi10_clk_map[SMU_CLK_COUNT] = {
        CLK_MAP(PHYCLK, PPCLK_PHYCLK),
 };
 
-static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = {
+static struct cmn2asic_mapping navi10_feature_mask_map[SMU_FEATURE_COUNT] = {
        FEA_MAP(DPM_PREFETCHER),
        FEA_MAP(DPM_GFXCLK),
        FEA_MAP(DPM_GFX_PACE),
@@ -186,7 +201,7 @@ static struct smu_11_0_cmn2aisc_mapping navi10_feature_mask_map[SMU_FEATURE_COUN
        FEA_MAP(APCC_DFLL),
 };
 
-static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = {
+static struct cmn2asic_mapping navi10_table_map[SMU_TABLE_COUNT] = {
        TAB_MAP(PPTABLE),
        TAB_MAP(WATERMARKS),
        TAB_MAP(AVFS),
@@ -201,12 +216,12 @@ static struct smu_11_0_cmn2aisc_mapping navi10_table_map[SMU_TABLE_COUNT] = {
        TAB_MAP(PACE),
 };
 
-static struct smu_11_0_cmn2aisc_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
+static struct cmn2asic_mapping navi10_pwr_src_map[SMU_POWER_SOURCE_COUNT] = {
        PWR_MAP(AC),
        PWR_MAP(DC),
 };
 
-static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
+static struct cmn2asic_mapping navi10_workload_map[PP_SMC_POWER_PROFILE_COUNT] = {
        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_BOOTUP_DEFAULT,       WORKLOAD_PPLIB_DEFAULT_BIT),
        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_FULLSCREEN3D,         WORKLOAD_PPLIB_FULL_SCREEN_3D_BIT),
        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_POWERSAVING,          WORKLOAD_PPLIB_POWER_SAVING_BIT),
@@ -216,97 +231,6 @@ static struct smu_11_0_cmn2aisc_mapping navi10_workload_map[PP_SMC_POWER_PROFILE
        WORKLOAD_MAP(PP_SMC_POWER_PROFILE_CUSTOM,               WORKLOAD_PPLIB_CUSTOM_BIT),
 };
 
-static int navi10_get_smu_msg_index(struct smu_context *smc, uint32_t index)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (index >= SMU_MSG_MAX_COUNT)
-               return -EINVAL;
-
-       mapping = navi10_message_map[index];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
-static int navi10_get_smu_clk_index(struct smu_context *smc, uint32_t index)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (index >= SMU_CLK_COUNT)
-               return -EINVAL;
-
-       mapping = navi10_clk_map[index];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
-static int navi10_get_smu_feature_index(struct smu_context *smc, uint32_t index)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (index >= SMU_FEATURE_COUNT)
-               return -EINVAL;
-
-       mapping = navi10_feature_mask_map[index];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
-static int navi10_get_smu_table_index(struct smu_context *smc, uint32_t index)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (index >= SMU_TABLE_COUNT)
-               return -EINVAL;
-
-       mapping = navi10_table_map[index];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
-static int navi10_get_pwr_src_index(struct smu_context *smc, uint32_t index)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (index >= SMU_POWER_SOURCE_COUNT)
-               return -EINVAL;
-
-       mapping = navi10_pwr_src_map[index];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
-
-static int navi10_get_workload_type(struct smu_context *smu, enum PP_SMC_POWER_PROFILE profile)
-{
-       struct smu_11_0_cmn2aisc_mapping mapping;
-
-       if (profile > PP_SMC_POWER_PROFILE_CUSTOM)
-               return -EINVAL;
-
-       mapping = navi10_workload_map[profile];
-       if (!(mapping.valid_mapping)) {
-               return -EINVAL;
-       }
-
-       return mapping.map_to;
-}
-
 static bool is_asic_secure(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
@@ -414,6 +338,29 @@ navi10_get_allowed_feature_mask(struct smu_context *smu,
 
 static int navi10_check_powerplay_table(struct smu_context *smu)
 {
+       struct smu_table_context *table_context = &smu->smu_table;
+       struct smu_11_0_powerplay_table *powerplay_table =
+               table_context->power_play_table;
+       struct smu_baco_context *smu_baco = &smu->smu_baco;
+
+       if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC)
+               smu->dc_controlled_by_gpio = true;
+
+       mutex_lock(&smu_baco->mutex);
+       if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO ||
+           powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO)
+               smu_baco->platform_support = true;
+       mutex_unlock(&smu_baco->mutex);
+
+       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;
+
        return 0;
 }
 
@@ -429,17 +376,17 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
        index = get_index_into_master_table(atom_master_list_of_data_tables_v2_1,
                                           smc_dpm_info);
 
-       ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL,
+       ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL,
                                      (uint8_t **)&smc_dpm_table);
        if (ret)
                return ret;
 
-       pr_info("smc_dpm_info table revision(format.content): %d.%d\n",
+       dev_info(adev->dev, "smc_dpm_info table revision(format.content): %d.%d\n",
                        smc_dpm_table->table_header.format_revision,
                        smc_dpm_table->table_header.content_revision);
 
        if (smc_dpm_table->table_header.format_revision != 4) {
-               pr_err("smc_dpm_info table format revision is not 4!\n");
+               dev_err(adev->dev, "smc_dpm_info table format revision is not 4!\n");
                return -EINVAL;
        }
 
@@ -449,7 +396,7 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
                        sizeof(*smc_dpm_table) - sizeof(smc_dpm_table->table_header));
                break;
        case 7: /* nv12 */
-               ret = smu_get_atom_data_table(smu, index, NULL, NULL, NULL,
+               ret = amdgpu_atombios_get_data_table(adev, index, NULL, NULL, NULL,
                                              (uint8_t **)&smc_dpm_table_v4_7);
                if (ret)
                        return ret;
@@ -457,7 +404,7 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
                        sizeof(*smc_dpm_table_v4_7) - sizeof(smc_dpm_table_v4_7->table_header));
                break;
        default:
-               pr_err("smc_dpm_info with unsupported content revision %d!\n",
+               dev_err(smu->adev->dev, "smc_dpm_info with unsupported content revision %d!\n",
                                smc_dpm_table->table_header.content_revision);
                return -EINVAL;
        }
@@ -472,41 +419,56 @@ static int navi10_append_powerplay_table(struct smu_context *smu)
 
 static int navi10_store_powerplay_table(struct smu_context *smu)
 {
-       struct smu_11_0_powerplay_table *powerplay_table = NULL;
        struct smu_table_context *table_context = &smu->smu_table;
-       struct smu_baco_context *smu_baco = &smu->smu_baco;
-
-       if (!table_context->power_play_table)
-               return -EINVAL;
-
-       powerplay_table = table_context->power_play_table;
+       struct smu_11_0_powerplay_table *powerplay_table =
+               table_context->power_play_table;
 
        memcpy(table_context->driver_pptable, &powerplay_table->smc_pptable,
               sizeof(PPTable_t));
 
-       table_context->thermal_controller_type = powerplay_table->thermal_controller_type;
+       return 0;
+}
+
+static int navi10_setup_pptable(struct smu_context *smu)
+{
+       int ret = 0;
 
-       if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_HARDWAREDC)
-               smu->dc_controlled_by_gpio = true;
+       ret = smu_v11_0_setup_pptable(smu);
+       if (ret)
+               return ret;
 
-       mutex_lock(&smu_baco->mutex);
-       if (powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_BACO ||
-           powerplay_table->platform_caps & SMU_11_0_PP_PLATFORM_CAP_MACO)
-               smu_baco->platform_support = true;
-       mutex_unlock(&smu_baco->mutex);
+       ret = navi10_store_powerplay_table(smu);
+       if (ret)
+               return ret;
 
-       return 0;
+       ret = navi10_append_powerplay_table(smu);
+       if (ret)
+               return ret;
+
+       ret = navi10_check_powerplay_table(smu);
+       if (ret)
+               return ret;
+
+       return ret;
 }
 
-static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables)
+static int navi10_tables_init(struct smu_context *smu)
 {
        struct smu_table_context *smu_table = &smu->smu_table;
+       struct smu_table *tables = smu_table->tables;
+       struct amdgpu_device *adev = smu->adev;
 
        SMU_TABLE_INIT(tables, SMU_TABLE_PPTABLE, sizeof(PPTable_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_WATERMARKS, sizeof(Watermarks_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
-       SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
+       if (adev->asic_type == CHIP_NAVI12)
+               SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_NV12_t),
+                              PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+       else
+               SMU_TABLE_INIT(tables, SMU_TABLE_SMU_METRICS, sizeof(SmuMetrics_t),
+                              PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
+       SMU_TABLE_INIT(tables, SMU_TABLE_I2C_COMMANDS, sizeof(SwI2cRequest_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
        SMU_TABLE_INIT(tables, SMU_TABLE_OVERDRIVE, sizeof(OverDriveTable_t),
                       PAGE_SIZE, AMDGPU_GEM_DOMAIN_VRAM);
@@ -516,37 +478,151 @@ static int navi10_tables_init(struct smu_context *smu, struct smu_table *tables)
                       sizeof(DpmActivityMonitorCoeffInt_t), PAGE_SIZE,
                       AMDGPU_GEM_DOMAIN_VRAM);
 
-       smu_table->metrics_table = kzalloc(sizeof(SmuMetrics_t), GFP_KERNEL);
+       smu_table->metrics_table = kzalloc(adev->asic_type == CHIP_NAVI12 ?
+                                          sizeof(SmuMetrics_NV12_t) :
+                                          sizeof(SmuMetrics_t), GFP_KERNEL);
        if (!smu_table->metrics_table)
-               return -ENOMEM;
+               goto err0_out;
        smu_table->metrics_time = 0;
 
+       smu_table->gpu_metrics_table_size = sizeof(struct gpu_metrics_v1_0);
+       smu_table->gpu_metrics_table = kzalloc(smu_table->gpu_metrics_table_size, GFP_KERNEL);
+       if (!smu_table->gpu_metrics_table)
+               goto err1_out;
+
        smu_table->watermarks_table = kzalloc(sizeof(Watermarks_t), GFP_KERNEL);
        if (!smu_table->watermarks_table)
-               return -ENOMEM;
+               goto err2_out;
 
        return 0;
+
+err2_out:
+       kfree(smu_table->gpu_metrics_table);
+err1_out:
+       kfree(smu_table->metrics_table);
+err0_out:
+       return -ENOMEM;
 }
 
-static int navi10_get_metrics_table(struct smu_context *smu,
-                                   SmuMetrics_t *metrics_table)
+static int navi10_get_metrics_table_locked(struct smu_context *smu,
+                                          SmuMetrics_t *metrics_table,
+                                          bool bypass_cache)
 {
        struct smu_table_context *smu_table= &smu->smu_table;
        int ret = 0;
 
-       mutex_lock(&smu->metrics_lock);
-       if (!smu_table->metrics_time || time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(100))) {
-               ret = smu_update_table(smu, SMU_TABLE_SMU_METRICS, 0,
-                               (void *)smu_table->metrics_table, false);
+       if (bypass_cache ||
+           !smu_table->metrics_time ||
+           time_after(jiffies, smu_table->metrics_time + msecs_to_jiffies(1))) {
+               ret = smu_cmn_update_table(smu,
+                                      SMU_TABLE_SMU_METRICS,
+                                      0,
+                                      smu_table->metrics_table,
+                                      false);
                if (ret) {
-                       pr_info("Failed to export SMU metrics table!\n");
-                       mutex_unlock(&smu->metrics_lock);
+                       dev_info(smu->adev->dev, "Failed to export SMU metrics table!\n");
                        return ret;
                }
                smu_table->metrics_time = jiffies;
        }
 
-       memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
+       if (metrics_table)
+               memcpy(metrics_table, smu_table->metrics_table, sizeof(SmuMetrics_t));
+
+       return 0;
+}
+
+static int navi10_get_smu_metrics_data(struct smu_context *smu,
+                                      MetricsMember_t member,
+                                      uint32_t *value)
+{
+       struct smu_table_context *smu_table= &smu->smu_table;
+       /*
+        * This works for NV12 also. As although NV12 uses a different
+        * SmuMetrics structure from other NV1X ASICs, they share the
+        * same offsets for the heading parts(those members used here).
+        */
+       SmuMetrics_t *metrics = (SmuMetrics_t *)smu_table->metrics_table;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = navi10_get_metrics_table_locked(smu,
+                                             NULL,
+                                             false);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       switch (member) {
+       case METRICS_CURR_GFXCLK:
+               *value = metrics->CurrClock[PPCLK_GFXCLK];
+               break;
+       case METRICS_CURR_SOCCLK:
+               *value = metrics->CurrClock[PPCLK_SOCCLK];
+               break;
+       case METRICS_CURR_UCLK:
+               *value = metrics->CurrClock[PPCLK_UCLK];
+               break;
+       case METRICS_CURR_VCLK:
+               *value = metrics->CurrClock[PPCLK_VCLK];
+               break;
+       case METRICS_CURR_DCLK:
+               *value = metrics->CurrClock[PPCLK_DCLK];
+               break;
+       case METRICS_CURR_DCEFCLK:
+               *value = metrics->CurrClock[PPCLK_DCEFCLK];
+               break;
+       case METRICS_AVERAGE_GFXCLK:
+               *value = metrics->AverageGfxclkFrequency;
+               break;
+       case METRICS_AVERAGE_SOCCLK:
+               *value = metrics->AverageSocclkFrequency;
+               break;
+       case METRICS_AVERAGE_UCLK:
+               *value = metrics->AverageUclkFrequency;
+               break;
+       case METRICS_AVERAGE_GFXACTIVITY:
+               *value = metrics->AverageGfxActivity;
+               break;
+       case METRICS_AVERAGE_MEMACTIVITY:
+               *value = metrics->AverageUclkActivity;
+               break;
+       case METRICS_AVERAGE_SOCKETPOWER:
+               *value = metrics->AverageSocketPower << 8;
+               break;
+       case METRICS_TEMPERATURE_EDGE:
+               *value = metrics->TemperatureEdge *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_HOTSPOT:
+               *value = metrics->TemperatureHotspot *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_MEM:
+               *value = metrics->TemperatureMem *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRGFX:
+               *value = metrics->TemperatureVrGfx *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_TEMPERATURE_VRSOC:
+               *value = metrics->TemperatureVrSoc *
+                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               break;
+       case METRICS_THROTTLER_STATUS:
+               *value = metrics->ThrottlerStatus;
+               break;
+       case METRICS_CURR_FANSPEED:
+               *value = metrics->CurrFanSpeed;
+               break;
+       default:
+               *value = UINT_MAX;
+               break;
+       }
+
        mutex_unlock(&smu->metrics_lock);
 
        return ret;
@@ -556,9 +632,6 @@ static int navi10_allocate_dpm_context(struct smu_context *smu)
 {
        struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
 
-       if (smu_dpm->dpm_context)
-               return -EINVAL;
-
        smu_dpm->dpm_context = kzalloc(sizeof(struct smu_11_0_dpm_context),
                                       GFP_KERNEL);
        if (!smu_dpm->dpm_context)
@@ -569,72 +642,210 @@ static int navi10_allocate_dpm_context(struct smu_context *smu)
        return 0;
 }
 
-static int navi10_set_default_dpm_table(struct smu_context *smu)
+static int navi10_init_smc_tables(struct smu_context *smu)
 {
-       struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
-       struct smu_table_context *table_context = &smu->smu_table;
-       struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
-       PPTable_t *driver_ppt = NULL;
-       int i;
+       int ret = 0;
 
-       driver_ppt = table_context->driver_pptable;
+       ret = navi10_tables_init(smu);
+       if (ret)
+               return ret;
+
+       ret = navi10_allocate_dpm_context(smu);
+       if (ret)
+               return ret;
+
+       return smu_v11_0_init_smc_tables(smu);
+}
 
-       dpm_context->dpm_tables.soc_table.min = driver_ppt->FreqTableSocclk[0];
-       dpm_context->dpm_tables.soc_table.max = driver_ppt->FreqTableSocclk[NUM_SOCCLK_DPM_LEVELS - 1];
+static int navi10_set_default_dpm_table(struct smu_context *smu)
+{
+       struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
+       PPTable_t *driver_ppt = smu->smu_table.driver_pptable;
+       struct smu_11_0_dpm_table *dpm_table;
+       int ret = 0;
 
-       dpm_context->dpm_tables.gfx_table.min = driver_ppt->FreqTableGfx[0];
-       dpm_context->dpm_tables.gfx_table.max = driver_ppt->FreqTableGfx[NUM_GFXCLK_DPM_LEVELS - 1];
+       /* socclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.soc_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_SOCCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_SOCCLK].SnapToDiscrete;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.socclk / 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;
+       }
 
-       dpm_context->dpm_tables.uclk_table.min = driver_ppt->FreqTableUclk[0];
-       dpm_context->dpm_tables.uclk_table.max = driver_ppt->FreqTableUclk[NUM_UCLK_DPM_LEVELS - 1];
+       /* gfxclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.gfx_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_GFXCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_GFXCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_GFXCLK].SnapToDiscrete;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.gfxclk / 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;
+       }
 
-       dpm_context->dpm_tables.vclk_table.min = driver_ppt->FreqTableVclk[0];
-       dpm_context->dpm_tables.vclk_table.max = driver_ppt->FreqTableVclk[NUM_VCLK_DPM_LEVELS - 1];
+       /* uclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.uclk_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_UCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_UCLK].SnapToDiscrete;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.uclk / 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;
+       }
 
-       dpm_context->dpm_tables.dclk_table.min = driver_ppt->FreqTableDclk[0];
-       dpm_context->dpm_tables.dclk_table.max = driver_ppt->FreqTableDclk[NUM_DCLK_DPM_LEVELS - 1];
+       /* vclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.vclk_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_VCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_VCLK].SnapToDiscrete;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.vclk / 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;
+       }
 
-       dpm_context->dpm_tables.dcef_table.min = driver_ppt->FreqTableDcefclk[0];
-       dpm_context->dpm_tables.dcef_table.max = driver_ppt->FreqTableDcefclk[NUM_DCEFCLK_DPM_LEVELS - 1];
+       /* dclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.dclk_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_DCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_DCLK].SnapToDiscrete;
+       } else {
+               dpm_table->count = 1;
+               dpm_table->dpm_levels[0].value = smu->smu_table.boot_values.dclk / 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;
+       }
 
-       dpm_context->dpm_tables.pixel_table.min = driver_ppt->FreqTablePixclk[0];
-       dpm_context->dpm_tables.pixel_table.max = driver_ppt->FreqTablePixclk[NUM_PIXCLK_DPM_LEVELS - 1];
+       /* dcefclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.dcef_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_DCEFCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_DCEFCLK].SnapToDiscrete;
+       } 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;
+       }
 
-       dpm_context->dpm_tables.display_table.min = driver_ppt->FreqTableDispclk[0];
-       dpm_context->dpm_tables.display_table.max = driver_ppt->FreqTableDispclk[NUM_DISPCLK_DPM_LEVELS - 1];
+       /* pixelclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.pixel_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_PIXCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_PIXCLK].SnapToDiscrete;
+       } 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;
+       }
 
-       dpm_context->dpm_tables.phy_table.min = driver_ppt->FreqTablePhyclk[0];
-       dpm_context->dpm_tables.phy_table.max = driver_ppt->FreqTablePhyclk[NUM_PHYCLK_DPM_LEVELS - 1];
+       /* displayclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.display_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_DISPCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_DISPCLK].SnapToDiscrete;
+       } 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;
+       }
 
-       for (i = 0; i < MAX_PCIE_CONF; i++) {
-               dpm_context->dpm_tables.pcie_table.pcie_gen[i] = driver_ppt->PcieGenSpeed[i];
-               dpm_context->dpm_tables.pcie_table.pcie_lane[i] = driver_ppt->PcieLaneCount[i];
+       /* phyclk dpm table setup */
+       dpm_table = &dpm_context->dpm_tables.phy_table;
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+               ret = smu_v11_0_set_single_dpm_table(smu,
+                                                    SMU_PHYCLK,
+                                                    dpm_table);
+               if (ret)
+                       return ret;
+               dpm_table->is_fine_grained =
+                       !driver_ppt->DpmDescriptor[PPCLK_PHYCLK].SnapToDiscrete;
+       } 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;
 }
 
-static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
+static int navi10_dpm_set_vcn_enable(struct smu_context *smu, bool enable)
 {
-       struct smu_power_context *smu_power = &smu->smu_power;
-       struct smu_power_gate *power_gate = &smu_power->power_gate;
        int ret = 0;
 
        if (enable) {
                /* vcn dpm on is a prerequisite for vcn power gate messages */
-               if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
-                       ret = smu_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1, NULL);
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
+                       ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_PowerUpVcn, 1, NULL);
                        if (ret)
                                return ret;
                }
-               power_gate->vcn_gated = false;
        } else {
-               if (smu_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
-                       ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL);
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_VCN_PG_BIT)) {
+                       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownVcn, NULL);
                        if (ret)
                                return ret;
                }
-               power_gate->vcn_gated = true;
        }
 
        return ret;
@@ -642,24 +853,20 @@ static int navi10_dpm_set_uvd_enable(struct smu_context *smu, bool enable)
 
 static int navi10_dpm_set_jpeg_enable(struct smu_context *smu, bool enable)
 {
-       struct smu_power_context *smu_power = &smu->smu_power;
-       struct smu_power_gate *power_gate = &smu_power->power_gate;
        int ret = 0;
 
        if (enable) {
-               if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
-                       ret = smu_send_smc_msg(smu, SMU_MSG_PowerUpJpeg, NULL);
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
+                       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerUpJpeg, NULL);
                        if (ret)
                                return ret;
                }
-               power_gate->jpeg_gated = false;
        } else {
-               if (smu_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
-                       ret = smu_send_smc_msg(smu, SMU_MSG_PowerDownJpeg, NULL);
+               if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_JPEG_PG_BIT)) {
+                       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_PowerDownJpeg, NULL);
                        if (ret)
                                return ret;
                }
-               power_gate->jpeg_gated = true;
        }
 
        return ret;
@@ -669,20 +876,41 @@ static int navi10_get_current_clk_freq_by_table(struct smu_context *smu,
                                       enum smu_clk_type clk_type,
                                       uint32_t *value)
 {
-       int ret = 0, clk_id = 0;
-       SmuMetrics_t metrics;
-
-       ret = navi10_get_metrics_table(smu, &metrics);
-       if (ret)
-               return ret;
+       MetricsMember_t member_type;
+       int clk_id = 0;
 
-       clk_id = smu_clk_get_index(smu, clk_type);
+       clk_id = smu_cmn_to_asic_specific_index(smu,
+                                               CMN2ASIC_MAPPING_CLK,
+                                               clk_type);
        if (clk_id < 0)
                return clk_id;
 
-       *value = metrics.CurrClock[clk_id];
+       switch (clk_id) {
+       case PPCLK_GFXCLK:
+               member_type = METRICS_CURR_GFXCLK;
+               break;
+       case PPCLK_UCLK:
+               member_type = METRICS_CURR_UCLK;
+               break;
+       case PPCLK_SOCCLK:
+               member_type = METRICS_CURR_SOCCLK;
+               break;
+       case PPCLK_VCLK:
+               member_type = METRICS_CURR_VCLK;
+               break;
+       case PPCLK_DCLK:
+               member_type = METRICS_CURR_DCLK;
+               break;
+       case PPCLK_DCEFCLK:
+               member_type = METRICS_CURR_DCEFCLK;
+               break;
+       default:
+               return -EINVAL;
+       }
 
-       return ret;
+       return navi10_get_smu_metrics_data(smu,
+                                          member_type,
+                                          value);
 }
 
 static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu_clk_type clk_type)
@@ -691,7 +919,9 @@ static bool navi10_is_support_fine_grained_dpm(struct smu_context *smu, enum smu
        DpmDescriptor_t *dpm_desc = NULL;
        uint32_t clk_index = 0;
 
-       clk_index = smu_clk_get_index(smu, clk_type);
+       clk_index = smu_cmn_to_asic_specific_index(smu,
+                                                  CMN2ASIC_MAPPING_CLK,
+                                                  clk_type);
        dpm_desc = &pptable->DpmDescriptor[clk_index];
 
        /* 0 - Fine grained DPM, 1 - Discrete DPM */
@@ -725,7 +955,6 @@ static int navi10_print_clk_levels(struct smu_context *smu,
        uint32_t gen_speed, lane_width;
        struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
        struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
-       struct amdgpu_device *adev = smu->adev;
        PPTable_t *pptable = (PPTable_t *)table_context->driver_pptable;
        OverDriveTable_t *od_table =
                (OverDriveTable_t *)table_context->overdrive_table;
@@ -740,20 +969,17 @@ static int navi10_print_clk_levels(struct smu_context *smu,
        case SMU_UCLK:
        case SMU_FCLK:
        case SMU_DCEFCLK:
-               ret = smu_get_current_clk_freq(smu, clk_type, &cur_value);
+               ret = navi10_get_current_clk_freq_by_table(smu, clk_type, &cur_value);
                if (ret)
                        return size;
 
-               /* 10KHz -> MHz */
-               cur_value = cur_value / 100;
-
-               ret = smu_get_dpm_level_count(smu, clk_type, &count);
+               ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &count);
                if (ret)
                        return size;
 
                if (!navi10_is_support_fine_grained_dpm(smu, clk_type)) {
                        for (i = 0; i < count; i++) {
-                               ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &value);
+                               ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &value);
                                if (ret)
                                        return size;
 
@@ -761,10 +987,10 @@ static int navi10_print_clk_levels(struct smu_context *smu,
                                                cur_value == value ? "*" : "");
                        }
                } else {
-                       ret = smu_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]);
+                       ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, 0, &freq_values[0]);
                        if (ret)
                                return size;
-                       ret = smu_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]);
+                       ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, count - 1, &freq_values[2]);
                        if (ret)
                                return size;
 
@@ -782,12 +1008,8 @@ static int navi10_print_clk_levels(struct smu_context *smu,
                }
                break;
        case SMU_PCIE:
-               gen_speed = (RREG32_PCIE(smnPCIE_LC_SPEED_CNTL) &
-                            PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE_MASK)
-                       >> PSWUSP0_PCIE_LC_SPEED_CNTL__LC_CURRENT_DATA_RATE__SHIFT;
-               lane_width = (RREG32_PCIE(smnPCIE_LC_LINK_WIDTH_CNTL) &
-                             PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD_MASK)
-                       >> PCIE_LC_LINK_WIDTH_CNTL__LC_LINK_WIDTH_RD__SHIFT;
+               gen_speed = smu_v11_0_get_current_pcie_link_speed_level(smu);
+               lane_width = smu_v11_0_get_current_pcie_link_width_level(smu);
                for (i = 0; i < NUM_LINK_LEVELS; i++)
                        size += sprintf(buf + size, "%d: %s %s %dMhz %s\n", i,
                                        (dpm_context->dpm_tables.pcie_table.pcie_gen[i] == 0) ? "2.5GT/s," :
@@ -841,7 +1063,7 @@ static int navi10_print_clk_levels(struct smu_context *smu,
                        default:
                                break;
                        }
-                       size += sprintf(buf + size, "%d: %uMHz %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE);
+                       size += sprintf(buf + size, "%d: %uMHz %umV\n", i, curve_settings[0], curve_settings[1] / NAVI10_VOLTAGE_SCALE);
                }
                break;
        case SMU_OD_RANGE:
@@ -924,15 +1146,15 @@ static int navi10_force_clk_levels(struct smu_context *smu,
                        soft_min_level = (soft_min_level >= 1 ? 1 : 0);
                }
 
-               ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
+               ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_min_level, &min_freq);
                if (ret)
                        return size;
 
-               ret = smu_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
+               ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, soft_max_level, &max_freq);
                if (ret)
                        return size;
 
-               ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false);
+               ret = smu_v11_0_set_soft_freq_limited_range(smu, clk_type, min_freq, max_freq);
                if (ret)
                        return size;
                break;
@@ -945,46 +1167,117 @@ static int navi10_force_clk_levels(struct smu_context *smu,
 
 static int navi10_populate_umd_state_clk(struct smu_context *smu)
 {
-       int ret = 0;
-       uint32_t min_sclk_freq = 0, min_mclk_freq = 0;
-
-       ret = smu_get_dpm_freq_range(smu, SMU_SCLK, &min_sclk_freq, NULL, false);
-       if (ret)
-               return ret;
-
-       smu->pstate_sclk = min_sclk_freq * 100;
-
-       ret = smu_get_dpm_freq_range(smu, SMU_MCLK, &min_mclk_freq, NULL, false);
-       if (ret)
-               return ret;
-
-       smu->pstate_mclk = min_mclk_freq * 100;
-
-       return ret;
-}
-
-static int navi10_get_clock_by_type_with_latency(struct smu_context *smu,
-                                                enum smu_clk_type clk_type,
-                                                struct pp_clock_levels_with_latency *clocks)
-{
-       int ret = 0, i = 0;
-       uint32_t level_count = 0, freq = 0;
-
-       switch (clk_type) {
-       case SMU_GFXCLK:
-       case SMU_DCEFCLK:
-       case SMU_SOCCLK:
-       case SMU_MCLK:
-       case SMU_UCLK:
-               ret = smu_get_dpm_level_count(smu, clk_type, &level_count);
-               if (ret)
-                       return ret;
+       struct smu_11_0_dpm_context *dpm_context =
+                               smu->smu_dpm.dpm_context;
+       struct smu_11_0_dpm_table *gfx_table =
+                               &dpm_context->dpm_tables.gfx_table;
+       struct smu_11_0_dpm_table *mem_table =
+                               &dpm_context->dpm_tables.uclk_table;
+       struct smu_11_0_dpm_table *soc_table =
+                               &dpm_context->dpm_tables.soc_table;
+       struct smu_umd_pstate_table *pstate_table =
+                               &smu->pstate_table;
+       struct amdgpu_device *adev = smu->adev;
+       uint32_t sclk_freq;
 
-               level_count = min(level_count, (uint32_t)MAX_NUM_CLOCKS);
+       pstate_table->gfxclk_pstate.min = gfx_table->min;
+       switch (adev->asic_type) {
+       case CHIP_NAVI10:
+               switch (adev->pdev->revision) {
+               case 0xf0: /* XTX */
+               case 0xc0:
+                       sclk_freq = NAVI10_PEAK_SCLK_XTX;
+                       break;
+               case 0xf1: /* XT */
+               case 0xc1:
+                       sclk_freq = NAVI10_PEAK_SCLK_XT;
+                       break;
+               default: /* XL */
+                       sclk_freq = NAVI10_PEAK_SCLK_XL;
+                       break;
+               }
+               break;
+       case CHIP_NAVI14:
+               switch (adev->pdev->revision) {
+               case 0xc7: /* XT */
+               case 0xf4:
+                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK;
+                       break;
+               case 0xc1: /* XTM */
+               case 0xf2:
+                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK;
+                       break;
+               case 0xc3: /* XLM */
+               case 0xf3:
+                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
+                       break;
+               case 0xc5: /* XTX */
+               case 0xf6:
+                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
+                       break;
+               default: /* XL */
+                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK;
+                       break;
+               }
+               break;
+       case CHIP_NAVI12:
+               sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK;
+               break;
+       default:
+               sclk_freq = gfx_table->dpm_levels[gfx_table->count - 1].value;
+               break;
+       }
+       pstate_table->gfxclk_pstate.peak = sclk_freq;
+
+       pstate_table->uclk_pstate.min = mem_table->min;
+       pstate_table->uclk_pstate.peak = mem_table->max;
+
+       pstate_table->socclk_pstate.min = soc_table->min;
+       pstate_table->socclk_pstate.peak = soc_table->max;
+
+       if (gfx_table->max > NAVI10_UMD_PSTATE_PROFILING_GFXCLK &&
+           mem_table->max > NAVI10_UMD_PSTATE_PROFILING_MEMCLK &&
+           soc_table->max > NAVI10_UMD_PSTATE_PROFILING_SOCCLK) {
+               pstate_table->gfxclk_pstate.standard =
+                       NAVI10_UMD_PSTATE_PROFILING_GFXCLK;
+               pstate_table->uclk_pstate.standard =
+                       NAVI10_UMD_PSTATE_PROFILING_MEMCLK;
+               pstate_table->socclk_pstate.standard =
+                       NAVI10_UMD_PSTATE_PROFILING_SOCCLK;
+       } else {
+               pstate_table->gfxclk_pstate.standard =
+                       pstate_table->gfxclk_pstate.min;
+               pstate_table->uclk_pstate.standard =
+                       pstate_table->uclk_pstate.min;
+               pstate_table->socclk_pstate.standard =
+                       pstate_table->socclk_pstate.min;
+       }
+
+       return 0;
+}
+
+static int navi10_get_clock_by_type_with_latency(struct smu_context *smu,
+                                                enum smu_clk_type clk_type,
+                                                struct pp_clock_levels_with_latency *clocks)
+{
+       int ret = 0, i = 0;
+       uint32_t level_count = 0, freq = 0;
+
+       switch (clk_type) {
+       case SMU_GFXCLK:
+       case SMU_DCEFCLK:
+       case SMU_SOCCLK:
+       case SMU_MCLK:
+       case SMU_UCLK:
+               ret = smu_v11_0_get_dpm_level_count(smu, clk_type, &level_count);
+               if (ret)
+                       return ret;
+
+               level_count = min(level_count, (uint32_t)MAX_NUM_CLOCKS);
                clocks->num_levels = level_count;
 
                for (i = 0; i < level_count; i++) {
-                       ret = smu_get_dpm_freq_by_index(smu, clk_type, i, &freq);
+                       ret = smu_v11_0_get_dpm_freq_by_index(smu, clk_type, i, &freq);
                        if (ret)
                                return ret;
 
@@ -1004,15 +1297,15 @@ static int navi10_pre_display_config_changed(struct smu_context *smu)
        int ret = 0;
        uint32_t max_freq = 0;
 
-       ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL);
+       ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays, 0, NULL);
        if (ret)
                return ret;
 
-       if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
-               ret = smu_get_dpm_freq_range(smu, SMU_UCLK, NULL, &max_freq, false);
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
+               ret = smu_v11_0_get_dpm_ultimate_freq(smu, SMU_UCLK, NULL, &max_freq);
                if (ret)
                        return ret;
-               ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, max_freq);
+               ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, max_freq);
                if (ret)
                        return ret;
        }
@@ -1025,9 +1318,9 @@ static int navi10_display_config_changed(struct smu_context *smu)
        int ret = 0;
 
        if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
-           smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
-           smu_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
-               ret = smu_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays,
+           smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT) &&
+           smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_SOCCLK_BIT)) {
+               ret = smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_NumOfDisplays,
                                                  smu->display_config->num_display,
                                                  NULL);
                if (ret)
@@ -1037,74 +1330,14 @@ static int navi10_display_config_changed(struct smu_context *smu)
        return ret;
 }
 
-static int navi10_force_dpm_limit_value(struct smu_context *smu, bool highest)
-{
-       int ret = 0, i = 0;
-       uint32_t min_freq, max_freq, force_freq;
-       enum smu_clk_type clk_type;
-
-       enum smu_clk_type clks[] = {
-               SMU_GFXCLK,
-               SMU_MCLK,
-               SMU_SOCCLK,
-       };
-
-       for (i = 0; i < ARRAY_SIZE(clks); i++) {
-               clk_type = clks[i];
-               ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
-               if (ret)
-                       return ret;
-
-               force_freq = highest ? max_freq : min_freq;
-               ret = smu_set_soft_freq_range(smu, clk_type, force_freq, force_freq, false);
-               if (ret)
-                       return ret;
-       }
-
-       return ret;
-}
-
-static int navi10_unforce_dpm_levels(struct smu_context *smu)
-{
-       int ret = 0, i = 0;
-       uint32_t min_freq, max_freq;
-       enum smu_clk_type clk_type;
-
-       enum smu_clk_type clks[] = {
-               SMU_GFXCLK,
-               SMU_MCLK,
-               SMU_SOCCLK,
-       };
-
-       for (i = 0; i < ARRAY_SIZE(clks); i++) {
-               clk_type = clks[i];
-               ret = smu_get_dpm_freq_range(smu, clk_type, &min_freq, &max_freq, false);
-               if (ret)
-                       return ret;
-
-               ret = smu_set_soft_freq_range(smu, clk_type, min_freq, max_freq, false);
-               if (ret)
-                       return ret;
-       }
-
-       return ret;
-}
-
 static int navi10_get_gpu_power(struct smu_context *smu, uint32_t *value)
 {
-       int ret = 0;
-       SmuMetrics_t metrics;
-
        if (!value)
                return -EINVAL;
 
-       ret = navi10_get_metrics_table(smu, &metrics);
-       if (ret)
-               return ret;
-
-       *value = metrics.AverageSocketPower << 8;
-
-       return 0;
+       return navi10_get_smu_metrics_data(smu,
+                                          METRICS_AVERAGE_SOCKETPOWER,
+                                          value);
 }
 
 static int navi10_get_current_activity_percent(struct smu_context *smu,
@@ -1112,28 +1345,27 @@ static int navi10_get_current_activity_percent(struct smu_context *smu,
                                               uint32_t *value)
 {
        int ret = 0;
-       SmuMetrics_t metrics;
 
        if (!value)
                return -EINVAL;
 
-       ret = navi10_get_metrics_table(smu, &metrics);
-       if (ret)
-               return ret;
-
        switch (sensor) {
        case AMDGPU_PP_SENSOR_GPU_LOAD:
-               *value = metrics.AverageGfxActivity;
+               ret = navi10_get_smu_metrics_data(smu,
+                                                 METRICS_AVERAGE_GFXACTIVITY,
+                                                 value);
                break;
        case AMDGPU_PP_SENSOR_MEM_LOAD:
-               *value = metrics.AverageUclkActivity;
+               ret = navi10_get_smu_metrics_data(smu,
+                                                 METRICS_AVERAGE_MEMACTIVITY,
+                                                 value);
                break;
        default:
-               pr_err("Invalid sensor for retrieving clock activity\n");
+               dev_err(smu->adev->dev, "Invalid sensor for retrieving clock activity\n");
                return -EINVAL;
        }
 
-       return 0;
+       return ret;
 }
 
 static bool navi10_is_dpm_running(struct smu_context *smu)
@@ -1141,7 +1373,7 @@ static bool navi10_is_dpm_running(struct smu_context *smu)
        int ret = 0;
        uint32_t feature_mask[2];
        unsigned long feature_enabled;
-       ret = smu_feature_get_enabled_mask(smu, feature_mask, 2);
+       ret = smu_cmn_get_enabled_mask(smu, feature_mask, 2);
        feature_enabled = (unsigned long)((uint64_t)feature_mask[0] |
                           ((uint64_t)feature_mask[1] << 32));
        return !!(feature_enabled & SMC_DPM_FEATURE);
@@ -1150,19 +1382,12 @@ static bool navi10_is_dpm_running(struct smu_context *smu)
 static int navi10_get_fan_speed_rpm(struct smu_context *smu,
                                    uint32_t *speed)
 {
-       SmuMetrics_t metrics;
-       int ret = 0;
-
        if (!speed)
                return -EINVAL;
 
-       ret = navi10_get_metrics_table(smu, &metrics);
-       if (ret)
-               return ret;
-
-       *speed = metrics.CurrFanSpeed;
-
-       return ret;
+       return navi10_get_smu_metrics_data(smu,
+                                          METRICS_CURR_FANSPEED,
+                                          speed);
 }
 
 static int navi10_get_fan_speed_percent(struct smu_context *smu,
@@ -1219,15 +1444,17 @@ static int navi10_get_power_profile_mode(struct smu_context *smu, char *buf)
 
        for (i = 0; i <= PP_SMC_POWER_PROFILE_CUSTOM; i++) {
                /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
-               workload_type = smu_workload_get_type(smu, i);
+               workload_type = smu_cmn_to_asic_specific_index(smu,
+                                                              CMN2ASIC_MAPPING_WORKLOAD,
+                                                              i);
                if (workload_type < 0)
                        return -EINVAL;
 
-               result = smu_update_table(smu,
+               result = smu_cmn_update_table(smu,
                                          SMU_TABLE_ACTIVITY_MONITOR_COEFF, workload_type,
                                          (void *)(&activity_monitor), false);
                if (result) {
-                       pr_err("[%s] Failed to get activity monitor!", __func__);
+                       dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
                        return result;
                }
 
@@ -1288,17 +1515,17 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
        smu->power_profile_mode = input[size];
 
        if (smu->power_profile_mode > PP_SMC_POWER_PROFILE_CUSTOM) {
-               pr_err("Invalid power profile mode %d\n", smu->power_profile_mode);
+               dev_err(smu->adev->dev, "Invalid power profile mode %d\n", smu->power_profile_mode);
                return -EINVAL;
        }
 
        if (smu->power_profile_mode == PP_SMC_POWER_PROFILE_CUSTOM) {
 
-               ret = smu_update_table(smu,
+               ret = smu_cmn_update_table(smu,
                                       SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), false);
                if (ret) {
-                       pr_err("[%s] Failed to get activity monitor!", __func__);
+                       dev_err(smu->adev->dev, "[%s] Failed to get activity monitor!", __func__);
                        return ret;
                }
 
@@ -1338,66 +1565,27 @@ static int navi10_set_power_profile_mode(struct smu_context *smu, long *input, u
                        break;
                }
 
-               ret = smu_update_table(smu,
+               ret = smu_cmn_update_table(smu,
                                       SMU_TABLE_ACTIVITY_MONITOR_COEFF, WORKLOAD_PPLIB_CUSTOM_BIT,
                                       (void *)(&activity_monitor), true);
                if (ret) {
-                       pr_err("[%s] Failed to set activity monitor!", __func__);
+                       dev_err(smu->adev->dev, "[%s] Failed to set activity monitor!", __func__);
                        return ret;
                }
        }
 
        /* conv PP_SMC_POWER_PROFILE* to WORKLOAD_PPLIB_*_BIT */
-       workload_type = smu_workload_get_type(smu, smu->power_profile_mode);
+       workload_type = smu_cmn_to_asic_specific_index(smu,
+                                                      CMN2ASIC_MAPPING_WORKLOAD,
+                                                      smu->power_profile_mode);
        if (workload_type < 0)
                return -EINVAL;
-       smu_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
+       smu_cmn_send_smc_msg_with_param(smu, SMU_MSG_SetWorkloadMask,
                                    1 << workload_type, NULL);
 
        return ret;
 }
 
-static int navi10_get_profiling_clk_mask(struct smu_context *smu,
-                                        enum amd_dpm_forced_level level,
-                                        uint32_t *sclk_mask,
-                                        uint32_t *mclk_mask,
-                                        uint32_t *soc_mask)
-{
-       int ret = 0;
-       uint32_t level_count = 0;
-
-       if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK) {
-               if (sclk_mask)
-                       *sclk_mask = 0;
-       } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK) {
-               if (mclk_mask)
-                       *mclk_mask = 0;
-       } else if (level == AMD_DPM_FORCED_LEVEL_PROFILE_PEAK) {
-               if(sclk_mask) {
-                       ret = smu_get_dpm_level_count(smu, SMU_SCLK, &level_count);
-                       if (ret)
-                               return ret;
-                       *sclk_mask = level_count - 1;
-               }
-
-               if(mclk_mask) {
-                       ret = smu_get_dpm_level_count(smu, SMU_MCLK, &level_count);
-                       if (ret)
-                               return ret;
-                       *mclk_mask = level_count - 1;
-               }
-
-               if(soc_mask) {
-                       ret = smu_get_dpm_level_count(smu, SMU_SOCCLK, &level_count);
-                       if (ret)
-                               return ret;
-                       *soc_mask = level_count - 1;
-               }
-       }
-
-       return ret;
-}
-
 static int navi10_notify_smc_display_config(struct smu_context *smu)
 {
        struct smu_clocks min_clocks = {0};
@@ -1408,31 +1596,31 @@ static int navi10_notify_smc_display_config(struct smu_context *smu)
        min_clocks.dcef_clock_in_sr = smu->display_config->min_dcef_deep_sleep_set_clk;
        min_clocks.memory_clock = smu->display_config->min_mem_set_clock;
 
-       if (smu_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
+       if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DPM_DCEFCLK_BIT)) {
                clock_req.clock_type = amd_pp_dcef_clock;
                clock_req.clock_freq_in_khz = min_clocks.dcef_clock * 10;
 
                ret = smu_v11_0_display_clock_voltage_request(smu, &clock_req);
                if (!ret) {
-                       if (smu_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
-                               ret = smu_send_smc_msg_with_param(smu,
+                       if (smu_cmn_feature_is_supported(smu, SMU_FEATURE_DS_DCEFCLK_BIT)) {
+                               ret = smu_cmn_send_smc_msg_with_param(smu,
                                                                  SMU_MSG_SetMinDeepSleepDcefclk,
                                                                  min_clocks.dcef_clock_in_sr/100,
                                                                  NULL);
                                if (ret) {
-                                       pr_err("Attempt to set divider for DCEFCLK Failed!");
+                                       dev_err(smu->adev->dev, "Attempt to set divider for DCEFCLK Failed!");
                                        return ret;
                                }
                        }
                } else {
-                       pr_info("Attempt to set Hard Min for DCEFCLK Failed!");
+                       dev_info(smu->adev->dev, "Attempt to set Hard Min for DCEFCLK Failed!");
                }
        }
 
-       if (smu_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
-               ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0);
+       if (smu_cmn_feature_is_enabled(smu, SMU_FEATURE_DPM_UCLK_BIT)) {
+               ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_clocks.memory_clock/100, 0);
                if (ret) {
-                       pr_err("[%s] Set hard min uclk failed!", __func__);
+                       dev_err(smu->adev->dev, "[%s] Set hard min uclk failed!", __func__);
                        return ret;
                }
        }
@@ -1441,70 +1629,68 @@ static int navi10_notify_smc_display_config(struct smu_context *smu)
 }
 
 static int navi10_set_watermarks_table(struct smu_context *smu,
-                                      void *watermarks, struct
-                                      dm_pp_wm_sets_with_clock_ranges_soc15
-                                      *clock_ranges)
+                                      struct dm_pp_wm_sets_with_clock_ranges_soc15 *clock_ranges)
 {
-       int i;
+       Watermarks_t *table = smu->smu_table.watermarks_table;
        int ret = 0;
-       Watermarks_t *table = watermarks;
+       int i;
 
-       if (!table || !clock_ranges)
-               return -EINVAL;
+       if (clock_ranges) {
+               if (clock_ranges->num_wm_dmif_sets > 4 ||
+                   clock_ranges->num_wm_mcif_sets > 4)
+                       return -EINVAL;
 
-       if (clock_ranges->num_wm_dmif_sets > 4 ||
-           clock_ranges->num_wm_mcif_sets > 4)
-               return -EINVAL;
+               for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
+                       table->WatermarkRow[1][i].MinClock =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[1][i].MaxClock =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[1][i].MinUclk =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[1][i].MaxUclk =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[1][i].WmSetting = (uint8_t)
+                                       clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
+               }
 
-       for (i = 0; i < clock_ranges->num_wm_dmif_sets; i++) {
-               table->WatermarkRow[1][i].MinClock =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_dcfclk_clk_in_khz /
-                       1000));
-               table->WatermarkRow[1][i].MaxClock =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_dcfclk_clk_in_khz /
-                       1000));
-               table->WatermarkRow[1][i].MinUclk =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_min_mem_clk_in_khz /
-                       1000));
-               table->WatermarkRow[1][i].MaxUclk =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_dmif_clocks_ranges[i].wm_max_mem_clk_in_khz /
-                       1000));
-               table->WatermarkRow[1][i].WmSetting = (uint8_t)
-                               clock_ranges->wm_dmif_clocks_ranges[i].wm_set_id;
-       }
+               for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
+                       table->WatermarkRow[0][i].MinClock =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[0][i].MaxClock =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[0][i].MinUclk =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[0][i].MaxUclk =
+                               cpu_to_le16((uint16_t)
+                               (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
+                               1000));
+                       table->WatermarkRow[0][i].WmSetting = (uint8_t)
+                                       clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
+               }
 
-       for (i = 0; i < clock_ranges->num_wm_mcif_sets; i++) {
-               table->WatermarkRow[0][i].MinClock =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_socclk_clk_in_khz /
-                       1000));
-               table->WatermarkRow[0][i].MaxClock =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_socclk_clk_in_khz /
-                       1000));
-               table->WatermarkRow[0][i].MinUclk =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_min_mem_clk_in_khz /
-                       1000));
-               table->WatermarkRow[0][i].MaxUclk =
-                       cpu_to_le16((uint16_t)
-                       (clock_ranges->wm_mcif_clocks_ranges[i].wm_max_mem_clk_in_khz /
-                       1000));
-               table->WatermarkRow[0][i].WmSetting = (uint8_t)
-                               clock_ranges->wm_mcif_clocks_ranges[i].wm_set_id;
+               smu->watermarks_bitmap |= WATERMARKS_EXIST;
        }
 
-       smu->watermarks_bitmap |= WATERMARKS_EXIST;
-
        /* pass data to smu controller */
-       if (!(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
-               ret = smu_write_watermarks_table(smu);
+       if ((smu->watermarks_bitmap & WATERMARKS_EXIST) &&
+            !(smu->watermarks_bitmap & WATERMARKS_LOADED)) {
+               ret = smu_cmn_write_watermarks_table(smu);
                if (ret) {
-                       pr_err("Failed to update WMTABLE!");
+                       dev_err(smu->adev->dev, "Failed to update WMTABLE!");
                        return ret;
                }
                smu->watermarks_bitmap |= WATERMARKS_LOADED;
@@ -1517,35 +1703,33 @@ static int navi10_thermal_get_temperature(struct smu_context *smu,
                                             enum amd_pp_sensors sensor,
                                             uint32_t *value)
 {
-       SmuMetrics_t metrics;
        int ret = 0;
 
        if (!value)
                return -EINVAL;
 
-       ret = navi10_get_metrics_table(smu, &metrics);
-       if (ret)
-               return ret;
-
        switch (sensor) {
        case AMDGPU_PP_SENSOR_HOTSPOT_TEMP:
-               *value = metrics.TemperatureHotspot *
-                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               ret = navi10_get_smu_metrics_data(smu,
+                                                 METRICS_TEMPERATURE_HOTSPOT,
+                                                 value);
                break;
        case AMDGPU_PP_SENSOR_EDGE_TEMP:
-               *value = metrics.TemperatureEdge *
-                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               ret = navi10_get_smu_metrics_data(smu,
+                                                 METRICS_TEMPERATURE_EDGE,
+                                                 value);
                break;
        case AMDGPU_PP_SENSOR_MEM_TEMP:
-               *value = metrics.TemperatureMem *
-                       SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+               ret = navi10_get_smu_metrics_data(smu,
+                                                 METRICS_TEMPERATURE_MEM,
+                                                 value);
                break;
        default:
-               pr_err("Invalid sensor for retrieving temp\n");
+               dev_err(smu->adev->dev, "Invalid sensor for retrieving temp\n");
                return -EINVAL;
        }
 
-       return 0;
+       return ret;
 }
 
 static int navi10_read_sensor(struct smu_context *smu,
@@ -1580,8 +1764,23 @@ static int navi10_read_sensor(struct smu_context *smu,
                ret = navi10_thermal_get_temperature(smu, sensor, (uint32_t *)data);
                *size = 4;
                break;
+       case AMDGPU_PP_SENSOR_GFX_MCLK:
+               ret = navi10_get_current_clk_freq_by_table(smu, SMU_UCLK, (uint32_t *)data);
+               *(uint32_t *)data *= 100;
+               *size = 4;
+               break;
+       case AMDGPU_PP_SENSOR_GFX_SCLK:
+               ret = navi10_get_current_clk_freq_by_table(smu, SMU_GFXCLK, (uint32_t *)data);
+               *(uint32_t *)data *= 100;
+               *size = 4;
+               break;
+       case AMDGPU_PP_SENSOR_VDDGFX:
+               ret = smu_v11_0_get_gfx_vdd(smu, (uint32_t *)data);
+               *size = 4;
+               break;
        default:
-               ret = smu_v11_0_read_sensor(smu, sensor, data, size);
+               ret = -EOPNOTSUPP;
+               break;
        }
        mutex_unlock(&smu->sensor_lock);
 
@@ -1617,160 +1816,32 @@ static int navi10_get_uclk_dpm_states(struct smu_context *smu, uint32_t *clocks_
        return 0;
 }
 
-static int navi10_set_performance_level(struct smu_context *smu,
-                                       enum amd_dpm_forced_level level);
-
-static int navi10_set_standard_performance_level(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-       int ret = 0;
-       uint32_t sclk_freq = 0, uclk_freq = 0;
-
-       switch (adev->asic_type) {
-       case CHIP_NAVI10:
-               sclk_freq = NAVI10_UMD_PSTATE_PROFILING_GFXCLK;
-               uclk_freq = NAVI10_UMD_PSTATE_PROFILING_MEMCLK;
-               break;
-       case CHIP_NAVI14:
-               sclk_freq = NAVI14_UMD_PSTATE_PROFILING_GFXCLK;
-               uclk_freq = NAVI14_UMD_PSTATE_PROFILING_MEMCLK;
-               break;
-       default:
-               /* by default, this is same as auto performance level */
-               return navi10_set_performance_level(smu, AMD_DPM_FORCED_LEVEL_AUTO);
-       }
-
-       ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false);
-       if (ret)
-               return ret;
-       ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-
-static int navi10_set_peak_performance_level(struct smu_context *smu)
-{
-       struct amdgpu_device *adev = smu->adev;
-       int ret = 0;
-       uint32_t sclk_freq = 0, uclk_freq = 0;
-
-       switch (adev->asic_type) {
-       case CHIP_NAVI10:
-               switch (adev->pdev->revision) {
-               case 0xf0: /* XTX */
-               case 0xc0:
-                       sclk_freq = NAVI10_PEAK_SCLK_XTX;
-                       break;
-               case 0xf1: /* XT */
-               case 0xc1:
-                       sclk_freq = NAVI10_PEAK_SCLK_XT;
-                       break;
-               default: /* XL */
-                       sclk_freq = NAVI10_PEAK_SCLK_XL;
-                       break;
-               }
-               break;
-       case CHIP_NAVI14:
-               switch (adev->pdev->revision) {
-               case 0xc7: /* XT */
-               case 0xf4:
-                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XT_GFXCLK;
-                       break;
-               case 0xc1: /* XTM */
-               case 0xf2:
-                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XTM_GFXCLK;
-                       break;
-               case 0xc3: /* XLM */
-               case 0xf3:
-                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
-                       break;
-               case 0xc5: /* XTX */
-               case 0xf6:
-                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XLM_GFXCLK;
-                       break;
-               default: /* XL */
-                       sclk_freq = NAVI14_UMD_PSTATE_PEAK_XL_GFXCLK;
-                       break;
-               }
-               break;
-       case CHIP_NAVI12:
-               sclk_freq = NAVI12_UMD_PSTATE_PEAK_GFXCLK;
-               break;
-       default:
-               ret = smu_get_dpm_level_range(smu, SMU_SCLK, NULL, &sclk_freq);
-               if (ret)
-                       return ret;
-       }
-
-       ret = smu_get_dpm_level_range(smu, SMU_UCLK, NULL, &uclk_freq);
-       if (ret)
-               return ret;
-
-       ret = smu_set_soft_freq_range(smu, SMU_SCLK, sclk_freq, sclk_freq, false);
-       if (ret)
-               return ret;
-       ret = smu_set_soft_freq_range(smu, SMU_UCLK, uclk_freq, uclk_freq, false);
-       if (ret)
-               return ret;
-
-       return ret;
-}
-
-static int navi10_set_performance_level(struct smu_context *smu,
-                                       enum amd_dpm_forced_level level)
-{
-       int ret = 0;
-       uint32_t sclk_mask, mclk_mask, soc_mask;
-
-       switch (level) {
-       case AMD_DPM_FORCED_LEVEL_HIGH:
-               ret = smu_force_dpm_limit_value(smu, true);
-               break;
-       case AMD_DPM_FORCED_LEVEL_LOW:
-               ret = smu_force_dpm_limit_value(smu, false);
-               break;
-       case AMD_DPM_FORCED_LEVEL_AUTO:
-               ret = smu_unforce_dpm_levels(smu);
-               break;
-       case AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD:
-               ret = navi10_set_standard_performance_level(smu);
-               break;
-       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK:
-       case AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK:
-               ret = smu_get_profiling_clk_mask(smu, level,
-                                                &sclk_mask,
-                                                &mclk_mask,
-                                                &soc_mask);
-               if (ret)
-                       return ret;
-               smu_force_clk_levels(smu, SMU_SCLK, 1 << sclk_mask, false);
-               smu_force_clk_levels(smu, SMU_MCLK, 1 << mclk_mask, false);
-               smu_force_clk_levels(smu, SMU_SOCCLK, 1 << soc_mask, false);
-               break;
-       case AMD_DPM_FORCED_LEVEL_PROFILE_PEAK:
-               ret = navi10_set_peak_performance_level(smu);
-               break;
-       case AMD_DPM_FORCED_LEVEL_MANUAL:
-       case AMD_DPM_FORCED_LEVEL_PROFILE_EXIT:
-       default:
-               break;
-       }
-       return ret;
-}
-
 static int navi10_get_thermal_temperature_range(struct smu_context *smu,
                                                struct smu_temperature_range *range)
 {
        struct smu_table_context *table_context = &smu->smu_table;
-       struct smu_11_0_powerplay_table *powerplay_table = table_context->power_play_table;
+       struct smu_11_0_powerplay_table *powerplay_table =
+                               table_context->power_play_table;
+       PPTable_t *pptable = smu->smu_table.driver_pptable;
 
-       if (!range || !powerplay_table)
+       if (!range)
                return -EINVAL;
 
-       range->max = powerplay_table->software_shutdown_temp *
+       memcpy(range, &smu11_thermal_policy[0], sizeof(struct smu_temperature_range));
+
+       range->max = pptable->TedgeLimit *
+               SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->edge_emergency_max = (pptable->TedgeLimit + CTF_OFFSET_EDGE) *
+               SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->hotspot_crit_max = pptable->ThotspotLimit *
+               SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->hotspot_emergency_max = (pptable->ThotspotLimit + CTF_OFFSET_HOTSPOT) *
+               SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->mem_crit_max = pptable->TmemLimit *
                SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->mem_emergency_max = (pptable->TmemLimit + CTF_OFFSET_MEM)*
+               SMU_TEMPERATURE_UNITS_PER_CENTIGRADES;
+       range->software_shutdown_temp = powerplay_table->software_shutdown_temp;
 
        return 0;
 }
@@ -1789,9 +1860,9 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
                return 0;
 
        if(disable_memory_clock_switch)
-               ret = smu_set_hard_freq_range(smu, SMU_UCLK, max_memory_clock, 0);
+               ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, max_memory_clock, 0);
        else
-               ret = smu_set_hard_freq_range(smu, SMU_UCLK, min_memory_clock, 0);
+               ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, min_memory_clock, 0);
 
        if(!ret)
                smu->disable_uclk_switch = disable_memory_clock_switch;
@@ -1799,51 +1870,35 @@ static int navi10_display_disable_memory_clock_switch(struct smu_context *smu,
        return ret;
 }
 
-static uint32_t navi10_get_pptable_power_limit(struct smu_context *smu)
+static int navi10_get_power_limit(struct smu_context *smu)
 {
+       struct smu_11_0_powerplay_table *powerplay_table =
+               (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
+       struct smu_11_0_overdrive_table *od_settings = smu->od_settings;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
-       return pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
-}
+       uint32_t power_limit, od_percent;
 
-static int navi10_get_power_limit(struct smu_context *smu,
-                                    uint32_t *limit,
-                                    bool cap)
-{
-       PPTable_t *pptable = smu->smu_table.driver_pptable;
-       uint32_t asic_default_power_limit = 0;
-       int ret = 0;
-       int power_src;
+       if (smu_v11_0_get_current_power_limit(smu, &power_limit)) {
+               /* the last hope to figure out the ppt limit */
+               if (!pptable) {
+                       dev_err(smu->adev->dev, "Cannot get PPT limit due to pptable missing!");
+                       return -EINVAL;
+               }
+               power_limit =
+                       pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
+       }
+       smu->current_power_limit = power_limit;
 
-       if (!smu->power_limit) {
-               if (smu_feature_is_enabled(smu, SMU_FEATURE_PPT_BIT) &&
-                       !amdgpu_sriov_vf(smu->adev)) {
-                       power_src = smu_power_get_index(smu, SMU_POWER_SOURCE_AC);
-                       if (power_src < 0)
-                               return -EINVAL;
+       if (smu->od_enabled &&
+           navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_POWER_LIMIT)) {
+               od_percent = le32_to_cpu(powerplay_table->overdrive_table.max[SMU_11_0_ODSETTING_POWERPERCENTAGE]);
 
-                       ret = smu_send_smc_msg_with_param(smu, SMU_MSG_GetPptLimit,
-                               power_src << 16, &asic_default_power_limit);
-                       if (ret) {
-                               pr_err("[%s] get PPT limit failed!", __func__);
-                               return ret;
-                       }
-               } else {
-                       /* the last hope to figure out the ppt limit */
-                       if (!pptable) {
-                               pr_err("Cannot get PPT limit due to pptable missing!");
-                               return -EINVAL;
-                       }
-                       asic_default_power_limit =
-                               pptable->SocketPowerLimitAc[PPT_THROTTLER_PPT0];
-               }
+               dev_dbg(smu->adev->dev, "ODSETTING_POWERPERCENTAGE: %d (default: %d)\n", od_percent, power_limit);
 
-               smu->power_limit = asic_default_power_limit;
+               power_limit *= (100 + od_percent);
+               power_limit /= 100;
        }
-
-       if (cap)
-               *limit = smu_v11_0_get_max_power_limit(smu);
-       else
-               *limit = smu->power_limit;
+       smu->max_power_limit = power_limit;
 
        return 0;
 }
@@ -1852,19 +1907,23 @@ static int navi10_update_pcie_parameters(struct smu_context *smu,
                                     uint32_t pcie_gen_cap,
                                     uint32_t pcie_width_cap)
 {
+       struct smu_11_0_dpm_context *dpm_context = smu->smu_dpm.dpm_context;
        PPTable_t *pptable = smu->smu_table.driver_pptable;
-       int ret, i;
        uint32_t smu_pcie_arg;
+       int ret, i;
 
-       struct smu_dpm_context *smu_dpm = &smu->smu_dpm;
-       struct smu_11_0_dpm_context *dpm_context = smu_dpm->dpm_context;
+       /* lclk dpm table setup */
+       for (i = 0; i < MAX_PCIE_CONF; i++) {
+               dpm_context->dpm_tables.pcie_table.pcie_gen[i] = pptable->PcieGenSpeed[i];
+               dpm_context->dpm_tables.pcie_table.pcie_lane[i] = pptable->PcieLaneCount[i];
+       }
 
        for (i = 0; i < NUM_LINK_LEVELS; i++) {
                smu_pcie_arg = (i << 16) |
                        ((pptable->PcieGenSpeed[i] <= pcie_gen_cap) ? (pptable->PcieGenSpeed[i] << 8) :
                                (pcie_gen_cap << 8)) | ((pptable->PcieLaneCount[i] <= pcie_width_cap) ?
                                        pptable->PcieLaneCount[i] : pcie_width_cap);
-               ret = smu_send_smc_msg_with_param(smu,
+               ret = smu_cmn_send_smc_msg_with_param(smu,
                                          SMU_MSG_OverridePcieParameters,
                                          smu_pcie_arg,
                                          NULL);
@@ -1881,23 +1940,28 @@ static int navi10_update_pcie_parameters(struct smu_context *smu,
        return 0;
 }
 
-static inline void navi10_dump_od_table(OverDriveTable_t *od_table) {
-       pr_debug("OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
-       pr_debug("OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1);
-       pr_debug("OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2);
-       pr_debug("OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3);
-       pr_debug("OD: UclkFmax: %d\n", od_table->UclkFmax);
-       pr_debug("OD: OverDrivePct: %d\n", od_table->OverDrivePct);
+static inline void navi10_dump_od_table(struct smu_context *smu,
+                                       OverDriveTable_t *od_table)
+{
+       dev_dbg(smu->adev->dev, "OD: Gfxclk: (%d, %d)\n", od_table->GfxclkFmin, od_table->GfxclkFmax);
+       dev_dbg(smu->adev->dev, "OD: Gfx1: (%d, %d)\n", od_table->GfxclkFreq1, od_table->GfxclkVolt1);
+       dev_dbg(smu->adev->dev, "OD: Gfx2: (%d, %d)\n", od_table->GfxclkFreq2, od_table->GfxclkVolt2);
+       dev_dbg(smu->adev->dev, "OD: Gfx3: (%d, %d)\n", od_table->GfxclkFreq3, od_table->GfxclkVolt3);
+       dev_dbg(smu->adev->dev, "OD: UclkFmax: %d\n", od_table->UclkFmax);
+       dev_dbg(smu->adev->dev, "OD: OverDrivePct: %d\n", od_table->OverDrivePct);
 }
 
-static int navi10_od_setting_check_range(struct smu_11_0_overdrive_table *od_table, enum SMU_11_0_ODSETTING_ID setting, uint32_t value)
+static int navi10_od_setting_check_range(struct smu_context *smu,
+                                        struct smu_11_0_overdrive_table *od_table,
+                                        enum SMU_11_0_ODSETTING_ID setting,
+                                        uint32_t value)
 {
        if (value < od_table->min[setting]) {
-               pr_warn("OD setting (%d, %d) is less than the minimum allowed (%d)\n", setting, value, od_table->min[setting]);
+               dev_warn(smu->adev->dev, "OD setting (%d, %d) is less than the minimum allowed (%d)\n", setting, value, od_table->min[setting]);
                return -EINVAL;
        }
        if (value > od_table->max[setting]) {
-               pr_warn("OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]);
+               dev_warn(smu->adev->dev, "OD setting (%d, %d) is greater than the maximum allowed (%d)\n", setting, value, od_table->max[setting]);
                return -EINVAL;
        }
        return 0;
@@ -1911,12 +1975,12 @@ static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
        uint32_t value = 0;
        int ret;
 
-       ret = smu_send_smc_msg_with_param(smu,
+       ret = smu_cmn_send_smc_msg_with_param(smu,
                                          SMU_MSG_GetVoltageByDpm,
                                          param,
                                          &value);
        if (ret) {
-               pr_err("[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
+               dev_err(smu->adev->dev, "[GetBaseVoltage] failed to get GFXCLK AVFS voltage from SMU!");
                return ret;
        }
 
@@ -1925,93 +1989,61 @@ static int navi10_overdrive_get_gfx_clk_base_voltage(struct smu_context *smu,
        return 0;
 }
 
-static int navi10_setup_od_limits(struct smu_context *smu) {
-       struct smu_11_0_overdrive_table *overdrive_table = NULL;
-       struct smu_11_0_powerplay_table *powerplay_table = NULL;
-
-       if (!smu->smu_table.power_play_table) {
-               pr_err("powerplay table uninitialized!\n");
-               return -ENOENT;
-       }
-       powerplay_table = (struct smu_11_0_powerplay_table *)smu->smu_table.power_play_table;
-       overdrive_table = &powerplay_table->overdrive_table;
-       if (!smu->od_settings) {
-               smu->od_settings = kmemdup(overdrive_table, sizeof(struct smu_11_0_overdrive_table), GFP_KERNEL);
-       } else {
-               memcpy(smu->od_settings, overdrive_table, sizeof(struct smu_11_0_overdrive_table));
-       }
-       return 0;
-}
-
 static bool navi10_is_baco_supported(struct smu_context *smu)
 {
        struct amdgpu_device *adev = smu->adev;
        uint32_t val;
 
-       if (!smu_v11_0_baco_is_support(smu))
+       if (amdgpu_sriov_vf(adev) || (!smu_v11_0_baco_is_support(smu)))
                return false;
 
        val = RREG32_SOC15(NBIO, 0, mmRCC_BIF_STRAP0);
        return (val & RCC_BIF_STRAP0__STRAP_PX_CAPABLE_MASK) ? true : false;
 }
 
-static int navi10_set_default_od_settings(struct smu_context *smu, bool initialize) {
-       OverDriveTable_t *od_table, *boot_od_table;
+static int navi10_set_default_od_settings(struct smu_context *smu)
+{
+       OverDriveTable_t *od_table =
+               (OverDriveTable_t *)smu->smu_table.overdrive_table;
+       OverDriveTable_t *boot_od_table =
+               (OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
        int ret = 0;
 
-       if (amdgpu_sriov_vf(smu->adev))
-               return 0;
-
-       ret = smu_v11_0_set_default_od_settings(smu, initialize, sizeof(OverDriveTable_t));
-       if (ret)
+       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;
+       }
 
-       od_table = (OverDriveTable_t *)smu->smu_table.overdrive_table;
-       boot_od_table = (OverDriveTable_t *)smu->smu_table.boot_overdrive_table;
-       if (initialize) {
-               ret = navi10_setup_od_limits(smu);
-               if (ret) {
-                       pr_err("Failed to retrieve board OD limits\n");
+       if (!od_table->GfxclkVolt1) {
+               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
+                                                               &od_table->GfxclkVolt1,
+                                                               od_table->GfxclkFreq1);
+               if (ret)
                        return ret;
-               }
-               if (od_table) {
-                       if (!od_table->GfxclkVolt1) {
-                               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
-                                                                               &od_table->GfxclkVolt1,
-                                                                               od_table->GfxclkFreq1);
-                               if (ret)
-                                       od_table->GfxclkVolt1 = 0;
-                               if (boot_od_table)
-                                       boot_od_table->GfxclkVolt1 = od_table->GfxclkVolt1;
-                       }
-
-                       if (!od_table->GfxclkVolt2) {
-                               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
-                                                                               &od_table->GfxclkVolt2,
-                                                                               od_table->GfxclkFreq2);
-                               if (ret)
-                                       od_table->GfxclkVolt2 = 0;
-                               if (boot_od_table)
-                                       boot_od_table->GfxclkVolt2 = od_table->GfxclkVolt2;
-                       }
+       }
 
-                       if (!od_table->GfxclkVolt3) {
-                               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
-                                                                               &od_table->GfxclkVolt3,
-                                                                               od_table->GfxclkFreq3);
-                               if (ret)
-                                       od_table->GfxclkVolt3 = 0;
-                               if (boot_od_table)
-                                       boot_od_table->GfxclkVolt3 = od_table->GfxclkVolt3;
-                       }
-               }
+       if (!od_table->GfxclkVolt2) {
+               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
+                                                               &od_table->GfxclkVolt2,
+                                                               od_table->GfxclkFreq2);
+               if (ret)
+                       return ret;
        }
 
-       if (od_table) {
-               navi10_dump_od_table(od_table);
+       if (!od_table->GfxclkVolt3) {
+               ret = navi10_overdrive_get_gfx_clk_base_voltage(smu,
+                                                               &od_table->GfxclkVolt3,
+                                                               od_table->GfxclkFreq3);
+               if (ret)
+                       return ret;
        }
 
-       return ret;
+       memcpy(boot_od_table, od_table, sizeof(OverDriveTable_t));
+
+       navi10_dump_od_table(smu, od_table);
+
+       return 0;
 }
 
 static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABLE_COMMAND type, long input[], uint32_t size) {
@@ -2025,12 +2057,12 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
        od_table = (OverDriveTable_t *)table_context->overdrive_table;
 
        if (!smu->od_enabled) {
-               pr_warn("OverDrive is not enabled!\n");
+               dev_warn(smu->adev->dev, "OverDrive is not enabled!\n");
                return -EINVAL;
        }
 
        if (!smu->od_settings) {
-               pr_err("OD board limits are not set!\n");
+               dev_err(smu->adev->dev, "OD board limits are not set!\n");
                return -ENOENT;
        }
 
@@ -2039,16 +2071,16 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
        switch (type) {
        case PP_OD_EDIT_SCLK_VDDC_TABLE:
                if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_LIMITS)) {
-                       pr_warn("GFXCLK_LIMITS not supported!\n");
+                       dev_warn(smu->adev->dev, "GFXCLK_LIMITS not supported!\n");
                        return -ENOTSUPP;
                }
                if (!table_context->overdrive_table) {
-                       pr_err("Overdrive is not initialized\n");
+                       dev_err(smu->adev->dev, "Overdrive is not initialized\n");
                        return -EINVAL;
                }
                for (i = 0; i < size; i += 2) {
                        if (i + 2 > size) {
-                               pr_info("invalid number of input parameters %d\n", size);
+                               dev_info(smu->adev->dev, "invalid number of input parameters %d\n", size);
                                return -EINVAL;
                        }
                        switch (input[i]) {
@@ -2056,7 +2088,7 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
                                freq_setting = SMU_11_0_ODSETTING_GFXCLKFMIN;
                                freq_ptr = &od_table->GfxclkFmin;
                                if (input[i + 1] > od_table->GfxclkFmax) {
-                                       pr_info("GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n",
+                                       dev_info(smu->adev->dev, "GfxclkFmin (%ld) must be <= GfxclkFmax (%u)!\n",
                                                input[i + 1],
                                                od_table->GfxclkFmin);
                                        return -EINVAL;
@@ -2066,18 +2098,18 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
                                freq_setting = SMU_11_0_ODSETTING_GFXCLKFMAX;
                                freq_ptr = &od_table->GfxclkFmax;
                                if (input[i + 1] < od_table->GfxclkFmin) {
-                                       pr_info("GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n",
+                                       dev_info(smu->adev->dev, "GfxclkFmax (%ld) must be >= GfxclkFmin (%u)!\n",
                                                input[i + 1],
                                                od_table->GfxclkFmax);
                                        return -EINVAL;
                                }
                                break;
                        default:
-                               pr_info("Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
-                               pr_info("Supported indices: [0:min,1:max]\n");
+                               dev_info(smu->adev->dev, "Invalid SCLK_VDDC_TABLE index: %ld\n", input[i]);
+                               dev_info(smu->adev->dev, "Supported indices: [0:min,1:max]\n");
                                return -EINVAL;
                        }
-                       ret = navi10_od_setting_check_range(od_settings, freq_setting, input[i + 1]);
+                       ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[i + 1]);
                        if (ret)
                                return ret;
                        *freq_ptr = input[i + 1];
@@ -2085,56 +2117,49 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
                break;
        case PP_OD_EDIT_MCLK_VDDC_TABLE:
                if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_UCLK_MAX)) {
-                       pr_warn("UCLK_MAX not supported!\n");
+                       dev_warn(smu->adev->dev, "UCLK_MAX not supported!\n");
                        return -ENOTSUPP;
                }
                if (size < 2) {
-                       pr_info("invalid number of parameters: %d\n", size);
+                       dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size);
                        return -EINVAL;
                }
                if (input[0] != 1) {
-                       pr_info("Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]);
-                       pr_info("Supported indices: [1:max]\n");
+                       dev_info(smu->adev->dev, "Invalid MCLK_VDDC_TABLE index: %ld\n", input[0]);
+                       dev_info(smu->adev->dev, "Supported indices: [1:max]\n");
                        return -EINVAL;
                }
-               ret = navi10_od_setting_check_range(od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]);
+               ret = navi10_od_setting_check_range(smu, od_settings, SMU_11_0_ODSETTING_UCLKFMAX, input[1]);
                if (ret)
                        return ret;
                od_table->UclkFmax = input[1];
                break;
        case PP_OD_RESTORE_DEFAULT_TABLE:
                if (!(table_context->overdrive_table && table_context->boot_overdrive_table)) {
-                       pr_err("Overdrive table was not initialized!\n");
+                       dev_err(smu->adev->dev, "Overdrive table was not initialized!\n");
                        return -EINVAL;
                }
                memcpy(table_context->overdrive_table, table_context->boot_overdrive_table, sizeof(OverDriveTable_t));
                break;
        case PP_OD_COMMIT_DPM_TABLE:
-               navi10_dump_od_table(od_table);
-               ret = smu_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
-               if (ret) {
-                       pr_err("Failed to import overdrive table!\n");
-                       return ret;
-               }
-               // no lock needed because smu_od_edit_dpm_table has it
-               ret = smu_handle_task(smu, smu->smu_dpm.dpm_level,
-                       AMD_PP_TASK_READJUST_POWER_STATE,
-                       false);
+               navi10_dump_od_table(smu, od_table);
+               ret = smu_cmn_update_table(smu, SMU_TABLE_OVERDRIVE, 0, (void *)od_table, true);
                if (ret) {
+                       dev_err(smu->adev->dev, "Failed to import overdrive table!\n");
                        return ret;
                }
                break;
        case PP_OD_EDIT_VDDC_CURVE:
                if (!navi10_od_feature_is_supported(od_settings, SMU_11_0_ODCAP_GFXCLK_CURVE)) {
-                       pr_warn("GFXCLK_CURVE not supported!\n");
+                       dev_warn(smu->adev->dev, "GFXCLK_CURVE not supported!\n");
                        return -ENOTSUPP;
                }
                if (size < 3) {
-                       pr_info("invalid number of parameters: %d\n", size);
+                       dev_info(smu->adev->dev, "invalid number of parameters: %d\n", size);
                        return -EINVAL;
                }
                if (!od_table) {
-                       pr_info("Overdrive is not initialized\n");
+                       dev_info(smu->adev->dev, "Overdrive is not initialized\n");
                        return -EINVAL;
                }
 
@@ -2158,28 +2183,28 @@ static int navi10_od_edit_dpm_table(struct smu_context *smu, enum PP_OD_DPM_TABL
                        voltage_ptr = &od_table->GfxclkVolt3;
                        break;
                default:
-                       pr_info("Invalid VDDC_CURVE index: %ld\n", input[0]);
-                       pr_info("Supported indices: [0, 1, 2]\n");
+                       dev_info(smu->adev->dev, "Invalid VDDC_CURVE index: %ld\n", input[0]);
+                       dev_info(smu->adev->dev, "Supported indices: [0, 1, 2]\n");
                        return -EINVAL;
                }
-               ret = navi10_od_setting_check_range(od_settings, freq_setting, input[1]);
+               ret = navi10_od_setting_check_range(smu, od_settings, freq_setting, input[1]);
                if (ret)
                        return ret;
                // Allow setting zero to disable the OverDrive VDDC curve
                if (input[2] != 0) {
-                       ret = navi10_od_setting_check_range(od_settings, voltage_setting, input[2]);
+                       ret = navi10_od_setting_check_range(smu, od_settings, voltage_setting, input[2]);
                        if (ret)
                                return ret;
                        *freq_ptr = input[1];
                        *voltage_ptr = ((uint16_t)input[2]) * NAVI10_VOLTAGE_SCALE;
-                       pr_debug("OD: set curve %ld: (%d, %d)\n", input[0], *freq_ptr, *voltage_ptr);
+                       dev_dbg(smu->adev->dev, "OD: set curve %ld: (%d, %d)\n", input[0], *freq_ptr, *voltage_ptr);
                } else {
                        // If setting 0, disable all voltage curve settings
                        od_table->GfxclkVolt1 = 0;
                        od_table->GfxclkVolt2 = 0;
                        od_table->GfxclkVolt3 = 0;
                }
-               navi10_dump_od_table(od_table);
+               navi10_dump_od_table(smu, od_table);
                break;
        default:
                return -ENOSYS;
@@ -2191,9 +2216,9 @@ static int navi10_run_btc(struct smu_context *smu)
 {
        int ret = 0;
 
-       ret = smu_send_smc_msg(smu, SMU_MSG_RunBtc, NULL);
+       ret = smu_cmn_send_smc_msg(smu, SMU_MSG_RunBtc, NULL);
        if (ret)
-               pr_err("RunBtc failed!\n");
+               dev_err(smu->adev->dev, "RunBtc failed!\n");
 
        return ret;
 }
@@ -2203,20 +2228,38 @@ static int navi10_dummy_pstate_control(struct smu_context *smu, bool enable)
        int result = 0;
 
        if (!enable)
-               result = smu_send_smc_msg(smu, SMU_MSG_DAL_DISABLE_DUMMY_PSTATE_CHANGE, NULL);
+               result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_DISABLE_DUMMY_PSTATE_CHANGE, NULL);
        else
-               result = smu_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL);
+               result = smu_cmn_send_smc_msg(smu, SMU_MSG_DAL_ENABLE_DUMMY_PSTATE_CHANGE, NULL);
 
        return result;
 }
 
+static inline bool navi10_need_umc_cdr_12gbps_workaround(struct amdgpu_device *adev)
+{
+       if (adev->asic_type != CHIP_NAVI10)
+               return false;
+
+       if (adev->pdev->device == 0x731f &&
+           (adev->pdev->revision == 0xc2 ||
+            adev->pdev->revision == 0xc3 ||
+            adev->pdev->revision == 0xca ||
+            adev->pdev->revision == 0xcb))
+               return true;
+       else
+               return false;
+}
+
 static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu)
 {
        uint32_t uclk_count, uclk_min, uclk_max;
        uint32_t smu_version;
        int ret = 0;
 
-       ret = smu_get_smc_version(smu, NULL, &smu_version);
+       if (!navi10_need_umc_cdr_12gbps_workaround(smu->adev))
+               return 0;
+
+       ret = smu_cmn_get_smc_version(smu, NULL, &smu_version);
        if (ret)
                return ret;
 
@@ -2224,25 +2267,25 @@ static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu)
        if (smu_version < 0x2A3200)
                return 0;
 
-       ret = smu_get_dpm_level_count(smu, SMU_UCLK, &uclk_count);
+       ret = smu_v11_0_get_dpm_level_count(smu, SMU_UCLK, &uclk_count);
        if (ret)
                return ret;
 
-       ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)0, &uclk_min);
+       ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)0, &uclk_min);
        if (ret)
                return ret;
 
-       ret = smu_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)(uclk_count - 1), &uclk_max);
+       ret = smu_v11_0_get_dpm_freq_by_index(smu, SMU_UCLK, (uint16_t)(uclk_count - 1), &uclk_max);
        if (ret)
                return ret;
 
        /* Force UCLK out of the highest DPM */
-       ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, uclk_min);
+       ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_min);
        if (ret)
                return ret;
 
        /* Revert the UCLK Hardmax */
-       ret = smu_set_hard_freq_range(smu, SMU_UCLK, 0, uclk_max);
+       ret = smu_v11_0_set_hard_freq_limited_range(smu, SMU_UCLK, 0, uclk_max);
        if (ret)
                return ret;
 
@@ -2253,23 +2296,301 @@ static int navi10_disable_umc_cdr_12gbps_workaround(struct smu_context *smu)
        return navi10_dummy_pstate_control(smu, true);
 }
 
+static void navi10_fill_i2c_req(SwI2cRequest_t  *req, bool write,
+                                 uint8_t address, uint32_t numbytes,
+                                 uint8_t *data)
+{
+       int i;
+
+       BUG_ON(numbytes > MAX_SW_I2C_COMMANDS);
+
+       req->I2CcontrollerPort = 0;
+       req->I2CSpeed = 2;
+       req->SlaveAddress = address;
+       req->NumCmds = numbytes;
+
+       for (i = 0; i < numbytes; i++) {
+               SwI2cCmd_t *cmd =  &req->SwI2cCmds[i];
+
+               /* First 2 bytes are always write for lower 2b EEPROM address */
+               if (i < 2)
+                       cmd->Cmd = 1;
+               else
+                       cmd->Cmd = write;
+
+
+               /* Add RESTART for read  after address filled */
+               cmd->CmdConfig |= (i == 2 && !write) ? CMDCONFIG_RESTART_MASK : 0;
+
+               /* Add STOP in the end */
+               cmd->CmdConfig |= (i == (numbytes - 1)) ? CMDCONFIG_STOP_MASK : 0;
+
+               /* Fill with data regardless if read or write to simplify code */
+               cmd->RegisterAddr = data[i];
+       }
+}
+
+static int navi10_i2c_read_data(struct i2c_adapter *control,
+                                              uint8_t address,
+                                              uint8_t *data,
+                                              uint32_t numbytes)
+{
+       uint32_t  i, ret = 0;
+       SwI2cRequest_t req;
+       struct amdgpu_device *adev = to_amdgpu_device(control);
+       struct smu_table_context *smu_table = &adev->smu.smu_table;
+       struct smu_table *table = &smu_table->driver_table;
+
+       memset(&req, 0, sizeof(req));
+       navi10_fill_i2c_req(&req, false, address, numbytes, data);
+
+       mutex_lock(&adev->smu.mutex);
+       /* Now read data starting with that address */
+       ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req,
+                                  true);
+       mutex_unlock(&adev->smu.mutex);
+
+       if (!ret) {
+               SwI2cRequest_t *res = (SwI2cRequest_t *)table->cpu_addr;
+
+               /* Assume SMU  fills res.SwI2cCmds[i].Data with read bytes */
+               for (i = 0; i < numbytes; i++)
+                       data[i] = res->SwI2cCmds[i].Data;
+
+               dev_dbg(adev->dev, "navi10_i2c_read_data, address = %x, bytes = %d, data :",
+                                 (uint16_t)address, numbytes);
+
+               print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
+                              8, 1, data, numbytes, false);
+       } else
+               dev_err(adev->dev, "navi10_i2c_read_data - error occurred :%x", ret);
+
+       return ret;
+}
+
+static int navi10_i2c_write_data(struct i2c_adapter *control,
+                                               uint8_t address,
+                                               uint8_t *data,
+                                               uint32_t numbytes)
+{
+       uint32_t ret;
+       SwI2cRequest_t req;
+       struct amdgpu_device *adev = to_amdgpu_device(control);
+
+       memset(&req, 0, sizeof(req));
+       navi10_fill_i2c_req(&req, true, address, numbytes, data);
+
+       mutex_lock(&adev->smu.mutex);
+       ret = smu_cmn_update_table(&adev->smu, SMU_TABLE_I2C_COMMANDS, 0, &req, true);
+       mutex_unlock(&adev->smu.mutex);
+
+       if (!ret) {
+               dev_dbg(adev->dev, "navi10_i2c_write(), address = %x, bytes = %d , data: ",
+                                        (uint16_t)address, numbytes);
+
+               print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE,
+                              8, 1, data, numbytes, false);
+               /*
+                * According to EEPROM spec there is a MAX of 10 ms required for
+                * EEPROM to flush internal RX buffer after STOP was issued at the
+                * end of write transaction. During this time the EEPROM will not be
+                * responsive to any more commands - so wait a bit more.
+                */
+               msleep(10);
+
+       } else
+               dev_err(adev->dev, "navi10_i2c_write- error occurred :%x", ret);
+
+       return ret;
+}
+
+static int navi10_i2c_xfer(struct i2c_adapter *i2c_adap,
+                             struct i2c_msg *msgs, int num)
+{
+       uint32_t  i, j, ret, data_size, data_chunk_size, next_eeprom_addr = 0;
+       uint8_t *data_ptr, data_chunk[MAX_SW_I2C_COMMANDS] = { 0 };
+
+       for (i = 0; i < num; i++) {
+               /*
+                * SMU interface allows at most MAX_SW_I2C_COMMANDS bytes of data at
+                * once and hence the data needs to be spliced into chunks and sent each
+                * chunk separately
+                */
+               data_size = msgs[i].len - 2;
+               data_chunk_size = MAX_SW_I2C_COMMANDS - 2;
+               next_eeprom_addr = (msgs[i].buf[0] << 8 & 0xff00) | (msgs[i].buf[1] & 0xff);
+               data_ptr = msgs[i].buf + 2;
+
+               for (j = 0; j < data_size / data_chunk_size; j++) {
+                       /* Insert the EEPROM dest addess, bits 0-15 */
+                       data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
+                       data_chunk[1] = (next_eeprom_addr & 0xff);
+
+                       if (msgs[i].flags & I2C_M_RD) {
+                               ret = navi10_i2c_read_data(i2c_adap,
+                                                            (uint8_t)msgs[i].addr,
+                                                            data_chunk, MAX_SW_I2C_COMMANDS);
+
+                               memcpy(data_ptr, data_chunk + 2, data_chunk_size);
+                       } else {
+
+                               memcpy(data_chunk + 2, data_ptr, data_chunk_size);
+
+                               ret = navi10_i2c_write_data(i2c_adap,
+                                                             (uint8_t)msgs[i].addr,
+                                                             data_chunk, MAX_SW_I2C_COMMANDS);
+                       }
+
+                       if (ret) {
+                               num = -EIO;
+                               goto fail;
+                       }
+
+                       next_eeprom_addr += data_chunk_size;
+                       data_ptr += data_chunk_size;
+               }
+
+               if (data_size % data_chunk_size) {
+                       data_chunk[0] = ((next_eeprom_addr >> 8) & 0xff);
+                       data_chunk[1] = (next_eeprom_addr & 0xff);
+
+                       if (msgs[i].flags & I2C_M_RD) {
+                               ret = navi10_i2c_read_data(i2c_adap,
+                                                            (uint8_t)msgs[i].addr,
+                                                            data_chunk, (data_size % data_chunk_size) + 2);
+
+                               memcpy(data_ptr, data_chunk + 2, data_size % data_chunk_size);
+                       } else {
+                               memcpy(data_chunk + 2, data_ptr, data_size % data_chunk_size);
+
+                               ret = navi10_i2c_write_data(i2c_adap,
+                                                             (uint8_t)msgs[i].addr,
+                                                             data_chunk, (data_size % data_chunk_size) + 2);
+                       }
+
+                       if (ret) {
+                               num = -EIO;
+                               goto fail;
+                       }
+               }
+       }
+
+fail:
+       return num;
+}
+
+static u32 navi10_i2c_func(struct i2c_adapter *adap)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+
+static const struct i2c_algorithm navi10_i2c_algo = {
+       .master_xfer = navi10_i2c_xfer,
+       .functionality = navi10_i2c_func,
+};
+
+static int navi10_i2c_control_init(struct smu_context *smu, struct i2c_adapter *control)
+{
+       struct amdgpu_device *adev = to_amdgpu_device(control);
+       int res;
+
+       control->owner = THIS_MODULE;
+       control->class = I2C_CLASS_SPD;
+       control->dev.parent = &adev->pdev->dev;
+       control->algo = &navi10_i2c_algo;
+       snprintf(control->name, sizeof(control->name), "AMDGPU SMU");
+
+       res = i2c_add_adapter(control);
+       if (res)
+               DRM_ERROR("Failed to register hw i2c, err: %d\n", res);
+
+       return res;
+}
+
+static void navi10_i2c_control_fini(struct smu_context *smu, struct i2c_adapter *control)
+{
+       i2c_del_adapter(control);
+}
+
+static ssize_t navi10_get_gpu_metrics(struct smu_context *smu,
+                                     void **table)
+{
+       struct smu_table_context *smu_table = &smu->smu_table;
+       struct gpu_metrics_v1_0 *gpu_metrics =
+               (struct gpu_metrics_v1_0 *)smu_table->gpu_metrics_table;
+       struct amdgpu_device *adev = smu->adev;
+       SmuMetrics_NV12_t nv12_metrics = { 0 };
+       SmuMetrics_t metrics;
+       int ret = 0;
+
+       mutex_lock(&smu->metrics_lock);
+
+       ret = navi10_get_metrics_table_locked(smu,
+                                             &metrics,
+                                             true);
+       if (ret) {
+               mutex_unlock(&smu->metrics_lock);
+               return ret;
+       }
+
+       if (adev->asic_type == CHIP_NAVI12)
+               memcpy(&nv12_metrics, smu_table->metrics_table, sizeof(SmuMetrics_NV12_t));
+
+       mutex_unlock(&smu->metrics_lock);
+
+       smu_v11_0_init_gpu_metrics_v1_0(gpu_metrics);
+
+       gpu_metrics->temperature_edge = metrics.TemperatureEdge;
+       gpu_metrics->temperature_hotspot = metrics.TemperatureHotspot;
+       gpu_metrics->temperature_mem = metrics.TemperatureMem;
+       gpu_metrics->temperature_vrgfx = metrics.TemperatureVrGfx;
+       gpu_metrics->temperature_vrsoc = metrics.TemperatureVrSoc;
+       gpu_metrics->temperature_vrmem = metrics.TemperatureVrMem0;
+
+       gpu_metrics->average_gfx_activity = metrics.AverageGfxActivity;
+       gpu_metrics->average_umc_activity = metrics.AverageUclkActivity;
+
+       gpu_metrics->average_socket_power = metrics.AverageSocketPower;
+
+       gpu_metrics->average_gfxclk_frequency = metrics.AverageGfxclkFrequency;
+       gpu_metrics->average_socclk_frequency = metrics.AverageSocclkFrequency;
+       gpu_metrics->average_uclk_frequency = metrics.AverageUclkFrequency;
+
+       if (adev->asic_type == CHIP_NAVI12) {
+               gpu_metrics->energy_accumulator = nv12_metrics.EnergyAccumulator;
+               gpu_metrics->average_vclk0_frequency = nv12_metrics.AverageVclkFrequency;
+               gpu_metrics->average_dclk0_frequency = nv12_metrics.AverageDclkFrequency;
+               gpu_metrics->average_mm_activity = nv12_metrics.VcnActivityPercentage;
+       }
+
+       gpu_metrics->current_gfxclk = metrics.CurrClock[PPCLK_GFXCLK];
+       gpu_metrics->current_socclk = metrics.CurrClock[PPCLK_SOCCLK];
+       gpu_metrics->current_uclk = metrics.CurrClock[PPCLK_UCLK];
+       gpu_metrics->current_vclk0 = metrics.CurrClock[PPCLK_VCLK];
+       gpu_metrics->current_dclk0 = metrics.CurrClock[PPCLK_DCLK];
+
+       gpu_metrics->throttle_status = metrics.ThrottlerStatus;
+
+       gpu_metrics->current_fan_speed = metrics.CurrFanSpeed;
+
+       gpu_metrics->pcie_link_width =
+                       smu_v11_0_get_current_pcie_link_width(smu);
+       gpu_metrics->pcie_link_speed =
+                       smu_v11_0_get_current_pcie_link_speed(smu);
+
+       *table = (void *)gpu_metrics;
+
+       return sizeof(struct gpu_metrics_v1_0);
+}
+
 static const struct pptable_funcs navi10_ppt_funcs = {
-       .tables_init = navi10_tables_init,
-       .alloc_dpm_context = navi10_allocate_dpm_context,
-       .store_powerplay_table = navi10_store_powerplay_table,
-       .check_powerplay_table = navi10_check_powerplay_table,
-       .append_powerplay_table = navi10_append_powerplay_table,
-       .get_smu_msg_index = navi10_get_smu_msg_index,
-       .get_smu_clk_index = navi10_get_smu_clk_index,
-       .get_smu_feature_index = navi10_get_smu_feature_index,
-       .get_smu_table_index = navi10_get_smu_table_index,
-       .get_smu_power_index = navi10_get_pwr_src_index,
-       .get_workload_type = navi10_get_workload_type,
        .get_allowed_feature_mask = navi10_get_allowed_feature_mask,
        .set_default_dpm_table = navi10_set_default_dpm_table,
-       .dpm_set_uvd_enable = navi10_dpm_set_uvd_enable,
+       .dpm_set_vcn_enable = navi10_dpm_set_vcn_enable,
        .dpm_set_jpeg_enable = navi10_dpm_set_jpeg_enable,
-       .get_current_clk_freq_by_table = navi10_get_current_clk_freq_by_table,
+       .i2c_init = navi10_i2c_control_init,
+       .i2c_fini = navi10_i2c_control_fini,
        .print_clk_levels = navi10_print_clk_levels,
        .force_clk_levels = navi10_force_clk_levels,
        .populate_umd_state_clk = navi10_populate_umd_state_clk,
@@ -2277,53 +2598,48 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .pre_display_config_changed = navi10_pre_display_config_changed,
        .display_config_changed = navi10_display_config_changed,
        .notify_smc_display_config = navi10_notify_smc_display_config,
-       .force_dpm_limit_value = navi10_force_dpm_limit_value,
-       .unforce_dpm_levels = navi10_unforce_dpm_levels,
        .is_dpm_running = navi10_is_dpm_running,
        .get_fan_speed_percent = navi10_get_fan_speed_percent,
        .get_fan_speed_rpm = navi10_get_fan_speed_rpm,
        .get_power_profile_mode = navi10_get_power_profile_mode,
        .set_power_profile_mode = navi10_set_power_profile_mode,
-       .get_profiling_clk_mask = navi10_get_profiling_clk_mask,
        .set_watermarks_table = navi10_set_watermarks_table,
        .read_sensor = navi10_read_sensor,
        .get_uclk_dpm_states = navi10_get_uclk_dpm_states,
-       .set_performance_level = navi10_set_performance_level,
+       .set_performance_level = smu_v11_0_set_performance_level,
        .get_thermal_temperature_range = navi10_get_thermal_temperature_range,
        .display_disable_memory_clock_switch = navi10_display_disable_memory_clock_switch,
        .get_power_limit = navi10_get_power_limit,
        .update_pcie_parameters = navi10_update_pcie_parameters,
        .init_microcode = smu_v11_0_init_microcode,
        .load_microcode = smu_v11_0_load_microcode,
-       .init_smc_tables = smu_v11_0_init_smc_tables,
+       .fini_microcode = smu_v11_0_fini_microcode,
+       .init_smc_tables = navi10_init_smc_tables,
        .fini_smc_tables = smu_v11_0_fini_smc_tables,
        .init_power = smu_v11_0_init_power,
        .fini_power = smu_v11_0_fini_power,
        .check_fw_status = smu_v11_0_check_fw_status,
-       .setup_pptable = smu_v11_0_setup_pptable,
+       .setup_pptable = navi10_setup_pptable,
        .get_vbios_bootup_values = smu_v11_0_get_vbios_bootup_values,
-       .get_clk_info_from_vbios = smu_v11_0_get_clk_info_from_vbios,
-       .check_pptable = smu_v11_0_check_pptable,
-       .parse_pptable = smu_v11_0_parse_pptable,
-       .populate_smc_tables = smu_v11_0_populate_smc_pptable,
        .check_fw_version = smu_v11_0_check_fw_version,
-       .write_pptable = smu_v11_0_write_pptable,
-       .set_min_dcef_deep_sleep = smu_v11_0_set_min_dcef_deep_sleep,
+       .write_pptable = smu_cmn_write_pptable,
        .set_driver_table_location = smu_v11_0_set_driver_table_location,
        .set_tool_table_location = smu_v11_0_set_tool_table_location,
        .notify_memory_pool_location = smu_v11_0_notify_memory_pool_location,
        .system_features_control = smu_v11_0_system_features_control,
-       .send_smc_msg_with_param = smu_v11_0_send_msg_with_param,
+       .send_smc_msg_with_param = smu_cmn_send_smc_msg_with_param,
+       .send_smc_msg = smu_cmn_send_smc_msg,
        .init_display_count = smu_v11_0_init_display_count,
        .set_allowed_mask = smu_v11_0_set_allowed_mask,
-       .get_enabled_mask = smu_v11_0_get_enabled_mask,
+       .get_enabled_mask = smu_cmn_get_enabled_mask,
+       .feature_is_enabled = smu_cmn_feature_is_enabled,
+       .disable_all_features_with_exception = smu_cmn_disable_all_features_with_exception,
        .notify_display_change = smu_v11_0_notify_display_change,
        .set_power_limit = smu_v11_0_set_power_limit,
-       .get_current_clk_freq = smu_v11_0_get_current_clk_freq,
        .init_max_sustainable_clocks = smu_v11_0_init_max_sustainable_clocks,
-       .start_thermal_control = smu_v11_0_start_thermal_control,
-       .stop_thermal_control = smu_v11_0_stop_thermal_control,
-       .set_deep_sleep_dcefclk = smu_v11_0_set_deep_sleep_dcefclk,
+       .enable_thermal_alert = smu_v11_0_enable_thermal_alert,
+       .disable_thermal_alert = smu_v11_0_disable_thermal_alert,
+       .set_min_dcef_deep_sleep = smu_v11_0_set_min_deep_sleep_dcefclk,
        .display_clock_voltage_request = smu_v11_0_display_clock_voltage_request,
        .get_fan_control_mode = smu_v11_0_get_fan_control_mode,
        .set_fan_control_mode = smu_v11_0_set_fan_control_mode,
@@ -2341,16 +2657,23 @@ static const struct pptable_funcs navi10_ppt_funcs = {
        .baco_exit = smu_v11_0_baco_exit,
        .get_dpm_ultimate_freq = smu_v11_0_get_dpm_ultimate_freq,
        .set_soft_freq_limited_range = smu_v11_0_set_soft_freq_limited_range,
-       .override_pcie_parameters = smu_v11_0_override_pcie_parameters,
        .set_default_od_settings = navi10_set_default_od_settings,
        .od_edit_dpm_table = navi10_od_edit_dpm_table,
-       .get_pptable_power_limit = navi10_get_pptable_power_limit,
        .run_btc = navi10_run_btc,
        .disable_umc_cdr_12gbps_workaround = navi10_disable_umc_cdr_12gbps_workaround,
        .set_power_source = smu_v11_0_set_power_source,
+       .get_pp_feature_mask = smu_cmn_get_pp_feature_mask,
+       .set_pp_feature_mask = smu_cmn_set_pp_feature_mask,
+       .get_gpu_metrics = navi10_get_gpu_metrics,
 };
 
 void navi10_set_ppt_funcs(struct smu_context *smu)
 {
        smu->ppt_funcs = &navi10_ppt_funcs;
+       smu->message_map = navi10_message_map;
+       smu->clock_map = navi10_clk_map;
+       smu->feature_map = navi10_feature_mask_map;
+       smu->table_map = navi10_table_map;
+       smu->pwr_src_map = navi10_pwr_src_map;
+       smu->workload_map = navi10_workload_map;
 }