OSDN Git Service

Merge branch 'drm-next-4.8' of git://people.freedesktop.org/~agd5f/linux into drm...
[android-x86/kernel.git] / drivers / gpu / drm / amd / powerplay / hwmgr / polaris10_hwmgr.c
index ec2a7ad..d1b528b 100644 (file)
@@ -98,7 +98,6 @@
 #define PCIE_BUS_CLK                10000
 #define TCLK                        (PCIE_BUS_CLK / 10)
 
-#define CEILING_UCHAR(double) ((double-(uint8_t)(double)) > 0 ? (uint8_t)(double+1) : (uint8_t)(double))
 
 static const uint16_t polaris10_clock_stretcher_lookup_table[2][4] =
 { {600, 1050, 3, 0}, {600, 1050, 6, 1} };
@@ -390,6 +389,34 @@ static int polaris10_program_voting_clients(struct pp_hwmgr *hwmgr)
        return 0;
 }
 
+static int polaris10_clear_voting_clients(struct pp_hwmgr *hwmgr)
+{
+       /* Reset voting clients before disabling DPM */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_SCLK_CNT, 1);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       SCLK_PWRMGT_CNTL, RESET_BUSY_CNT, 1);
+
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_0, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_1, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_2, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_3, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_4, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_5, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_6, 0);
+       cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC,
+                       ixCG_FREQ_TRAN_VOTING_7, 0);
+
+       return 0;
+}
+
 /**
 * Get the location of various tables inside the FW image.
 *
@@ -516,6 +543,11 @@ static int polaris10_copy_and_switch_arb_sets(struct pp_hwmgr *hwmgr,
        return 0;
 }
 
+static int polaris10_reset_to_default(struct pp_hwmgr *hwmgr)
+{
+       return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_ResetToDefaults);
+}
+
 /**
 * Initial switch from ARB F0->F1
 *
@@ -529,6 +561,21 @@ static int polaris10_initial_switch_from_arbf0_to_f1(struct pp_hwmgr *hwmgr)
                        MC_CG_ARB_FREQ_F0, MC_CG_ARB_FREQ_F1);
 }
 
+static int polaris10_force_switch_to_arbf0(struct pp_hwmgr *hwmgr)
+{
+       uint32_t tmp;
+
+       tmp = (cgs_read_ind_register(hwmgr->device,
+                       CGS_IND_REG__SMC, ixSMC_SCRATCH9) &
+                       0x0000ff00) >> 8;
+
+       if (tmp == MC_CG_ARB_FREQ_F0)
+               return 0;
+
+       return polaris10_copy_and_switch_arb_sets(hwmgr,
+                       tmp, MC_CG_ARB_FREQ_F0);
+}
+
 static int polaris10_setup_default_pcie_table(struct pp_hwmgr *hwmgr)
 {
        struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
@@ -733,7 +780,7 @@ static int polaris10_populate_smc_mvdd_table(struct pp_hwmgr *hwmgr,
                        table->Smio[level] |=
                                data->mvdd_voltage_table.entries[level].smio_low;
                }
-               table->SmioMask2 = data->vddci_voltage_table.mask_low;
+               table->SmioMask2 = data->mvdd_voltage_table.mask_low;
 
                table->MvddLevelCount = (uint32_t) PP_HOST_TO_SMC_UL(count);
        }
@@ -1357,9 +1404,9 @@ static int polaris10_populate_all_memory_levels(struct pp_hwmgr *hwmgr)
                        return result;
        }
 
-       /* in order to prevent MC activity from stutter mode to push DPM up.
+       /* In order to prevent MC activity from stutter mode to push DPM up,
         * the UVD change complements this by putting the MCLK in
-        * a higher state by default such that we are not effected by
+        * a higher state by default such that we are not affected by
         * up threshold or and MCLK DPM latency.
         */
        levels[0].ActivityLevel = 0x1f;
@@ -1781,7 +1828,7 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
 {
        uint32_t ro, efuse, volt_without_cks, volt_with_cks, value, max, min;
        struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-       uint8_t i, stretch_amount, stretch_amount2, volt_offset = 0;
+       uint8_t i, stretch_amount, volt_offset = 0;
        struct phm_ppt_v1_information *table_info =
                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
        struct phm_ppt_v1_clock_voltage_dependency_table *sclk_table =
@@ -1807,38 +1854,33 @@ static int polaris10_populate_clock_stretcher_data_table(struct pp_hwmgr *hwmgr)
 
        ro = efuse * (max -min)/255 + min;
 
-       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset
-        * there is a little difference in calculating
-        * volt_with_cks with windows */
+       /* Populate Sclk_CKS_masterEn0_7 and Sclk_voltageOffset */
        for (i = 0; i < sclk_table->count; i++) {
                data->smc_state_table.Sclk_CKS_masterEn0_7 |=
                                sclk_table->entries[i].cks_enable << i;
                if (hwmgr->chip_id == CHIP_POLARIS10) {
-                       volt_without_cks = (uint32_t)((2753594000 + (sclk_table->entries[i].clk/100) * 136418 -(ro - 70) * 1000000) / \
+                       volt_without_cks = (uint32_t)((2753594000U + (sclk_table->entries[i].clk/100) * 136418 -(ro - 70) * 1000000) / \
                                                (2424180 - (sclk_table->entries[i].clk/100) * 1132925/1000));
-                       volt_with_cks = (uint32_t)((279720200 + sclk_table->entries[i].clk * 3232 - (ro - 65) * 100000000) / \
-                                       (252248000 - sclk_table->entries[i].clk/100 * 115764));
+                       volt_with_cks = (uint32_t)((2797202000U + sclk_table->entries[i].clk/100 * 3232 - (ro - 65) * 1000000) / \
+                                       (2522480 - sclk_table->entries[i].clk/100 * 115764/100));
                } else {
-                       volt_without_cks = (uint32_t)((2416794800 + (sclk_table->entries[i].clk/100) * 1476925/10 -(ro - 50) * 1000000) / \
-                                               (2625416 - (sclk_table->entries[i].clk/100) * 12586807/10000));
-                       volt_with_cks = (uint32_t)((2999656000 + sclk_table->entries[i].clk * 392803/100 - (ro - 44) * 1000000) / \
-                                       (3422454 - sclk_table->entries[i].clk/100 * 18886376/10000));
+                       volt_without_cks = (uint32_t)((2416794800U + (sclk_table->entries[i].clk/100) * 1476925/10 -(ro - 50) * 1000000) / \
+                                               (2625416 - (sclk_table->entries[i].clk/100) * (12586807/10000)));
+                       volt_with_cks = (uint32_t)((2999656000U - sclk_table->entries[i].clk/100 * 392803 - (ro - 44) * 1000000) / \
+                                       (3422454 - sclk_table->entries[i].clk/100 * (18886376/10000)));
                }
 
                if (volt_without_cks >= volt_with_cks)
-                       volt_offset = (uint8_t)CEILING_UCHAR((volt_without_cks - volt_with_cks +
-                                       sclk_table->entries[i].cks_voffset) * 100 / 625);
+                       volt_offset = (uint8_t)(((volt_without_cks - volt_with_cks +
+                                       sclk_table->entries[i].cks_voffset) * 100 + 624) / 625);
 
                data->smc_state_table.Sclk_voltageOffset[i] = volt_offset;
        }
 
        data->smc_state_table.LdoRefSel = (table_info->cac_dtp_table->ucCKS_LDO_REFSEL != 0) ? table_info->cac_dtp_table->ucCKS_LDO_REFSEL : 6;
        /* Populate CKS Lookup Table */
-       if (stretch_amount == 1 || stretch_amount == 2 || stretch_amount == 5)
-               stretch_amount2 = 0;
-       else if (stretch_amount == 3 || stretch_amount == 4)
-               stretch_amount2 = 1;
-       else {
+       if (stretch_amount != 1 && stretch_amount != 2 && stretch_amount != 3 &&
+                       stretch_amount != 4 && stretch_amount != 5) {
                phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
                                PHM_PlatformCaps_ClockStretcher);
                PP_ASSERT_WITH_CODE(false,
@@ -1893,9 +1935,8 @@ static int polaris10_populate_vr_config(struct pp_hwmgr *hwmgr,
        if (POLARIS10_VOLTAGE_CONTROL_BY_SVID2 == data->mvdd_control) {
                config = VR_SVI2_PLANE_2;
                table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
-       } else if (POLARIS10_VOLTAGE_CONTROL_BY_GPIO == data->mvdd_control) {
-               config = VR_SMIO_PATTERN_2;
-               table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
+               cgs_write_ind_register(hwmgr->device, CGS_IND_REG__SMC, data->soft_regs_start +
+                       offsetof(SMU74_SoftRegisters, AllowMvddSwitch), 0x1);
        } else {
                config = VR_STATIC_VOLTAGE;
                table->VRConfig |= (config << VRCONF_MVDD_SHIFT);
@@ -2265,6 +2306,17 @@ static int polaris10_enable_ulv(struct pp_hwmgr *hwmgr)
        return 0;
 }
 
+static int polaris10_disable_ulv(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_ulv_parm *ulv = &(data->ulv);
+
+       if (ulv->ulv_supported)
+               return smum_send_msg_to_smc(hwmgr->smumgr, PPSMC_MSG_DisableULV);
+
+       return 0;
+}
+
 static int polaris10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
 {
        if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
@@ -2285,6 +2337,21 @@ static int polaris10_enable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
        return 0;
 }
 
+static int polaris10_disable_deep_sleep_master_switch(struct pp_hwmgr *hwmgr)
+{
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_SclkDeepSleep)) {
+               if (smum_send_msg_to_smc(hwmgr->smumgr,
+                               PPSMC_MSG_MASTER_DeepSleep_OFF)) {
+                       PP_ASSERT_WITH_CODE(false,
+                                       "Attempt to disable Master Deep Sleep switch failed!",
+                                       return -1);
+               }
+       }
+
+       return 0;
+}
+
 static int polaris10_enable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
 {
        struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
@@ -2382,6 +2449,58 @@ static int polaris10_start_dpm(struct pp_hwmgr *hwmgr)
        return 0;
 }
 
+static int polaris10_disable_sclk_mclk_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+
+       /* disable SCLK dpm */
+       if (!data->sclk_dpm_key_disabled)
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_DPM_Disable) == 0),
+                               "Failed to disable SCLK DPM!",
+                               return -1);
+
+       /* disable MCLK dpm */
+       if (!data->mclk_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_MCLKDPM_Disable) == 0),
+                               "Failed to disable MCLK DPM!",
+                               return -1);
+       }
+
+       return 0;
+}
+
+static int polaris10_stop_dpm(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+
+       /* disable general power management */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, GENERAL_PWRMGT,
+                       GLOBAL_PWRMGT_EN, 0);
+       /* disable sclk deep sleep */
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC, SCLK_PWRMGT_CNTL,
+                       DYNAMIC_PM_EN, 0);
+
+       /* disable PCIE dpm */
+       if (!data->pcie_dpm_key_disabled) {
+               PP_ASSERT_WITH_CODE(
+                               (smum_send_msg_to_smc(hwmgr->smumgr,
+                                               PPSMC_MSG_PCIeDPM_Disable) == 0),
+                               "Failed to disable pcie DPM during DPM Stop Function!",
+                               return -1);
+       }
+
+       if (polaris10_disable_sclk_mclk_dpm(hwmgr)) {
+               printk(KERN_ERR "Failed to disable Sclk DPM and Mclk DPM!");
+               return -1;
+       }
+
+       return 0;
+}
+
 static void polaris10_set_dpm_event_sources(struct pp_hwmgr *hwmgr, uint32_t sources)
 {
        bool protection;
@@ -2439,6 +2558,23 @@ static int polaris10_enable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
        return polaris10_enable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
 }
 
+static int polaris10_disable_auto_throttle_source(struct pp_hwmgr *hwmgr,
+               PHM_AutoThrottleSource source)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+
+       if (data->active_auto_throttle_sources & (1 << source)) {
+               data->active_auto_throttle_sources &= ~(1 << source);
+               polaris10_set_dpm_event_sources(hwmgr, data->active_auto_throttle_sources);
+       }
+       return 0;
+}
+
+static int polaris10_disable_thermal_auto_throttle(struct pp_hwmgr *hwmgr)
+{
+       return polaris10_disable_auto_throttle_source(hwmgr, PHM_AutoThrottleSource_Thermal);
+}
+
 int polaris10_pcie_performance_request(struct pp_hwmgr *hwmgr)
 {
        struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
@@ -2562,8 +2698,60 @@ int polaris10_enable_dpm_tasks(struct pp_hwmgr *hwmgr)
 
 int polaris10_disable_dpm_tasks(struct pp_hwmgr *hwmgr)
 {
+       int tmp_result, result = 0;
 
-       return 0;
+       tmp_result = (polaris10_is_dpm_running(hwmgr)) ? 0 : -1;
+       PP_ASSERT_WITH_CODE(tmp_result == 0,
+                       "DPM is not running right now, no need to disable DPM!",
+                       return 0);
+
+       if (phm_cap_enabled(hwmgr->platform_descriptor.platformCaps,
+                       PHM_PlatformCaps_ThermalController))
+               PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                               GENERAL_PWRMGT, THERMAL_PROTECTION_DIS, 1);
+
+       tmp_result = polaris10_disable_power_containment(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable power containment!", result = tmp_result);
+
+       tmp_result = polaris10_disable_smc_cac(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable SMC CAC!", result = tmp_result);
+
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       CG_SPLL_SPREAD_SPECTRUM, SSEN, 0);
+       PHM_WRITE_INDIRECT_FIELD(hwmgr->device, CGS_IND_REG__SMC,
+                       GENERAL_PWRMGT, DYN_SPREAD_SPECTRUM_EN, 0);
+
+       tmp_result = polaris10_disable_thermal_auto_throttle(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable thermal auto throttle!", result = tmp_result);
+
+       tmp_result = polaris10_stop_dpm(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to stop DPM!", result = tmp_result);
+
+       tmp_result = polaris10_disable_deep_sleep_master_switch(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable deep sleep master switch!", result = tmp_result);
+
+       tmp_result = polaris10_disable_ulv(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to disable ULV!", result = tmp_result);
+
+       tmp_result = polaris10_clear_voting_clients(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to clear voting clients!", result = tmp_result);
+
+       tmp_result = polaris10_reset_to_default(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to reset to default!", result = tmp_result);
+
+       tmp_result = polaris10_force_switch_to_arbf0(hwmgr);
+       PP_ASSERT_WITH_CODE((tmp_result == 0),
+                       "Failed to force to switch arbf0!", result = tmp_result);
+
+       return result;
 }
 
 int polaris10_reset_asic_tasks(struct pp_hwmgr *hwmgr)
@@ -2574,13 +2762,6 @@ int polaris10_reset_asic_tasks(struct pp_hwmgr *hwmgr)
 
 int polaris10_hwmgr_backend_fini(struct pp_hwmgr *hwmgr)
 {
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (data->soft_pp_table) {
-               kfree(data->soft_pp_table);
-               data->soft_pp_table = NULL;
-       }
-
        return phm_hwmgr_backend_fini(hwmgr);
 }
 
@@ -2636,8 +2817,13 @@ int polaris10_set_features_platform_caps(struct pp_hwmgr *hwmgr)
        phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
                                                PHM_PlatformCaps_TCPRamping);
 
-       phm_cap_set(hwmgr->platform_descriptor.platformCaps,
-                                       PHM_PlatformCaps_PowerContainment);
+       if (hwmgr->powercontainment_enabled)
+               phm_cap_set(hwmgr->platform_descriptor.platformCaps,
+                           PHM_PlatformCaps_PowerContainment);
+       else
+               phm_cap_unset(hwmgr->platform_descriptor.platformCaps,
+                           PHM_PlatformCaps_PowerContainment);
+
        phm_cap_set(hwmgr->platform_descriptor.platformCaps,
                                                        PHM_PlatformCaps_CAC);
 
@@ -2685,7 +2871,7 @@ static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr)
 {
        struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
        uint16_t vv_id;
-       uint16_t vddc = 0;
+       uint32_t vddc = 0;
        uint16_t i, j;
        uint32_t sclk = 0;
        struct phm_ppt_v1_information *table_info =
@@ -2709,15 +2895,16 @@ static int polaris10_get_evv_voltages(struct pp_hwmgr *hwmgr)
                                }
                        }
 
+                       if (atomctrl_get_voltage_evv_on_sclk_ai(hwmgr,
+                                               VOLTAGE_TYPE_VDDC,
+                                               sclk, vv_id, &vddc) != 0) {
+                               printk(KERN_WARNING "failed to retrieving EVV voltage!\n");
+                               continue;
+                       }
 
-                       PP_ASSERT_WITH_CODE(0 == atomctrl_get_voltage_evv_on_sclk_ai(hwmgr,
-                                                       VOLTAGE_TYPE_VDDC, sclk, vv_id, &vddc),
-                                               "Error retrieving EVV voltage value!",
-                                               continue);
-
-
-                       /* need to make sure vddc is less than 2v or else, it could burn the ASIC. */
-                       PP_ASSERT_WITH_CODE((vddc < 2000 && vddc != 0),
+                       /* need to make sure vddc is less than 2v or else, it could burn the ASIC.
+                        * real voltage level in unit of 0.01mv */
+                       PP_ASSERT_WITH_CODE((vddc < 200000 && vddc != 0),
                                        "Invalid VDDC value", result = -EINVAL;);
 
                        /* the voltage should not be zero nor equal to leakage ID */
@@ -2970,13 +3157,19 @@ int polaris10_patch_voltage_workaround(struct pp_hwmgr *hwmgr)
 
 int polaris10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
 {
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_hwmgr *data;
        struct pp_atomctrl_gpio_pin_assignment gpio_pin_assignment;
        uint32_t temp_reg;
        int result;
        struct phm_ppt_v1_information *table_info =
                        (struct phm_ppt_v1_information *)(hwmgr->pptable);
 
+       data = kzalloc(sizeof(struct polaris10_hwmgr), GFP_KERNEL);
+       if (data == NULL)
+               return -ENOMEM;
+
+       hwmgr->backend = data;
+
        data->dll_default_on = false;
        data->sram_end = SMC_RAM_END;
        data->mclk_dpm0_activity_target = 0xa;
@@ -3150,7 +3343,7 @@ int polaris10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
                sys_info.info_id = CGS_SYSTEM_INFO_PCIE_GEN_INFO;
                result = cgs_query_system_info(hwmgr->device, &sys_info);
                if (result)
-                       data->pcie_gen_cap = 0x30007;
+                       data->pcie_gen_cap = AMDGPU_DEFAULT_PCIE_GEN_MASK;
                else
                        data->pcie_gen_cap = (uint32_t)sys_info.value;
                if (data->pcie_gen_cap & CAIL_PCIE_LINK_SPEED_SUPPORT_GEN3)
@@ -3159,7 +3352,7 @@ int polaris10_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
                sys_info.info_id = CGS_SYSTEM_INFO_PCIE_MLW;
                result = cgs_query_system_info(hwmgr->device, &sys_info);
                if (result)
-                       data->pcie_lane_cap = 0x2f0000;
+                       data->pcie_lane_cap = AMDGPU_DEFAULT_PCIE_MLW_MASK;
                else
                        data->pcie_lane_cap = (uint32_t)sys_info.value;
 
@@ -4822,42 +5015,6 @@ int polaris10_setup_asic_task(struct pp_hwmgr *hwmgr)
        return result;
 }
 
-static int polaris10_get_pp_table(struct pp_hwmgr *hwmgr, char **table)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (!data->soft_pp_table) {
-               data->soft_pp_table = kmemdup(hwmgr->soft_pp_table,
-                                             hwmgr->soft_pp_table_size,
-                                             GFP_KERNEL);
-               if (!data->soft_pp_table)
-                       return -ENOMEM;
-       }
-
-       *table = (char *)&data->soft_pp_table;
-
-       return hwmgr->soft_pp_table_size;
-}
-
-static int polaris10_set_pp_table(struct pp_hwmgr *hwmgr, const char *buf, size_t size)
-{
-       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
-
-       if (!data->soft_pp_table) {
-               data->soft_pp_table = kzalloc(hwmgr->soft_pp_table_size, GFP_KERNEL);
-               if (!data->soft_pp_table)
-                       return -ENOMEM;
-       }
-
-       memcpy(data->soft_pp_table, buf, size);
-
-       hwmgr->soft_pp_table = data->soft_pp_table;
-
-       /* TODO: re-init powerplay to implement modified pptable */
-
-       return 0;
-}
-
 static int polaris10_force_clock_level(struct pp_hwmgr *hwmgr,
                enum pp_clock_type type, uint32_t mask)
 {
@@ -5000,6 +5157,89 @@ static int polaris10_get_fan_control_mode(struct pp_hwmgr *hwmgr)
                                CG_FDO_CTRL2, FDO_PWM_MODE);
 }
 
+static int polaris10_get_sclk_od(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_single_dpm_table *sclk_table = &(data->dpm_table.sclk_table);
+       struct polaris10_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.sclk_table);
+       int value;
+
+       value = (sclk_table->dpm_levels[sclk_table->count - 1].value -
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value) *
+                       100 /
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return value;
+}
+
+static int polaris10_set_sclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_single_dpm_table *golden_sclk_table =
+                       &(data->golden_dpm_table.sclk_table);
+       struct pp_power_state  *ps;
+       struct polaris10_power_state  *polaris10_ps;
+
+       if (value > 20)
+               value = 20;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
+
+       polaris10_ps->performance_levels[polaris10_ps->performance_level_count - 1].engine_clock =
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value *
+                       value / 100 +
+                       golden_sclk_table->dpm_levels[golden_sclk_table->count - 1].value;
+
+       return 0;
+}
+
+static int polaris10_get_mclk_od(struct pp_hwmgr *hwmgr)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_single_dpm_table *mclk_table = &(data->dpm_table.mclk_table);
+       struct polaris10_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mclk_table);
+       int value;
+
+       value = (mclk_table->dpm_levels[mclk_table->count - 1].value -
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value) *
+                       100 /
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return value;
+}
+
+static int polaris10_set_mclk_od(struct pp_hwmgr *hwmgr, uint32_t value)
+{
+       struct polaris10_hwmgr *data = (struct polaris10_hwmgr *)(hwmgr->backend);
+       struct polaris10_single_dpm_table *golden_mclk_table =
+                       &(data->golden_dpm_table.mclk_table);
+       struct pp_power_state  *ps;
+       struct polaris10_power_state  *polaris10_ps;
+
+       if (value > 20)
+               value = 20;
+
+       ps = hwmgr->request_ps;
+
+       if (ps == NULL)
+               return -EINVAL;
+
+       polaris10_ps = cast_phw_polaris10_power_state(&ps->hardware);
+
+       polaris10_ps->performance_levels[polaris10_ps->performance_level_count - 1].memory_clock =
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value *
+                       value / 100 +
+                       golden_mclk_table->dpm_levels[golden_mclk_table->count - 1].value;
+
+       return 0;
+}
 static const struct pp_hwmgr_func polaris10_hwmgr_funcs = {
        .backend_init = &polaris10_hwmgr_backend_init,
        .backend_fini = &polaris10_hwmgr_backend_fini,
@@ -5038,22 +5278,17 @@ static const struct pp_hwmgr_func polaris10_hwmgr_funcs = {
        .check_states_equal = polaris10_check_states_equal,
        .set_fan_control_mode = polaris10_set_fan_control_mode,
        .get_fan_control_mode = polaris10_get_fan_control_mode,
-       .get_pp_table = polaris10_get_pp_table,
-       .set_pp_table = polaris10_set_pp_table,
        .force_clock_level = polaris10_force_clock_level,
        .print_clock_levels = polaris10_print_clock_levels,
        .enable_per_cu_power_gating = polaris10_phm_enable_per_cu_power_gating,
+       .get_sclk_od = polaris10_get_sclk_od,
+       .set_sclk_od = polaris10_set_sclk_od,
+       .get_mclk_od = polaris10_get_mclk_od,
+       .set_mclk_od = polaris10_set_mclk_od,
 };
 
 int polaris10_hwmgr_init(struct pp_hwmgr *hwmgr)
 {
-       struct polaris10_hwmgr  *data;
-
-       data = kzalloc (sizeof(struct polaris10_hwmgr), GFP_KERNEL);
-       if (data == NULL)
-               return -ENOMEM;
-
-       hwmgr->backend = data;
        hwmgr->hwmgr_func = &polaris10_hwmgr_funcs;
        hwmgr->pptable_func = &tonga_pptable_funcs;
        pp_polaris10_thermal_initialize(hwmgr);