Merge branch 'drm-fixes' of git://people.freedesktop.org/~airlied/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jul 2013 21:40:10 +0000 (14:40 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Jul 2013 21:40:10 +0000 (14:40 -0700)
Pull drm fixes from Dave Airlie:
 "This is just a regular fixes pull apart from the qxl one, it has
  radeon and intel bits in it,

  The intel fixes are for a regression with the RC6 fix and a 3.10 hdmi
  regression, whereas radeon is more DPM fixes, a few lockup fixes and
  some rn50/r100 DAC fixes"

* 'drm-fixes' of git://people.freedesktop.org/~airlied/linux:
  drm/radeon/dpm: fix r600_enable_sclk_control()
  drm/radeon/dpm: implement force performance levels for rv6xx
  drm/radeon/dpm: fix displaygap programming on rv6xx
  drm/radeon/dpm: fix a typo in the rv6xx mclk setup
  drm/i915: initialize gt_lock early with other spin locks
  drm/i915: fix hdmi portclock limits
  drm/radeon: fix combios tables on older cards
  drm/radeon: improve dac adjust heuristics for legacy pdac
  drm/radeon: Another card with wrong primary dac adj
  drm/radeon: fix endian issues with DP handling (v3)
  drm/radeon/vm: only align the pt base to 32k
  drm/radeon: wait for 3D idle before using CP DMA

drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/intel_hdmi.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/radeon_asic.c
drivers/gpu/drm/radeon/radeon_asic.h
drivers/gpu/drm/radeon/radeon_combios.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/rv6xx_dpm.c

index abf158d..66c6380 100644 (file)
@@ -1498,6 +1498,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
        spin_lock_init(&dev_priv->rps.lock);
+       spin_lock_init(&dev_priv->gt_lock);
        spin_lock_init(&dev_priv->backlight.lock);
        mutex_init(&dev_priv->dpio_lock);
        mutex_init(&dev_priv->rps.hw_lock);
index 98df2a0..2fd3fd5 100644 (file)
@@ -785,10 +785,22 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
        }
 }
 
+static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
+{
+       struct drm_device *dev = intel_hdmi_to_dev(hdmi);
+
+       if (IS_G4X(dev))
+               return 165000;
+       else if (IS_HASWELL(dev))
+               return 300000;
+       else
+               return 225000;
+}
+
 static int intel_hdmi_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
-       if (mode->clock > 165000)
+       if (mode->clock > hdmi_portclock_limit(intel_attached_hdmi(connector)))
                return MODE_CLOCK_HIGH;
        if (mode->clock < 20000)
                return MODE_CLOCK_LOW;
@@ -806,6 +818,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
        struct drm_device *dev = encoder->base.dev;
        struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
        int clock_12bpc = pipe_config->requested_mode.clock * 3 / 2;
+       int portclock_limit = hdmi_portclock_limit(intel_hdmi);
        int desired_bpp;
 
        if (intel_hdmi->color_range_auto) {
@@ -829,7 +842,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
         * outputs. We also need to check that the higher clock still fits
         * within limits.
         */
-       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= 225000
+       if (pipe_config->pipe_bpp > 8*3 && clock_12bpc <= portclock_limit
            && HAS_PCH_SPLIT(dev)) {
                DRM_DEBUG_KMS("picking bpc to 12 for HDMI output\n");
                desired_bpp = 12*3;
@@ -846,7 +859,7 @@ bool intel_hdmi_compute_config(struct intel_encoder *encoder,
                pipe_config->pipe_bpp = desired_bpp;
        }
 
-       if (adjusted_mode->clock > 225000) {
+       if (adjusted_mode->clock > portclock_limit) {
                DRM_DEBUG_KMS("too high HDMI clock, rejecting mode\n");
                return false;
        }
index 6a347f5..51a2a60 100644 (file)
@@ -5497,8 +5497,6 @@ void intel_gt_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       spin_lock_init(&dev_priv->gt_lock);
-
        if (IS_VALLEYVIEW(dev)) {
                dev_priv->gt.force_wake_get = vlv_force_wake_get;
                dev_priv->gt.force_wake_put = vlv_force_wake_put;
index 064023b..32501f6 100644 (file)
@@ -44,6 +44,41 @@ static char *pre_emph_names[] = {
 };
 
 /***** radeon AUX functions *****/
+
+/* Atom needs data in little endian format
+ * so swap as appropriate when copying data to
+ * or from atom. Note that atom operates on
+ * dw units.
+ */
+static void radeon_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le)
+{
+#ifdef __BIG_ENDIAN
+       u8 src_tmp[20], dst_tmp[20]; /* used for byteswapping */
+       u32 *dst32, *src32;
+       int i;
+
+       memcpy(src_tmp, src, num_bytes);
+       src32 = (u32 *)src_tmp;
+       dst32 = (u32 *)dst_tmp;
+       if (to_le) {
+               for (i = 0; i < ((num_bytes + 3) / 4); i++)
+                       dst32[i] = cpu_to_le32(src32[i]);
+               memcpy(dst, dst_tmp, num_bytes);
+       } else {
+               u8 dws = num_bytes & ~3;
+               for (i = 0; i < ((num_bytes + 3) / 4); i++)
+                       dst32[i] = le32_to_cpu(src32[i]);
+               memcpy(dst, dst_tmp, dws);
+               if (num_bytes % 4) {
+                       for (i = 0; i < (num_bytes % 4); i++)
+                               dst[dws+i] = dst_tmp[dws+i];
+               }
+       }
+#else
+       memcpy(dst, src, num_bytes);
+#endif
+}
+
 union aux_channel_transaction {
        PROCESS_AUX_CHANNEL_TRANSACTION_PS_ALLOCATION v1;
        PROCESS_AUX_CHANNEL_TRANSACTION_PARAMETERS_V2 v2;
@@ -65,10 +100,10 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
 
        base = (unsigned char *)(rdev->mode_info.atom_context->scratch + 1);
 
-       memcpy(base, send, send_bytes);
+       radeon_copy_swap(base, send, send_bytes, true);
 
-       args.v1.lpAuxRequest = 0 + 4;
-       args.v1.lpDataOut = 16 + 4;
+       args.v1.lpAuxRequest = cpu_to_le16((u16)(0 + 4));
+       args.v1.lpDataOut = cpu_to_le16((u16)(16 + 4));
        args.v1.ucDataOutLen = 0;
        args.v1.ucChannelID = chan->rec.i2c_id;
        args.v1.ucDelay = delay / 10;
@@ -102,7 +137,7 @@ static int radeon_process_aux_ch(struct radeon_i2c_chan *chan,
                recv_bytes = recv_size;
 
        if (recv && recv_size)
-               memcpy(recv, base + 16, recv_bytes);
+               radeon_copy_swap(recv, base + 16, recv_bytes, false);
 
        return recv_bytes;
 }
index 393880a..10f712e 100644 (file)
@@ -3166,7 +3166,7 @@ int r600_copy_cpdma(struct radeon_device *rdev,
 
        size_in_bytes = (num_gpu_pages << RADEON_GPU_PAGE_SHIFT);
        num_loops = DIV_ROUND_UP(size_in_bytes, 0x1fffff);
-       r = radeon_ring_lock(rdev, ring, num_loops * 6 + 21);
+       r = radeon_ring_lock(rdev, ring, num_loops * 6 + 24);
        if (r) {
                DRM_ERROR("radeon: moving bo (%d).\n", r);
                radeon_semaphore_free(rdev, &sem, NULL);
@@ -3181,6 +3181,9 @@ int r600_copy_cpdma(struct radeon_device *rdev,
                radeon_semaphore_free(rdev, &sem, NULL);
        }
 
+       radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
+       radeon_ring_write(ring, (WAIT_UNTIL - PACKET3_SET_CONFIG_REG_OFFSET) >> 2);
+       radeon_ring_write(ring, WAIT_3D_IDLE_bit);
        for (i = 0; i < num_loops; i++) {
                cur_size_in_bytes = size_in_bytes;
                if (cur_size_in_bytes > 0x1fffff)
index b88f54b..e5c860f 100644 (file)
@@ -278,9 +278,9 @@ bool r600_dynamicpm_enabled(struct radeon_device *rdev)
 void r600_enable_sclk_control(struct radeon_device *rdev, bool enable)
 {
        if (enable)
-               WREG32_P(GENERAL_PWRMGT, 0, ~SCLK_PWRMGT_OFF);
+               WREG32_P(SCLK_PWRMGT_CNTL, 0, ~SCLK_PWRMGT_OFF);
        else
-               WREG32_P(GENERAL_PWRMGT, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
+               WREG32_P(SCLK_PWRMGT_CNTL, SCLK_PWRMGT_OFF, ~SCLK_PWRMGT_OFF);
 }
 
 void r600_enable_mclk_control(struct radeon_device *rdev, bool enable)
index 78bec1a..f8f8b31 100644 (file)
@@ -1161,6 +1161,7 @@ static struct radeon_asic rv6xx_asic = {
                .get_mclk = &rv6xx_dpm_get_mclk,
                .print_power_state = &rv6xx_dpm_print_power_state,
                .debugfs_print_current_performance_level = &rv6xx_dpm_debugfs_print_current_performance_level,
+               .force_performance_level = &rv6xx_dpm_force_performance_level,
        },
        .pflip = {
                .pre_page_flip = &rs600_pre_page_flip,
index ca18957..902479f 100644 (file)
@@ -421,6 +421,8 @@ void rv6xx_dpm_print_power_state(struct radeon_device *rdev,
                                 struct radeon_ps *ps);
 void rv6xx_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
                                                       struct seq_file *m);
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level);
 /* rs780 dpm */
 int rs780_dpm_init(struct radeon_device *rdev);
 int rs780_dpm_enable(struct radeon_device *rdev);
index 78edadc..68ce360 100644 (file)
@@ -147,7 +147,7 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
                                         enum radeon_combios_table_offset table)
 {
        struct radeon_device *rdev = dev->dev_private;
-       int rev;
+       int rev, size;
        uint16_t offset = 0, check_offset;
 
        if (!rdev->bios)
@@ -156,174 +156,106 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
        switch (table) {
                /* absolute offset tables */
        case COMBIOS_ASIC_INIT_1_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0xc);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0xc;
                break;
        case COMBIOS_BIOS_SUPPORT_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x14);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x14;
                break;
        case COMBIOS_DAC_PROGRAMMING_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2a;
                break;
        case COMBIOS_MAX_COLOR_DEPTH_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2c;
                break;
        case COMBIOS_CRTC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x2e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x2e;
                break;
        case COMBIOS_PLL_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x30);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x30;
                break;
        case COMBIOS_TV_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x32);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x32;
                break;
        case COMBIOS_DFP_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x34);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x34;
                break;
        case COMBIOS_HW_CONFIG_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x36);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x36;
                break;
        case COMBIOS_MULTIMEDIA_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x38);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x38;
                break;
        case COMBIOS_TV_STD_PATCH_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x3e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x3e;
                break;
        case COMBIOS_LCD_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x40);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x40;
                break;
        case COMBIOS_MOBILE_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x42);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x42;
                break;
        case COMBIOS_PLL_INIT_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x46);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x46;
                break;
        case COMBIOS_MEM_CONFIG_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x48);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x48;
                break;
        case COMBIOS_SAVE_MASK_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4a;
                break;
        case COMBIOS_HARDCODED_EDID_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4c;
                break;
        case COMBIOS_ASIC_INIT_2_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x4e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x4e;
                break;
        case COMBIOS_CONNECTOR_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x50);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x50;
                break;
        case COMBIOS_DYN_CLK_1_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x52);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x52;
                break;
        case COMBIOS_RESERVED_MEM_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x54);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x54;
                break;
        case COMBIOS_EXT_TMDS_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x58);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x58;
                break;
        case COMBIOS_MEM_CLK_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5a;
                break;
        case COMBIOS_EXT_DAC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5c;
                break;
        case COMBIOS_MISC_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x5e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x5e;
                break;
        case COMBIOS_CRT_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x60);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x60;
                break;
        case COMBIOS_INTEGRATED_SYSTEM_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x62);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x62;
                break;
        case COMBIOS_COMPONENT_VIDEO_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x64);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x64;
                break;
        case COMBIOS_FAN_SPEED_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x66);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x66;
                break;
        case COMBIOS_OVERDRIVE_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x68);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x68;
                break;
        case COMBIOS_OEM_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6a);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6a;
                break;
        case COMBIOS_DYN_CLK_2_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6c);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6c;
                break;
        case COMBIOS_POWER_CONNECTOR_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x6e);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x6e;
                break;
        case COMBIOS_I2C_INFO_TABLE:
-               check_offset = RBIOS16(rdev->bios_header_start + 0x70);
-               if (check_offset)
-                       offset = check_offset;
+               check_offset = 0x70;
                break;
                /* relative offset tables */
        case COMBIOS_ASIC_INIT_3_TABLE: /* offset from misc info */
@@ -439,11 +371,16 @@ static uint16_t combios_get_table_offset(struct drm_device *dev,
                }
                break;
        default:
+               check_offset = 0;
                break;
        }
 
-       return offset;
+       size = RBIOS8(rdev->bios_header_start + 0x6);
+       /* check absolute offset tables */
+       if (table < COMBIOS_ASIC_INIT_3_TABLE && check_offset && check_offset < size)
+               offset = RBIOS16(rdev->bios_header_start + check_offset);
 
+       return offset;
 }
 
 bool radeon_combios_check_hardcoded_edid(struct radeon_device *rdev)
@@ -965,16 +902,22 @@ struct radeon_encoder_primary_dac *radeon_combios_get_primary_dac_info(struct
                        dac = RBIOS8(dac_info + 0x3) & 0xf;
                        p_dac->ps2_pdac_adj = (bg << 8) | (dac);
                }
-               /* if the values are all zeros, use the table */
-               if (p_dac->ps2_pdac_adj)
+               /* if the values are zeros, use the table */
+               if ((dac == 0) || (bg == 0))
+                       found = 0;
+               else
                        found = 1;
        }
 
        /* quirks */
+       /* Radeon 7000 (RV100) */
+       if (((dev->pdev->device == 0x5159) &&
+           (dev->pdev->subsystem_vendor == 0x174B) &&
+           (dev->pdev->subsystem_device == 0x7c28)) ||
        /* Radeon 9100 (R200) */
-       if ((dev->pdev->device == 0x514D) &&
+          ((dev->pdev->device == 0x514D) &&
            (dev->pdev->subsystem_vendor == 0x174B) &&
-           (dev->pdev->subsystem_device == 0x7149)) {
+           (dev->pdev->subsystem_device == 0x7149))) {
                /* vbios value is bad, use the default */
                found = 0;
        }
index d9d31a3..6a51d94 100644 (file)
@@ -466,7 +466,7 @@ int radeon_vm_manager_init(struct radeon_device *rdev)
                size += rdev->vm_manager.max_pfn * 8;
                size *= 2;
                r = radeon_sa_bo_manager_init(rdev, &rdev->vm_manager.sa_manager,
-                                             RADEON_VM_PTB_ALIGN(size),
+                                             RADEON_GPU_PAGE_ALIGN(size),
                                              RADEON_VM_PTB_ALIGN_SIZE,
                                              RADEON_GEM_DOMAIN_VRAM);
                if (r) {
@@ -621,7 +621,7 @@ int radeon_vm_alloc_pt(struct radeon_device *rdev, struct radeon_vm *vm)
        }
 
 retry:
-       pd_size = RADEON_VM_PTB_ALIGN(radeon_vm_directory_size(rdev));
+       pd_size = radeon_vm_directory_size(rdev);
        r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
                             &vm->page_directory, pd_size,
                             RADEON_VM_PTB_ALIGN_SIZE, false);
@@ -953,8 +953,8 @@ static int radeon_vm_update_pdes(struct radeon_device *rdev,
 retry:
                r = radeon_sa_bo_new(rdev, &rdev->vm_manager.sa_manager,
                                     &vm->page_tables[pt_idx],
-                                    RADEON_VM_PTB_ALIGN(RADEON_VM_PTE_COUNT * 8),
-                                    RADEON_VM_PTB_ALIGN_SIZE, false);
+                                    RADEON_VM_PTE_COUNT * 8,
+                                    RADEON_GPU_PAGE_SIZE, false);
 
                if (r == -ENOMEM) {
                        r = radeon_vm_evict(rdev, vm);
index 65e33f3..363018c 100644 (file)
@@ -819,7 +819,7 @@ static void rv6xx_program_memory_timing_parameters(struct radeon_device *rdev)
                 POWERMODE1(calculate_memory_refresh_rate(rdev,
                                                          pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
                 POWERMODE2(calculate_memory_refresh_rate(rdev,
-                                                         pi->hw.sclks[R600_POWER_LEVEL_MEDIUM])) |
+                                                         pi->hw.sclks[R600_POWER_LEVEL_HIGH])) |
                 POWERMODE3(calculate_memory_refresh_rate(rdev,
                                                          pi->hw.sclks[R600_POWER_LEVEL_HIGH])));
        WREG32(ARB_RFSH_RATE, arb_refresh_rate);
@@ -1182,10 +1182,10 @@ static void rv6xx_program_display_gap(struct radeon_device *rdev)
        u32 tmp = RREG32(CG_DISPLAY_GAP_CNTL);
 
        tmp &= ~(DISP1_GAP_MCHG_MASK | DISP2_GAP_MCHG_MASK);
-       if (RREG32(AVIVO_D1CRTC_CONTROL) & AVIVO_CRTC_EN) {
+       if (rdev->pm.dpm.new_active_crtcs & 1) {
                tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
                tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
-       } else if (RREG32(AVIVO_D2CRTC_CONTROL) & AVIVO_CRTC_EN) {
+       } else if (rdev->pm.dpm.new_active_crtcs & 2) {
                tmp |= DISP1_GAP_MCHG(R600_PM_DISPLAY_GAP_IGNORE);
                tmp |= DISP2_GAP_MCHG(R600_PM_DISPLAY_GAP_VBLANK);
        } else {
@@ -1670,6 +1670,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
        struct radeon_ps *old_ps = rdev->pm.dpm.current_ps;
        int ret;
 
+       pi->restricted_levels = 0;
+
        rv6xx_set_uvd_clock_before_set_eng_clock(rdev, new_ps, old_ps);
 
        rv6xx_clear_vc(rdev);
@@ -1756,6 +1758,8 @@ int rv6xx_dpm_set_power_state(struct radeon_device *rdev)
 
        rv6xx_set_uvd_clock_after_set_eng_clock(rdev, new_ps, old_ps);
 
+       rdev->pm.dpm.forced_level = RADEON_DPM_FORCED_LEVEL_AUTO;
+
        return 0;
 }
 
@@ -2085,3 +2089,34 @@ u32 rv6xx_dpm_get_mclk(struct radeon_device *rdev, bool low)
        else
                return requested_state->high.mclk;
 }
+
+int rv6xx_dpm_force_performance_level(struct radeon_device *rdev,
+                                     enum radeon_dpm_forced_level level)
+{
+       struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
+
+       if (level == RADEON_DPM_FORCED_LEVEL_HIGH) {
+               pi->restricted_levels = 3;
+       } else if (level == RADEON_DPM_FORCED_LEVEL_LOW) {
+               pi->restricted_levels = 2;
+       } else {
+               pi->restricted_levels = 0;
+       }
+
+       rv6xx_clear_vc(rdev);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, true);
+       r600_set_at(rdev, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF);
+       r600_wait_for_power_level(rdev, R600_POWER_LEVEL_LOW);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, false);
+       r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, false);
+       rv6xx_enable_medium(rdev);
+       rv6xx_enable_high(rdev);
+       if (pi->restricted_levels == 3)
+               r600_power_level_enable(rdev, R600_POWER_LEVEL_LOW, false);
+       rv6xx_program_vc(rdev);
+       rv6xx_program_at(rdev);
+
+       rdev->pm.dpm.forced_level = level;
+
+       return 0;
+}