]> 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 a5be34664299dea144f98024390d48cfbc359267..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+ */
        }
@@ -1836,8 +1892,10 @@ static void intel_disable_pipe(struct drm_i915_private *dev_priv,
 void intel_flush_display_plane(struct drm_i915_private *dev_priv,
                                      enum plane plane)
 {
-       I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
-       I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane)));
+       if (dev_priv->info->gen >= 4)
+               I915_WRITE(DSPSURF(plane), I915_READ(DSPSURF(plane)));
+       else
+               I915_WRITE(DSPADDR(plane), I915_READ(DSPADDR(plane)));
 }
 
 /**
@@ -1955,9 +2013,9 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
 
 /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
  * is assumed to be a power-of-two. */
-static unsigned long gen4_compute_dspaddr_offset_xtiled(int *x, int *y,
-                                                       unsigned int bpp,
-                                                       unsigned int pitch)
+unsigned long intel_gen4_compute_offset_xtiled(int *x, int *y,
+                                              unsigned int bpp,
+                                              unsigned int pitch)
 {
        int tile_rows, tiles;
 
@@ -1998,24 +2056,38 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        dspcntr = I915_READ(reg);
        /* Mask out pixel format bits in case we change it */
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
-       switch (fb->bits_per_pixel) {
-       case 8:
+       switch (fb->pixel_format) {
+       case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
                break;
-       case 16:
-               if (fb->depth == 15)
-                       dspcntr |= DISPPLANE_15_16BPP;
-               else
-                       dspcntr |= DISPPLANE_16BPP;
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_ARGB1555:
+               dspcntr |= DISPPLANE_BGRX555;
                break;
-       case 24:
-       case 32:
-               dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
+       case DRM_FORMAT_RGB565:
+               dspcntr |= DISPPLANE_BGRX565;
+               break;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               dspcntr |= DISPPLANE_BGRX888;
+               break;
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
+               dspcntr |= DISPPLANE_RGBX888;
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+               dspcntr |= DISPPLANE_BGRX101010;
+               break;
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_ABGR2101010:
+               dspcntr |= DISPPLANE_RGBX101010;
                break;
        default:
-               DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
+               DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
                return -EINVAL;
        }
+
        if (INTEL_INFO(dev)->gen >= 4) {
                if (obj->tiling_mode != I915_TILING_NONE)
                        dspcntr |= DISPPLANE_TILED;
@@ -2029,9 +2101,9 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
 
        if (INTEL_INFO(dev)->gen >= 4) {
                intel_crtc->dspaddr_offset =
-                       gen4_compute_dspaddr_offset_xtiled(&x, &y,
-                                                          fb->bits_per_pixel / 8,
-                                                          fb->pitches[0]);
+                       intel_gen4_compute_offset_xtiled(&x, &y,
+                                                        fb->bits_per_pixel / 8,
+                                                        fb->pitches[0]);
                linear_offset -= intel_crtc->dspaddr_offset;
        } else {
                intel_crtc->dspaddr_offset = linear_offset;
@@ -2082,27 +2154,31 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        dspcntr = I915_READ(reg);
        /* Mask out pixel format bits in case we change it */
        dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
-       switch (fb->bits_per_pixel) {
-       case 8:
+       switch (fb->pixel_format) {
+       case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
                break;
-       case 16:
-               if (fb->depth != 16)
-                       return -EINVAL;
-
-               dspcntr |= DISPPLANE_16BPP;
+       case DRM_FORMAT_RGB565:
+               dspcntr |= DISPPLANE_BGRX565;
                break;
-       case 24:
-       case 32:
-               if (fb->depth == 24)
-                       dspcntr |= DISPPLANE_32BPP_NO_ALPHA;
-               else if (fb->depth == 30)
-                       dspcntr |= DISPPLANE_32BPP_30BIT_NO_ALPHA;
-               else
-                       return -EINVAL;
+       case DRM_FORMAT_XRGB8888:
+       case DRM_FORMAT_ARGB8888:
+               dspcntr |= DISPPLANE_BGRX888;
+               break;
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
+               dspcntr |= DISPPLANE_RGBX888;
+               break;
+       case DRM_FORMAT_XRGB2101010:
+       case DRM_FORMAT_ARGB2101010:
+               dspcntr |= DISPPLANE_BGRX101010;
+               break;
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_ABGR2101010:
+               dspcntr |= DISPPLANE_RGBX101010;
                break;
        default:
-               DRM_ERROR("Unknown color depth %d\n", fb->bits_per_pixel);
+               DRM_ERROR("Unknown pixel format 0x%08x\n", fb->pixel_format);
                return -EINVAL;
        }
 
@@ -2118,9 +2194,9 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
 
        linear_offset = y * fb->pitches[0] + x * (fb->bits_per_pixel / 8);
        intel_crtc->dspaddr_offset =
-               gen4_compute_dspaddr_offset_xtiled(&x, &y,
-                                                  fb->bits_per_pixel / 8,
-                                                  fb->pitches[0]);
+               intel_gen4_compute_offset_xtiled(&x, &y,
+                                                fb->bits_per_pixel / 8,
+                                                fb->pitches[0]);
        linear_offset -= intel_crtc->dspaddr_offset;
 
        DRM_DEBUG_KMS("Writing base %08X %08lX %d %d %d\n",
@@ -2128,8 +2204,12 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        I915_MODIFY_DISPBASE(DSPSURF(plane),
                             obj->gtt_offset + intel_crtc->dspaddr_offset);
-       I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
-       I915_WRITE(DSPLINOFF(plane), linear_offset);
+       if (IS_HASWELL(dev)) {
+               I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
+       } else {
+               I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
+               I915_WRITE(DSPLINOFF(plane), linear_offset);
+       }
        POSTING_READ(reg);
 
        return 0;
@@ -2177,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;
@@ -2235,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;
 }
@@ -2343,6 +2436,29 @@ static void cpt_phase_pointer_enable(struct drm_device *dev, int pipe)
        POSTING_READ(SOUTH_CHICKEN1);
 }
 
+static void ivb_modeset_global_resources(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *pipe_B_crtc =
+               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
+       struct intel_crtc *pipe_C_crtc =
+               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_C]);
+       uint32_t temp;
+
+       /* When everything is off disable fdi C so that we could enable fdi B
+        * with all lanes. XXX: This misses the case where a pipe is not using
+        * any pch resources and so doesn't need any fdi lanes. */
+       if (!pipe_B_crtc->base.enabled && !pipe_C_crtc->base.enabled) {
+               WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
+               WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
+
+               temp = I915_READ(SOUTH_CHICKEN1);
+               temp &= ~FDI_BC_BIFURCATION_SELECT;
+               DRM_DEBUG_KMS("disabling fdi C rx\n");
+               I915_WRITE(SOUTH_CHICKEN1, temp);
+       }
+}
+
 /* The FDI link training functions for ILK/Ibexpeak. */
 static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 {
@@ -2386,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++) {
@@ -2479,6 +2593,9 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
        I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
+       I915_WRITE(FDI_RX_MISC(pipe),
+                  FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
+
        reg = FDI_RX_CTL(pipe);
        temp = I915_READ(reg);
        if (HAS_PCH_CPT(dev)) {
@@ -2493,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);
@@ -2599,6 +2715,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
+       DRM_DEBUG_KMS("FDI_RX_IIR before link train 0x%x\n",
+                     I915_READ(FDI_RX_IIR(pipe)));
+
        /* enable CPU FDI TX and PCH FDI RX */
        reg = FDI_TX_CTL(pipe);
        temp = I915_READ(reg);
@@ -2611,6 +2730,9 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        temp |= FDI_COMPOSITE_SYNC;
        I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
+       I915_WRITE(FDI_RX_MISC(pipe),
+                  FDI_RX_TP1_TO_TP2_48 | FDI_RX_FDI_DELAY_90);
+
        reg = FDI_RX_CTL(pipe);
        temp = I915_READ(reg);
        temp &= ~FDI_LINK_TRAIN_AUTO;
@@ -2622,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);
@@ -2642,7 +2763,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
                if (temp & FDI_RX_BIT_LOCK ||
                    (I915_READ(reg) & FDI_RX_BIT_LOCK)) {
                        I915_WRITE(reg, temp | FDI_RX_BIT_LOCK);
-                       DRM_DEBUG_KMS("FDI train 1 done.\n");
+                       DRM_DEBUG_KMS("FDI train 1 done, level %i.\n", i);
                        break;
                }
        }
@@ -2683,7 +2804,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
 
                if (temp & FDI_RX_SYMBOL_LOCK) {
                        I915_WRITE(reg, temp | FDI_RX_SYMBOL_LOCK);
-                       DRM_DEBUG_KMS("FDI train 2 done.\n");
+                       DRM_DEBUG_KMS("FDI train 2 done, level %i.\n", i);
                        break;
                }
        }
@@ -2700,9 +2821,6 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
        int pipe = intel_crtc->pipe;
        u32 reg, temp;
 
-       /* Write the TU size bits so error detection works */
-       I915_WRITE(FDI_RX_TUSIZE1(pipe),
-                  I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
 
        /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
        reg = FDI_RX_CTL(pipe);
@@ -2803,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);
        }
@@ -3003,15 +3118,24 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
 
        assert_transcoder_disabled(dev_priv, pipe);
 
+       /* Write the TU size bits before fdi link training, so that error
+        * detection works. */
+       I915_WRITE(FDI_RX_TUSIZE1(pipe),
+                  I915_READ(PIPE_DATA_M1(pipe)) & TU_SIZE_MASK);
+
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc);
 
-       intel_enable_pch_pll(intel_crtc);
+       /* XXX: pch pll's can be enabled any time before we enable the PCH
+        * transcoder, and we actually should do this to not upset any PCH
+        * transcoder that already use the clock when we share it.
+        *
+        * 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. */
+       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);
@@ -3048,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) &&
@@ -3081,15 +3204,37 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
                        temp |= TRANS_DP_PORT_SEL_D;
                        break;
                default:
-                       DRM_DEBUG_KMS("Wrong PCH DP port return. Guess port B\n");
-                       temp |= TRANS_DP_PORT_SEL_B;
-                       break;
+                       BUG();
                }
 
                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)
@@ -3182,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);
        }
@@ -3225,6 +3366,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        is_pch_port = ironlake_crtc_driving_pch(crtc);
 
        if (is_pch_port) {
+               /* Note: FDI PLL enabling _must_ be done before we enable the
+                * cpu pipes, hence this is separate from all the other fdi/pch
+                * enabling. */
                ironlake_fdi_pll_enable(intel_crtc);
        } else {
                assert_fdi_tx_disabled(dev_priv, pipe);
@@ -3237,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);
        }
@@ -3303,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)
@@ -3312,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);
        }
@@ -3335,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);
@@ -3395,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 */
@@ -3480,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;
@@ -4997,6 +5146,88 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
        return true;
 }
 
+static void cpt_enable_fdi_bc_bifurcation(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t temp;
+
+       temp = I915_READ(SOUTH_CHICKEN1);
+       if (temp & FDI_BC_BIFURCATION_SELECT)
+               return;
+
+       WARN_ON(I915_READ(FDI_RX_CTL(PIPE_B)) & FDI_RX_ENABLE);
+       WARN_ON(I915_READ(FDI_RX_CTL(PIPE_C)) & FDI_RX_ENABLE);
+
+       temp |= FDI_BC_BIFURCATION_SELECT;
+       DRM_DEBUG_KMS("enabling fdi C rx\n");
+       I915_WRITE(SOUTH_CHICKEN1, temp);
+       POSTING_READ(SOUTH_CHICKEN1);
+}
+
+static bool ironlake_check_fdi_lanes(struct intel_crtc *intel_crtc)
+{
+       struct drm_device *dev = intel_crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *pipe_B_crtc =
+               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[PIPE_B]);
+
+       DRM_DEBUG_KMS("checking fdi config on pipe %i, lanes %i\n",
+                     intel_crtc->pipe, intel_crtc->fdi_lanes);
+       if (intel_crtc->fdi_lanes > 4) {
+               DRM_DEBUG_KMS("invalid fdi lane config on pipe %i: %i lanes\n",
+                             intel_crtc->pipe, intel_crtc->fdi_lanes);
+               /* Clamp lanes to avoid programming the hw with bogus values. */
+               intel_crtc->fdi_lanes = 4;
+
+               return false;
+       }
+
+       if (dev_priv->num_pipe == 2)
+               return true;
+
+       switch (intel_crtc->pipe) {
+       case PIPE_A:
+               return true;
+       case PIPE_B:
+               if (dev_priv->pipe_to_crtc_mapping[PIPE_C]->enabled &&
+                   intel_crtc->fdi_lanes > 2) {
+                       DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n",
+                                     intel_crtc->pipe, intel_crtc->fdi_lanes);
+                       /* Clamp lanes to avoid programming the hw with bogus values. */
+                       intel_crtc->fdi_lanes = 2;
+
+                       return false;
+               }
+
+               if (intel_crtc->fdi_lanes > 2)
+                       WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT);
+               else
+                       cpt_enable_fdi_bc_bifurcation(dev);
+
+               return true;
+       case PIPE_C:
+               if (!pipe_B_crtc->base.enabled || pipe_B_crtc->fdi_lanes <= 2) {
+                       if (intel_crtc->fdi_lanes > 2) {
+                               DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %i: %i lanes\n",
+                                             intel_crtc->pipe, intel_crtc->fdi_lanes);
+                               /* Clamp lanes to avoid programming the hw with bogus values. */
+                               intel_crtc->fdi_lanes = 2;
+
+                               return false;
+                       }
+               } else {
+                       DRM_DEBUG_KMS("fdi link B uses too many lanes to enable link C\n");
+                       return false;
+               }
+
+               cpt_enable_fdi_bc_bifurcation(dev);
+
+               return true;
+       default:
+               BUG();
+       }
+}
+
 static void ironlake_set_m_n(struct drm_crtc *crtc,
                             struct drm_display_mode *mode,
                             struct drm_display_mode *adjusted_mode)
@@ -5195,7 +5426,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        struct intel_encoder *encoder;
        u32 temp;
        int ret;
-       bool dither;
+       bool dither, fdi_config_ok;
 
        for_each_encoder_on_crtc(dev, crtc, encoder) {
                switch (encoder->type) {
@@ -5229,7 +5460,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        intel_crtc_update_cursor(crtc, true);
 
        /* determine panel color depth */
-       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode);
+       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
+                                             adjusted_mode);
        if (is_lvds && dev_priv->lvds_dither)
                dither = true;
 
@@ -5332,8 +5564,12 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_set_pipe_timings(intel_crtc, mode, adjusted_mode);
 
+       /* Note, this also computes intel_crtc->fdi_lanes which is used below in
+        * ironlake_check_fdi_lanes. */
        ironlake_set_m_n(crtc, mode, adjusted_mode);
 
+       fdi_config_ok = ironlake_check_fdi_lanes(intel_crtc);
+
        if (is_cpu_edp)
                ironlake_set_pll_edp(crtc, adjusted_mode->clock);
 
@@ -5351,7 +5587,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
        intel_update_linetime_watermarks(dev, pipe, adjusted_mode);
 
-       return ret;
+       return fdi_config_ok ? ret : -EINVAL;
 }
 
 static int haswell_crtc_mode_set(struct drm_crtc *crtc,
@@ -5427,7 +5663,8 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        intel_crtc_update_cursor(crtc, true);
 
        /* determine panel color depth */
-       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp, mode);
+       dither = intel_choose_pipe_bpp_dither(crtc, fb, &intel_crtc->bpp,
+                                             adjusted_mode);
        if (is_lvds && dev_priv->lvds_dither)
                dither = true;
 
@@ -5572,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;
@@ -5582,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,
@@ -6218,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));
@@ -6348,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,
@@ -6652,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);
 }
 
@@ -6707,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);
 }
@@ -7010,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);
@@ -7035,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;
@@ -7053,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)
@@ -7067,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);
@@ -7484,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;
@@ -7530,6 +7784,9 @@ bool intel_set_mode(struct drm_crtc *crtc,
         * update the the output configuration. */
        intel_modeset_update_state(dev, prepare_pipes);
 
+       if (dev_priv->display.modeset_global_resources)
+               dev_priv->display.modeset_global_resources(dev);
+
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
         */
@@ -7539,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. */
@@ -8027,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;
@@ -8060,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 */
@@ -8079,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;
@@ -8155,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)
@@ -8195,27 +8438,51 @@ int intel_framebuffer_init(struct drm_device *dev,
        if (mode_cmd->pitches[0] & 63)
                return -EINVAL;
 
+       /* FIXME <= Gen4 stride limits are bit unclear */
+       if (mode_cmd->pitches[0] > 32768)
+               return -EINVAL;
+
+       if (obj->tiling_mode != I915_TILING_NONE &&
+           mode_cmd->pitches[0] != obj->stride)
+               return -EINVAL;
+
+       /* Reject formats not supported by any plane early. */
        switch (mode_cmd->pixel_format) {
-       case DRM_FORMAT_RGB332:
+       case DRM_FORMAT_C8:
        case DRM_FORMAT_RGB565:
        case DRM_FORMAT_XRGB8888:
-       case DRM_FORMAT_XBGR8888:
        case DRM_FORMAT_ARGB8888:
+               break;
+       case DRM_FORMAT_XRGB1555:
+       case DRM_FORMAT_ARGB1555:
+               if (INTEL_INFO(dev)->gen > 3)
+                       return -EINVAL;
+               break;
+       case DRM_FORMAT_XBGR8888:
+       case DRM_FORMAT_ABGR8888:
        case DRM_FORMAT_XRGB2101010:
        case DRM_FORMAT_ARGB2101010:
-               /* RGB formats are common across chipsets */
+       case DRM_FORMAT_XBGR2101010:
+       case DRM_FORMAT_ABGR2101010:
+               if (INTEL_INFO(dev)->gen < 4)
+                       return -EINVAL;
                break;
        case DRM_FORMAT_YUYV:
        case DRM_FORMAT_UYVY:
        case DRM_FORMAT_YVYU:
        case DRM_FORMAT_VYUY:
+               if (INTEL_INFO(dev)->gen < 6)
+                       return -EINVAL;
                break;
        default:
-               DRM_DEBUG_KMS("unsupported pixel format %u\n",
-                               mode_cmd->pixel_format);
+               DRM_DEBUG_KMS("unsupported pixel format 0x%08x\n", mode_cmd->pixel_format);
                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);
@@ -8310,6 +8577,8 @@ static void intel_init_display(struct drm_device *dev)
                        /* FIXME: detect B0+ stepping and use auto training */
                        dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
                        dev_priv->display.write_eld = ironlake_write_eld;
+                       dev_priv->display.modeset_global_resources =
+                               ivb_modeset_global_resources;
                } else if (IS_HASWELL(dev)) {
                        dev_priv->display.fdi_link_train = hsw_fdi_link_train;
                        dev_priv->display.write_eld = haswell_write_eld;
@@ -8386,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 },
@@ -8425,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 */