Fix display underruns on Pineview with 2048x1280 VGA display.
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_display.c
index 5908cd5..074d283 100644 (file)
@@ -718,6 +718,9 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipestat_reg = PIPESTAT(pipe);
+       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       int timeout = crtc->hwmode.vrefresh ?
+               DIV_ROUND_UP(1000, crtc->hwmode.vrefresh) : 50;
 
        /* Clear existing vblank status. Note this will clear any other
         * sticky status fields as well.
@@ -738,7 +741,7 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
        /* Wait for vblank interrupt bit to set */
        if (wait_for(I915_READ(pipestat_reg) &
                     PIPE_VBLANK_INTERRUPT_STATUS,
-                    50))
+                    timeout))
                DRM_DEBUG_KMS("vblank wait timed out\n");
 }
 
@@ -2547,7 +2550,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       u32 reg, temp, i;
+       u32 reg, temp, i, retry;
 
        /* Train 1: umask FDI RX Interrupt symbol_lock and bit_lock bit
           for train result */
@@ -2599,15 +2602,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                POSTING_READ(reg);
                udelay(500);
 
-               reg = FDI_RX_IIR(pipe);
-               temp = I915_READ(reg);
-               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-               if (temp & FDI_RX_BIT_LOCK) {
-                       I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
-                       DRM_DEBUG_KMS("FDI train 1 done.\n");
-                       break;
+               for (retry = 0; retry < 5; retry++) {
+                       reg = FDI_RX_IIR(pipe);
+                       temp = I915_READ(reg);
+                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+                       if (temp & FDI_RX_BIT_LOCK) {
+                               I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
+                               DRM_DEBUG_KMS("FDI train 1 done.\n");
+                               break;
+                       }
+                       udelay(50);
                }
+               if (retry < 5)
+                       break;
        }
        if (i == 4)
                DRM_ERROR("FDI train 1 fail!\n");
@@ -2648,15 +2655,19 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
                POSTING_READ(reg);
                udelay(500);
 
-               reg = FDI_RX_IIR(pipe);
-               temp = I915_READ(reg);
-               DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
-
-               if (temp & FDI_RX_SYMBOL_LOCK) {
-                       I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
-                       DRM_DEBUG_KMS("FDI train 2 done.\n");
-                       break;
+               for (retry = 0; retry < 5; retry++) {
+                       reg = FDI_RX_IIR(pipe);
+                       temp = I915_READ(reg);
+                       DRM_DEBUG_KMS("FDI_RX_IIR 0x%x\n", temp);
+                       if (temp & FDI_RX_SYMBOL_LOCK) {
+                               I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
+                               DRM_DEBUG_KMS("FDI train 2 done.\n");
+                               break;
+                       }
+                       udelay(50);
                }
+               if (retry < 5)
+                       break;
        }
        if (i == 4)
                DRM_ERROR("FDI train 2 fail!\n");
@@ -5313,14 +5324,14 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
                dspcntr |= DISPPLANE_SEL_PIPE_B;
 
        if (pipe == 0 && INTEL_INFO(dev)->gen < 4) {
-               /* Enable pixel doubling when the dot clock is > 90% of the (display)
+               /* Enable pixel doubling when the dot clock is > 85% of the (display)
                 * core speed.
                 *
                 * XXX: No double-wide on 915GM pipe B. Is that the only reason for the
                 * pipe == 0 check?
                 */
                if (mode->clock >
-                   dev_priv->display.get_display_clock_speed(dev) * 9 / 10)
+                   dev_priv->display.get_display_clock_speed(dev) * 17 / 20)
                        pipeconf |= PIPECONF_DOUBLE_WIDE;
                else
                        pipeconf &= ~PIPECONF_DOUBLE_WIDE;
@@ -6992,7 +7003,7 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
        return mode;
 }
 
-#define GPU_IDLE_TIMEOUT 500 /* ms */
+#define GPU_IDLE_TIMEOUT 400 /* ms */
 
 /* When this timer fires, we've been idle for awhile */
 static void intel_gpu_idle_timer(unsigned long arg)
@@ -7011,7 +7022,7 @@ static void intel_gpu_idle_timer(unsigned long arg)
        queue_work(dev_priv->wq, &dev_priv->idle_work);
 }
 
-#define CRTC_IDLE_TIMEOUT 1000 /* ms */
+#define CRTC_IDLE_TIMEOUT 700 /* ms */
 
 static void intel_crtc_idle_timer(unsigned long arg)
 {
@@ -7072,9 +7083,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       int dpll_reg = DPLL(pipe);
-       int dpll = I915_READ(dpll_reg);
 
        if (HAS_PCH_SPLIT(dev))
                return;
@@ -7087,10 +7095,15 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
         * the manual case.
         */
        if (!HAS_PIPE_CXSR(dev) && intel_crtc->lowfreq_avail) {
+               int pipe = intel_crtc->pipe;
+               int dpll_reg = DPLL(pipe);
+               u32 dpll;
+
                DRM_DEBUG_DRIVER("downclocking LVDS\n");
 
                assert_panel_unlocked(dev_priv, pipe);
 
+               dpll = I915_READ(dpll_reg);
                dpll |= DISPLAY_RATE_SELECT_FPA1;
                I915_WRITE(dpll_reg, dpll);
                intel_wait_for_vblank(dev, pipe);
@@ -7098,7 +7111,6 @@ static void intel_decrease_pllclock(struct drm_crtc *crtc)
                if (!(dpll & DISPLAY_RATE_SELECT_FPA1))
                        DRM_DEBUG_DRIVER("failed to downclock LVDS!\n");
        }
-
 }
 
 /**
@@ -7588,6 +7600,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                goto cleanup_pending;
 
        intel_disable_fbc(dev);
+       intel_mark_busy(dev, intel_fb->obj);
        mutex_unlock(&dev->struct_mutex);
 
        trace_i915_flip_request(intel_crtc->plane, obj);
@@ -8289,7 +8302,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
        u32 gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
        u32 pcu_mbox, rc6_mask = 0;
        u32 gtfifodbg;
-       int cur_freq, min_freq, max_freq;
+       u8 cur_delay, min_delay, max_delay;
        int rc6_mode;
        int i;
 
@@ -8325,7 +8338,7 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN6_RC_SLEEP, 0);
        I915_WRITE(GEN6_RC1e_THRESHOLD, 1000);
        I915_WRITE(GEN6_RC6_THRESHOLD, 50000);
-       I915_WRITE(GEN6_RC6p_THRESHOLD, 100000);
+       I915_WRITE(GEN6_RC6p_THRESHOLD, 150000);
        I915_WRITE(GEN6_RC6pp_THRESHOLD, 64000); /* unused */
 
        rc6_mode = intel_enable_rc6(dev_priv->dev);
@@ -8348,19 +8361,18 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                   GEN6_RC_CTL_EI_MODE(1) |
                   GEN6_RC_CTL_HW_ENABLE);
 
-       I915_WRITE(GEN6_RPNSWREQ,
-                  GEN6_FREQUENCY(10) |
-                  GEN6_OFFSET(0) |
-                  GEN6_AGGRESSIVE_TURBO);
-       I915_WRITE(GEN6_RC_VIDEO_FREQ,
-                  GEN6_FREQUENCY(12));
-
        I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
        I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
                   18 << 24 |
                   6 << 16);
-       I915_WRITE(GEN6_RP_UP_THRESHOLD, 10000);
-       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 1000000);
+       /*
+        * These thresholds found through experimentation. Making them
+        * symmetric will prevent holding the clock high when the workload is
+        * light. This allows us to improve our power usage, and lower thermals.
+        */
+       I915_WRITE(GEN6_RP_UP_THRESHOLD, 0x4000);
+       I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 0x4000);
+
        I915_WRITE(GEN6_RP_UP_EI, 100000);
        I915_WRITE(GEN6_RP_DOWN_EI, 5000000);
        I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
@@ -8384,9 +8396,9 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                     500))
                DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
 
-       min_freq = (rp_state_cap & 0xff0000) >> 16;
-       max_freq = rp_state_cap & 0xff;
-       cur_freq = (gt_perf_status & 0xff00) >> 8;
+       min_delay = (rp_state_cap & 0xff0000) >> 16;
+       max_delay = rp_state_cap & 0xff;
+       cur_delay = (gt_perf_status & 0xff00) >> 8;
 
        /* Check for overclock support */
        if (wait_for((I915_READ(GEN6_PCODE_MAILBOX) & GEN6_PCODE_READY) == 0,
@@ -8398,14 +8410,21 @@ void gen6_enable_rps(struct drm_i915_private *dev_priv)
                     500))
                DRM_ERROR("timeout waiting for pcode mailbox to finish\n");
        if (pcu_mbox & (1<<31)) { /* OC supported */
-               max_freq = pcu_mbox & 0xff;
+               max_delay = pcu_mbox & 0xff;
                DRM_DEBUG_DRIVER("overclocking supported, adjusting frequency max to %dMHz\n", pcu_mbox * 50);
        }
 
        /* In units of 100MHz */
-       dev_priv->max_delay = max_freq;
-       dev_priv->min_delay = min_freq;
-       dev_priv->cur_delay = cur_freq;
+       dev_priv->min_delay = max(min_delay, dev_priv->min_delay);
+       dev_priv->max_delay = max_delay;
+       dev_priv->cur_delay = max(dev_priv->min_delay, (u8)10);
+
+       I915_WRITE(GEN6_RPNSWREQ,
+                  GEN6_FREQUENCY(dev_priv->cur_delay) |
+                  GEN6_OFFSET(0) |
+                  GEN6_AGGRESSIVE_TURBO);
+       I915_WRITE(GEN6_RC_VIDEO_FREQ,
+                  GEN6_FREQUENCY(12));
 
        /* requires MSI enabled */
        I915_WRITE(GEN6_PMIER,
@@ -8626,7 +8645,9 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
         * This implements the WaDisableRCZUnitClockGating workaround.
         */
-       I915_WRITE(GEN6_UCGCTL2, GEN6_RCZUNIT_CLOCK_GATE_DISABLE);
+       I915_WRITE(GEN6_UCGCTL2,
+                  GEN6_RCZUNIT_CLOCK_GATE_DISABLE |
+                  GEN6_RCCUNIT_CLOCK_GATE_DISABLE);
 
        I915_WRITE(ILK_DSPCLK_GATE, IVB_VRHUNIT_CLK_GATE);