WREG32_P(CG_INTGFX_MISC, 0, ~0xFFF00000);
 }
 
-static void rs780_force_voltage_to_high(struct radeon_device *rdev)
+static void rs780_force_voltage(struct radeon_device *rdev, u16 voltage)
 {
-       struct igp_power_info *pi = rs780_get_pi(rdev);
        struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
 
        if ((current_state->max_voltage == RS780_VDDC_LEVEL_HIGH) &&
        udelay(1);
 
        WREG32_P(FVTHROT_PWM_CTRL_REG0,
-                STARTING_PWM_HIGHTIME(pi->max_voltage),
+                STARTING_PWM_HIGHTIME(voltage),
                 ~STARTING_PWM_HIGHTIME_MASK);
 
        WREG32_P(FVTHROT_PWM_CTRL_REG0,
        WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
 }
 
+static void rs780_force_fbdiv(struct radeon_device *rdev, u32 fb_div)
+{
+       struct igp_ps *current_state = rs780_get_ps(rdev->pm.dpm.current_ps);
+
+       if (current_state->sclk_low == current_state->sclk_high)
+               return;
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
+
+       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(fb_div),
+                ~FORCED_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(fb_div),
+                ~STARTING_FEEDBACK_DIV_MASK);
+       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
+
+       udelay(100);
+
+       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+}
+
 static int rs780_set_engine_clock_scaling(struct radeon_device *rdev,
                                          struct radeon_ps *new_ps,
                                          struct radeon_ps *old_ps)
        if (ret)
                return ret;
 
-       WREG32_P(GFX_MACRO_BYPASS_CNTL, SPLL_BYPASS_CNTL, ~SPLL_BYPASS_CNTL);
-
-       WREG32_P(FVTHROT_FBDIV_REG2, FORCED_FEEDBACK_DIV(max_dividers.fb_div),
-                ~FORCED_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, STARTING_FEEDBACK_DIV(max_dividers.fb_div),
-                ~STARTING_FEEDBACK_DIV_MASK);
-       WREG32_P(FVTHROT_FBDIV_REG1, FORCE_FEEDBACK_DIV, ~FORCE_FEEDBACK_DIV);
-
-       udelay(100);
-
-       WREG32_P(GFX_MACRO_BYPASS_CNTL, 0, ~SPLL_BYPASS_CNTL);
+       rs780_force_fbdiv(rdev, max_dividers.fb_div);
 
        if (max_dividers.fb_div > min_dividers.fb_div) {
                WREG32_P(FVTHROT_FBDIV_REG0,
        rs780_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 
        if (pi->voltage_control) {
-               rs780_force_voltage_to_high(rdev);
+               rs780_force_voltage(rdev, pi->max_voltage);
                mdelay(5);
        }
 
                seq_printf(m, "power level 1    sclk: %u vddc_index: %d\n",
                           ps->sclk_high, ps->max_voltage);
 }
+
+int rs780_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level)
+{
+       struct igp_power_info *pi = rs780_get_pi(rdev);
+       struct radeon_ps *rps = rdev->pm.dpm.current_ps;
+       struct igp_ps *ps = rs780_get_ps(rps);
+       struct atom_clock_dividers dividers;
+       int ret;
+
+       rs780_clk_scaling_enable(rdev, false);
+       rs780_voltage_scaling_enable(rdev, false);
+
+       if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->max_voltage);
+
+               ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_high, false, ÷rs);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, dividers.fb_div);
+       } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+               ret = radeon_atom_get_clock_dividers(rdev, COMPUTE_ENGINE_PLL_PARAM,
+                                                    ps->sclk_low, false, ÷rs);
+               if (ret)
+                       return ret;
+
+               rs780_force_fbdiv(rdev, dividers.fb_div);
+
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->min_voltage);
+       } else {
+               if (pi->voltage_control)
+                       rs780_force_voltage(rdev, pi->max_voltage);
+
+               WREG32_P(FVTHROT_FBDIV_REG1, 0, ~FORCE_FEEDBACK_DIV);
+               rs780_clk_scaling_enable(rdev, true);
+
+               if (pi->voltage_control) {
+                       rs780_voltage_scaling_enable(rdev, true);
+                       rs780_enable_voltage_scaling(rdev, rps);
+               }
+       }
+
+       rdev->pm.dpm.forced_level = level;
+
+       return 0;
+}