]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - drivers/gpu/drm/i915/intel_display.c
drm/i915: make the panel fitter work on pipes B and C on Haswell
[linux-imx.git] / drivers / gpu / drm / i915 / intel_display.c
index 2b598eb6187208abcfd9136d839b3b562eea22ba..1e405a3b660443d8bee0e4d359868c0718487376 100644 (file)
@@ -41,8 +41,6 @@
 #include <drm/drm_crtc_helper.h>
 #include <linux/dma_remapping.h>
 
-#define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
-
 bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
@@ -541,7 +539,7 @@ static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
                                limit = &intel_limits_ironlake_single_lvds;
                }
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT) ||
-                       HAS_eDP)
+                  intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
                limit = &intel_limits_ironlake_display_port;
        else
                limit = &intel_limits_ironlake_dac;
@@ -1151,14 +1149,9 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
        u32 val;
        bool cur_state;
 
-       if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
-                       DRM_ERROR("Attempting to enable FDI_RX on Haswell pipe > 0\n");
-                       return;
-       } else {
-               reg = FDI_RX_CTL(pipe);
-               val = I915_READ(reg);
-               cur_state = !!(val & FDI_RX_ENABLE);
-       }
+       reg = FDI_RX_CTL(pipe);
+       val = I915_READ(reg);
+       cur_state = !!(val & FDI_RX_ENABLE);
        WARN(cur_state != state,
             "FDI RX state assertion failure (expected %s, current %s)\n",
             state_string(state), state_string(cur_state));
@@ -1191,10 +1184,6 @@ static void assert_fdi_rx_pll_enabled(struct drm_i915_private *dev_priv,
        int reg;
        u32 val;
 
-       if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
-               DRM_ERROR("Attempting to enable FDI on Haswell with pipe > 0\n");
-               return;
-       }
        reg = FDI_RX_CTL(pipe);
        val = I915_READ(reg);
        WARN(!(val & FDI_RX_PLL_ENABLE), "FDI RX PLL assertion failure, should be active but is disabled\n");
@@ -1579,14 +1568,14 @@ out_unlock:
 }
 
 /**
- * intel_enable_pch_pll - enable PCH PLL
+ * ironlake_enable_pch_pll - enable PCH PLL
  * @dev_priv: i915 private structure
  * @pipe: pipe PLL to enable
  *
  * The PCH PLL needs to be enabled before the PCH transcoder, since it
  * drives the transcoder clock.
  */
-static void intel_enable_pch_pll(struct intel_crtc *intel_crtc)
+static void ironlake_enable_pch_pll(struct intel_crtc *intel_crtc)
 {
        struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
        struct intel_pch_pll *pll;
@@ -1670,12 +1659,12 @@ static void intel_disable_pch_pll(struct intel_crtc *intel_crtc)
        pll->on = false;
 }
 
-static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
-                                   enum pipe pipe)
+static void ironlake_enable_pch_transcoder(struct drm_i915_private *dev_priv,
+                                          enum pipe pipe)
 {
-       int reg;
-       u32 val, pipeconf_val;
+       struct drm_device *dev = dev_priv->dev;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
+       uint32_t reg, val, pipeconf_val;
 
        /* PCH only available on ILK+ */
        BUG_ON(dev_priv->info->gen < 5);
@@ -1689,10 +1678,15 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
        assert_fdi_tx_enabled(dev_priv, pipe);
        assert_fdi_rx_enabled(dev_priv, pipe);
 
-       if (IS_HASWELL(dev_priv->dev) && pipe > 0) {
-               DRM_ERROR("Attempting to enable transcoder on Haswell with pipe > 0\n");
-               return;
+       if (HAS_PCH_CPT(dev)) {
+               /* Workaround: Set the timing override bit before enabling the
+                * pch transcoder. */
+               reg = TRANS_CHICKEN2(pipe);
+               val = I915_READ(reg);
+               val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
+               I915_WRITE(reg, val);
        }
+
        reg = TRANSCONF(pipe);
        val = I915_READ(reg);
        pipeconf_val = I915_READ(PIPECONF(pipe));
@@ -1721,11 +1715,42 @@ static void intel_enable_transcoder(struct drm_i915_private *dev_priv,
                DRM_ERROR("failed to enable transcoder %d\n", pipe);
 }
 
-static void intel_disable_transcoder(struct drm_i915_private *dev_priv,
-                                    enum pipe pipe)
+static void lpt_enable_pch_transcoder(struct drm_i915_private *dev_priv,
+                                     enum transcoder cpu_transcoder)
 {
-       int reg;
-       u32 val;
+       u32 val, pipeconf_val;
+
+       /* PCH only available on ILK+ */
+       BUG_ON(dev_priv->info->gen < 5);
+
+       /* FDI must be feeding us bits for PCH ports */
+       assert_fdi_tx_enabled(dev_priv, cpu_transcoder);
+       assert_fdi_rx_enabled(dev_priv, TRANSCODER_A);
+
+       /* Workaround: set timing override bit. */
+       val = I915_READ(_TRANSA_CHICKEN2);
+       val |= TRANS_CHICKEN2_TIMING_OVERRIDE;
+       I915_WRITE(_TRANSA_CHICKEN2, val);
+
+       val = TRANS_ENABLE;
+       pipeconf_val = I915_READ(PIPECONF(cpu_transcoder));
+
+       if ((pipeconf_val & PIPECONF_INTERLACE_MASK_HSW) ==
+           PIPECONF_INTERLACED_ILK)
+               val |= TRANS_INTERLACED;
+       else
+               val |= TRANS_PROGRESSIVE;
+
+       I915_WRITE(TRANSCONF(TRANSCODER_A), val);
+       if (wait_for(I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE, 100))
+               DRM_ERROR("Failed to enable PCH transcoder\n");
+}
+
+static void ironlake_disable_pch_transcoder(struct drm_i915_private *dev_priv,
+                                           enum pipe pipe)
+{
+       struct drm_device *dev = dev_priv->dev;
+       uint32_t reg, val;
 
        /* FDI relies on the transcoder */
        assert_fdi_tx_disabled(dev_priv, pipe);
@@ -1741,6 +1766,31 @@ static void intel_disable_transcoder(struct drm_i915_private *dev_priv,
        /* wait for PCH transcoder off, transcoder state */
        if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
                DRM_ERROR("failed to disable transcoder %d\n", pipe);
+
+       if (!HAS_PCH_IBX(dev)) {
+               /* Workaround: Clear the timing override chicken bit again. */
+               reg = TRANS_CHICKEN2(pipe);
+               val = I915_READ(reg);
+               val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE;
+               I915_WRITE(reg, val);
+       }
+}
+
+static void lpt_disable_pch_transcoder(struct drm_i915_private *dev_priv)
+{
+       u32 val;
+
+       val = I915_READ(_TRANSACONF);
+       val &= ~TRANS_ENABLE;
+       I915_WRITE(_TRANSACONF, val);
+       /* wait for PCH transcoder off, transcoder state */
+       if (wait_for((I915_READ(_TRANSACONF) & TRANS_STATE_ENABLE) == 0, 50))
+               DRM_ERROR("Failed to disable PCH transcoder\n");
+
+       /* Workaround: clear timing override bit. */
+       val = I915_READ(_TRANSA_CHICKEN2);
+       val &= ~TRANS_CHICKEN2_TIMING_OVERRIDE;
+       I915_WRITE(_TRANSA_CHICKEN2, val);
 }
 
 /**
@@ -1762,9 +1812,15 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
 {
        enum transcoder cpu_transcoder = intel_pipe_to_cpu_transcoder(dev_priv,
                                                                      pipe);
+       enum transcoder pch_transcoder;
        int reg;
        u32 val;
 
+       if (IS_HASWELL(dev_priv->dev))
+               pch_transcoder = TRANSCODER_A;
+       else
+               pch_transcoder = pipe;
+
        /*
         * A pipe without a PLL won't actually be able to drive bits from
         * a plane.  On ILK+ the pipe PLLs are integrated, so we don't
@@ -1775,8 +1831,8 @@ static void intel_enable_pipe(struct drm_i915_private *dev_priv, enum pipe pipe,
        else {
                if (pch_port) {
                        /* if driving the PCH, we need FDI enabled */
-                       assert_fdi_rx_pll_enabled(dev_priv, pipe);
-                       assert_fdi_tx_pll_enabled(dev_priv, pipe);
+                       assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
+                       assert_fdi_tx_pll_enabled(dev_priv, cpu_transcoder);
                }
                /* FIXME: assert CPU port conditions for SNB+ */
        }
@@ -2201,13 +2257,39 @@ intel_finish_fb(struct drm_framebuffer *old_fb)
        return ret;
 }
 
+static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_master_private *master_priv;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       if (!dev->primary->master)
+               return;
+
+       master_priv = dev->primary->master->driver_priv;
+       if (!master_priv->sarea_priv)
+               return;
+
+       switch (intel_crtc->pipe) {
+       case 0:
+               master_priv->sarea_priv->pipeA_x = x;
+               master_priv->sarea_priv->pipeA_y = y;
+               break;
+       case 1:
+               master_priv->sarea_priv->pipeB_x = x;
+               master_priv->sarea_priv->pipeB_y = y;
+               break;
+       default:
+               break;
+       }
+}
+
 static int
 intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                    struct drm_framebuffer *fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_i915_master_private *master_priv;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_framebuffer *old_fb;
        int ret;
@@ -2259,20 +2341,7 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        intel_update_fbc(dev);
        mutex_unlock(&dev->struct_mutex);
 
-       if (!dev->primary->master)
-               return 0;
-
-       master_priv = dev->primary->master->driver_priv;
-       if (!master_priv->sarea_priv)
-               return 0;
-
-       if (intel_crtc->pipe) {
-               master_priv->sarea_priv->pipeB_x = x;
-               master_priv->sarea_priv->pipeB_y = y;
-       } else {
-               master_priv->sarea_priv->pipeA_x = x;
-               master_priv->sarea_priv->pipeA_y = y;
-       }
+       intel_crtc_update_sarea_pos(crtc, x, y);
 
        return 0;
 }
@@ -2433,11 +2502,9 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
        udelay(150);
 
        /* Ironlake workaround, enable clock pointer after FDI enable*/
-       if (HAS_PCH_IBX(dev)) {
-               I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
-               I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR |
-                          FDI_RX_PHASE_SYNC_POINTER_EN);
-       }
+       I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
+       I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR |
+                  FDI_RX_PHASE_SYNC_POINTER_EN);
 
        reg = FDI_RX_IIR(pipe);
        for (tries = 0; tries < 5; tries++) {
@@ -2543,8 +2610,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
-       if (HAS_PCH_CPT(dev))
-               cpt_phase_pointer_enable(dev, pipe);
+       cpt_phase_pointer_enable(dev, pipe);
 
        for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
@@ -2678,8 +2744,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
-       if (HAS_PCH_CPT(dev))
-               cpt_phase_pointer_enable(dev, pipe);
+       cpt_phase_pointer_enable(dev, pipe);
 
        for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
@@ -2856,9 +2921,6 @@ static void ironlake_fdi_disable(struct drm_crtc *crtc)
        /* Ironlake workaround, disable clock pointer after downing FDI */
        if (HAS_PCH_IBX(dev)) {
                I915_WRITE(FDI_RX_CHICKEN(pipe), FDI_RX_PHASE_SYNC_POINTER_OVR);
-               I915_WRITE(FDI_RX_CHICKEN(pipe),
-                          I915_READ(FDI_RX_CHICKEN(pipe) &
-                                    ~FDI_RX_PHASE_SYNC_POINTER_EN));
        } else if (HAS_PCH_CPT(dev)) {
                cpt_phase_pointer_disable(dev, pipe);
        }
@@ -3071,12 +3133,9 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
         * Note that enable_pch_pll tries to do the right thing, but get_pch_pll
         * unconditionally resets the pll - we need that to have the right LVDS
         * enable sequence. */
-       intel_enable_pch_pll(intel_crtc);
+       ironlake_enable_pch_pll(intel_crtc);
 
-       if (HAS_PCH_LPT(dev)) {
-               DRM_DEBUG_KMS("LPT detected: programming iCLKIP\n");
-               lpt_program_iclkip(crtc);
-       } else if (HAS_PCH_CPT(dev)) {
+       if (HAS_PCH_CPT(dev)) {
                u32 sel;
 
                temp = I915_READ(PCH_DPLL_SEL);
@@ -3113,8 +3172,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        I915_WRITE(TRANS_VSYNC(pipe),  I915_READ(VSYNC(pipe)));
        I915_WRITE(TRANS_VSYNCSHIFT(pipe),  I915_READ(VSYNCSHIFT(pipe)));
 
-       if (!IS_HASWELL(dev))
-               intel_fdi_normal_train(crtc);
+       intel_fdi_normal_train(crtc);
 
        /* For PCH DP, enable TRANS_DP_CTL */
        if (HAS_PCH_CPT(dev) &&
@@ -3152,7 +3210,31 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
                I915_WRITE(reg, temp);
        }
 
-       intel_enable_transcoder(dev_priv, pipe);
+       ironlake_enable_pch_transcoder(dev_priv, pipe);
+}
+
+static void lpt_pch_enable(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum transcoder cpu_transcoder = intel_crtc->cpu_transcoder;
+
+       assert_transcoder_disabled(dev_priv, TRANSCODER_A);
+
+       lpt_program_iclkip(crtc);
+
+       /* Set transcoder timing. */
+       I915_WRITE(_TRANS_HTOTAL_A, I915_READ(HTOTAL(cpu_transcoder)));
+       I915_WRITE(_TRANS_HBLANK_A, I915_READ(HBLANK(cpu_transcoder)));
+       I915_WRITE(_TRANS_HSYNC_A,  I915_READ(HSYNC(cpu_transcoder)));
+
+       I915_WRITE(_TRANS_VTOTAL_A, I915_READ(VTOTAL(cpu_transcoder)));
+       I915_WRITE(_TRANS_VBLANK_A, I915_READ(VBLANK(cpu_transcoder)));
+       I915_WRITE(_TRANS_VSYNC_A,  I915_READ(VSYNC(cpu_transcoder)));
+       I915_WRITE(_TRANS_VSYNCSHIFT_A, I915_READ(VSYNCSHIFT(cpu_transcoder)));
+
+       lpt_enable_pch_transcoder(dev_priv, cpu_transcoder);
 }
 
 static void intel_put_pch_pll(struct intel_crtc *intel_crtc)
@@ -3245,16 +3327,12 @@ prepare: /* separate function? */
 void intel_cpt_verify_modeset(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int dslreg = PIPEDSL(pipe), tc2reg = TRANS_CHICKEN2(pipe);
+       int dslreg = PIPEDSL(pipe);
        u32 temp;
 
        temp = I915_READ(dslreg);
        udelay(500);
        if (wait_for(I915_READ(dslreg) != temp, 5)) {
-               /* Without this, mode sets may fail silently on FDI */
-               I915_WRITE(tc2reg, TRANS_AUTOTRAIN_GEN_STALL_DIS);
-               udelay(250);
-               I915_WRITE(tc2reg, 0);
                if (wait_for(I915_READ(dslreg) != temp, 5))
                        DRM_ERROR("mode set failed: pipe %d stuck\n", pipe);
        }
@@ -3303,12 +3381,17 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        /* Enable panel fitting for LVDS */
        if (dev_priv->pch_pf_size &&
-           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+           (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
+            intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
                 */
-               I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
+               if (IS_IVYBRIDGE(dev))
+                       I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
+                                                PF_PIPE_SEL_IVB(pipe));
+               else
+                       I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
                I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos);
                I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
        }
@@ -3369,7 +3452,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        is_pch_port = haswell_crtc_driving_pch(crtc);
 
        if (is_pch_port)
-               ironlake_fdi_pll_enable(intel_crtc);
+               dev_priv->display.fdi_link_train(crtc);
 
        for_each_encoder_on_crtc(dev, crtc, encoder)
                if (encoder->pre_enable)
@@ -3378,12 +3461,14 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_ddi_enable_pipe_clock(intel_crtc);
 
        /* Enable panel fitting for eDP */
-       if (dev_priv->pch_pf_size && HAS_eDP) {
+       if (dev_priv->pch_pf_size &&
+           intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP)) {
                /* Force use of hard-coded filter coefficients
                 * as some pre-programmed values are broken,
                 * e.g. x201.
                 */
-               I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
+               I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3 |
+                                        PF_PIPE_SEL_IVB(pipe));
                I915_WRITE(PF_WIN_POS(pipe), dev_priv->pch_pf_pos);
                I915_WRITE(PF_WIN_SZ(pipe), dev_priv->pch_pf_size);
        }
@@ -3401,7 +3486,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        intel_enable_plane(dev_priv, plane, pipe);
 
        if (is_pch_port)
-               ironlake_pch_enable(crtc);
+               lpt_pch_enable(crtc);
 
        mutex_lock(&dev->struct_mutex);
        intel_update_fbc(dev);
@@ -3461,7 +3546,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 
        ironlake_fdi_disable(crtc);
 
-       intel_disable_transcoder(dev_priv, pipe);
+       ironlake_disable_pch_transcoder(dev_priv, pipe);
 
        if (HAS_PCH_CPT(dev)) {
                /* disable TRANS_DP_CTL */
@@ -3546,10 +3631,8 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
                        encoder->post_disable(encoder);
 
        if (is_pch_port) {
-               ironlake_fdi_disable(crtc);
-               intel_disable_transcoder(dev_priv, pipe);
-               intel_disable_pch_pll(intel_crtc);
-               ironlake_fdi_pll_disable(intel_crtc);
+               lpt_disable_pch_transcoder(dev_priv);
+               intel_ddi_fdi_disable(crtc);
        }
 
        intel_crtc->active = false;
@@ -5726,6 +5809,8 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct intel_encoder *encoder;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
        int ret;
@@ -5736,7 +5821,19 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                                              x, y, fb);
        drm_vblank_post_modeset(dev, pipe);
 
-       return ret;
+       if (ret != 0)
+               return ret;
+
+       for_each_encoder_on_crtc(dev, crtc, encoder) {
+               DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
+                       encoder->base.base.id,
+                       drm_get_encoder_name(&encoder->base),
+                       mode->base.id, mode->name);
+               encoder_funcs = encoder->base.helper_private;
+               encoder_funcs->mode_set(&encoder->base, mode, adjusted_mode);
+       }
+
+       return 0;
 }
 
 static bool intel_eld_uptodate(struct drm_connector *connector,
@@ -6372,7 +6469,7 @@ intel_framebuffer_create_for_mode(struct drm_device *dev,
                                  int depth, int bpp)
 {
        struct drm_i915_gem_object *obj;
-       struct drm_mode_fb_cmd2 mode_cmd;
+       struct drm_mode_fb_cmd2 mode_cmd = { 0 };
 
        obj = i915_gem_alloc_object(dev,
                                    intel_framebuffer_size_for_mode(mode, bpp));
@@ -6502,24 +6599,19 @@ bool intel_get_load_detect_pipe(struct drm_connector *connector,
                DRM_DEBUG_KMS("reusing fbdev for load-detection framebuffer\n");
        if (IS_ERR(fb)) {
                DRM_DEBUG_KMS("failed to allocate framebuffer for load-detection\n");
-               goto fail;
+               return false;
        }
 
        if (!intel_set_mode(crtc, mode, 0, 0, fb)) {
                DRM_DEBUG_KMS("failed to set mode on load-detect pipe\n");
                if (old->release_fb)
                        old->release_fb->funcs->destroy(old->release_fb);
-               goto fail;
+               return false;
        }
 
        /* let the connector get through one full cycle before testing */
        intel_wait_for_vblank(dev, intel_crtc->pipe);
-
        return true;
-fail:
-       connector->encoder = NULL;
-       encoder->crtc = NULL;
-       return false;
 }
 
 void intel_release_load_detect_pipe(struct drm_connector *connector,
@@ -6806,14 +6898,19 @@ static void intel_unpin_work_fn(struct work_struct *__work)
 {
        struct intel_unpin_work *work =
                container_of(__work, struct intel_unpin_work, work);
+       struct drm_device *dev = work->crtc->dev;
 
-       mutex_lock(&work->dev->struct_mutex);
+       mutex_lock(&dev->struct_mutex);
        intel_unpin_fb_obj(work->old_fb_obj);
        drm_gem_object_unreference(&work->pending_flip_obj->base);
        drm_gem_object_unreference(&work->old_fb_obj->base);
 
-       intel_update_fbc(work->dev);
-       mutex_unlock(&work->dev->struct_mutex);
+       intel_update_fbc(dev);
+       mutex_unlock(&dev->struct_mutex);
+
+       BUG_ON(atomic_read(&to_intel_crtc(work->crtc)->unpin_work_count) == 0);
+       atomic_dec(&to_intel_crtc(work->crtc)->unpin_work_count);
+
        kfree(work);
 }
 
@@ -6861,9 +6958,9 @@ static void do_intel_finish_page_flip(struct drm_device *dev,
 
        atomic_clear_mask(1 << intel_crtc->plane,
                          &obj->pending_flip.counter);
-
        wake_up(&dev_priv->pending_flip_queue);
-       schedule_work(&work->work);
+
+       queue_work(dev_priv->wq, &work->work);
 
        trace_i915_flip_complete(intel_crtc->plane, work->pending_flip_obj);
 }
@@ -7164,7 +7261,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
                return -ENOMEM;
 
        work->event = event;
-       work->dev = crtc->dev;
+       work->crtc = crtc;
        intel_fb = to_intel_framebuffer(crtc->fb);
        work->old_fb_obj = intel_fb->obj;
        INIT_WORK(&work->work, intel_unpin_work_fn);
@@ -7189,6 +7286,9 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        intel_fb = to_intel_framebuffer(fb);
        obj = intel_fb->obj;
 
+       if (atomic_read(&intel_crtc->unpin_work_count) >= 2)
+               flush_workqueue(dev_priv->wq);
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                goto cleanup;
@@ -7207,6 +7307,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
         * the flip occurs and the object is no longer visible.
         */
        atomic_add(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
+       atomic_inc(&intel_crtc->unpin_work_count);
 
        ret = dev_priv->display.queue_flip(dev, crtc, fb, obj);
        if (ret)
@@ -7221,6 +7322,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
        return 0;
 
 cleanup_pending:
+       atomic_dec(&intel_crtc->unpin_work_count);
        atomic_sub(1 << intel_crtc->plane, &work->old_fb_obj->pending_flip);
        drm_gem_object_unreference(&work->old_fb_obj->base);
        drm_gem_object_unreference(&obj->base);
@@ -7638,8 +7740,6 @@ bool intel_set_mode(struct drm_crtc *crtc,
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_display_mode *adjusted_mode, saved_mode, saved_hwmode;
-       struct drm_encoder_helper_funcs *encoder_funcs;
-       struct drm_encoder *encoder;
        struct intel_crtc *intel_crtc;
        unsigned disable_pipes, prepare_pipes, modeset_pipes;
        bool ret = true;
@@ -7696,18 +7796,6 @@ bool intel_set_mode(struct drm_crtc *crtc,
                                           x, y, fb);
                if (!ret)
                    goto done;
-
-               list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
-
-                       if (encoder->crtc != &intel_crtc->base)
-                               continue;
-
-                       DRM_DEBUG_KMS("[ENCODER:%d:%s] set [MODE:%d:%s]\n",
-                               encoder->base.id, drm_get_encoder_name(encoder),
-                               mode->base.id, mode->name);
-                       encoder_funcs = encoder->helper_private;
-                       encoder_funcs->mode_set(encoder, mode, adjusted_mode);
-               }
        }
 
        /* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@ -8184,17 +8272,9 @@ static void intel_setup_outputs(struct drm_device *dev)
                I915_WRITE(PFIT_CONTROL, 0);
        }
 
-       if (HAS_PCH_SPLIT(dev)) {
-               dpd_is_edp = intel_dpd_is_edp(dev);
-
-               if (has_edp_a(dev))
-                       intel_dp_init(dev, DP_A, PORT_A);
-
-               if (dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
-                       intel_dp_init(dev, PCH_DP_D, PORT_D);
-       }
-
-       intel_crt_init(dev);
+       if (!(IS_HASWELL(dev) &&
+             (I915_READ(DDI_BUF_CTL(PORT_A)) & DDI_A_4_LANES)))
+               intel_crt_init(dev);
 
        if (IS_HASWELL(dev)) {
                int found;
@@ -8217,6 +8297,10 @@ static void intel_setup_outputs(struct drm_device *dev)
                        intel_ddi_init(dev, PORT_D);
        } else if (HAS_PCH_SPLIT(dev)) {
                int found;
+               dpd_is_edp = intel_dpd_is_edp(dev);
+
+               if (has_edp_a(dev))
+                       intel_dp_init(dev, DP_A, PORT_A);
 
                if (I915_READ(HDMIB) & PORT_DETECTED) {
                        /* PCH SDVOB multiplex with HDMIB */
@@ -8236,7 +8320,7 @@ static void intel_setup_outputs(struct drm_device *dev)
                if (I915_READ(PCH_DP_C) & DP_DETECTED)
                        intel_dp_init(dev, PCH_DP_C, PORT_C);
 
-               if (!dpd_is_edp && (I915_READ(PCH_DP_D) & DP_DETECTED))
+               if (I915_READ(PCH_DP_D) & DP_DETECTED)
                        intel_dp_init(dev, PCH_DP_D, PORT_D);
        } else if (IS_VALLEYVIEW(dev)) {
                int found;
@@ -8312,6 +8396,8 @@ static void intel_setup_outputs(struct drm_device *dev)
 
        if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
                ironlake_init_pch_refclk(dev);
+
+       drm_helper_move_panel_connectors_to_head(dev);
 }
 
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -8393,6 +8479,10 @@ int intel_framebuffer_init(struct drm_device *dev,
                return -EINVAL;
        }
 
+       /* FIXME need to adjust LINOFF/TILEOFF accordingly. */
+       if (mode_cmd->offsets[0] != 0)
+               return -EINVAL;
+
        ret = drm_framebuffer_init(dev, &intel_fb->base, &intel_fb_funcs);
        if (ret) {
                DRM_ERROR("framebuffer init failed %d\n", ret);
@@ -8565,6 +8655,34 @@ struct intel_quirk {
        void (*hook)(struct drm_device *dev);
 };
 
+/* For systems that don't have a meaningful PCI subdevice/subvendor ID */
+struct intel_dmi_quirk {
+       void (*hook)(struct drm_device *dev);
+       const struct dmi_system_id (*dmi_id_list)[];
+};
+
+static int intel_dmi_reverse_brightness(const struct dmi_system_id *id)
+{
+       DRM_INFO("Backlight polarity reversed on %s\n", id->ident);
+       return 1;
+}
+
+static const struct intel_dmi_quirk intel_dmi_quirks[] = {
+       {
+               .dmi_id_list = &(const struct dmi_system_id[]) {
+                       {
+                               .callback = intel_dmi_reverse_brightness,
+                               .ident = "NCR Corporation",
+                               .matches = {DMI_MATCH(DMI_SYS_VENDOR, "NCR Corporation"),
+                                           DMI_MATCH(DMI_PRODUCT_NAME, ""),
+                               },
+                       },
+                       { }  /* terminating entry */
+               },
+               .hook = quirk_invert_brightness,
+       },
+};
+
 static struct intel_quirk intel_quirks[] = {
        /* HP Mini needs pipe A force quirk (LP: #322104) */
        { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
@@ -8604,6 +8722,10 @@ static void intel_init_quirks(struct drm_device *dev)
                     q->subsystem_device == PCI_ANY_ID))
                        q->hook(dev);
        }
+       for (i = 0; i < ARRAY_SIZE(intel_dmi_quirks); i++) {
+               if (dmi_check_system(*intel_dmi_quirks[i].dmi_id_list) != 0)
+                       intel_dmi_quirks[i].hook(dev);
+       }
 }
 
 /* Disable the VGA plane that we never use */