Merge branch 'drm-nouveau-fixes' of git://git.freedesktop.org/git/nouveau/linux-2...
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_display.c
index 04411ad..981b1f1 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/kernel.h>
 #include <linux/slab.h>
 #include <linux/vgaarb.h>
+#include <drm/drm_edid.h>
 #include "drmP.h"
 #include "intel_drv.h"
 #include "i915_drm.h"
 
 #define HAS_eDP (intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))
 
-bool intel_pipe_has_type (struct drm_crtc *crtc, int type);
+bool intel_pipe_has_type(struct drm_crtc *crtc, int type);
 static void intel_update_watermarks(struct drm_device *dev);
 static void intel_increase_pllclock(struct drm_crtc *crtc);
 static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
 
 typedef struct {
-    /* given values */
-    int n;
-    int m1, m2;
-    int p1, p2;
-    /* derived values */
-    int        dot;
-    int        vco;
-    int        m;
-    int        p;
+       /* given values */
+       int n;
+       int m1, m2;
+       int p1, p2;
+       /* derived values */
+       int     dot;
+       int     vco;
+       int     m;
+       int     p;
 } intel_clock_t;
 
 typedef struct {
-    int        min, max;
+       int     min, max;
 } intel_range_t;
 
 typedef struct {
-    int        dot_limit;
-    int        p2_slow, p2_fast;
+       int     dot_limit;
+       int     p2_slow, p2_fast;
 } intel_p2_t;
 
 #define INTEL_P2_NUM                 2
 typedef struct intel_limit intel_limit_t;
 struct intel_limit {
-    intel_range_t   dot, vco, n, m, m1, m2, p, p1;
-    intel_p2_t     p2;
-    bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
-                     int, int, intel_clock_t *);
+       intel_range_t   dot, vco, n, m, m1, m2, p, p1;
+       intel_p2_t          p2;
+       bool (* find_pll)(const intel_limit_t *, struct drm_crtc *,
+                       int, int, intel_clock_t *);
 };
 
 /* FDI */
@@ -105,56 +106,56 @@ intel_fdi_link_freq(struct drm_device *dev)
 }
 
 static const intel_limit_t intel_limits_i8xx_dvo = {
-        .dot = { .min = 25000, .max = 350000 },
-        .vco = { .min = 930000, .max = 1400000 },
-        .n = { .min = 3, .max = 16 },
-        .m = { .min = 96, .max = 140 },
-        .m1 = { .min = 18, .max = 26 },
-        .m2 = { .min = 6, .max = 16 },
-        .p = { .min = 4, .max = 128 },
-        .p1 = { .min = 2, .max = 33 },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 930000, .max = 1400000 },
+       .n = { .min = 3, .max = 16 },
+       .m = { .min = 96, .max = 140 },
+       .m1 = { .min = 18, .max = 26 },
+       .m2 = { .min = 6, .max = 16 },
+       .p = { .min = 4, .max = 128 },
+       .p1 = { .min = 2, .max = 33 },
        .p2 = { .dot_limit = 165000,
                .p2_slow = 4, .p2_fast = 2 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
-        .dot = { .min = 25000, .max = 350000 },
-        .vco = { .min = 930000, .max = 1400000 },
-        .n = { .min = 3, .max = 16 },
-        .m = { .min = 96, .max = 140 },
-        .m1 = { .min = 18, .max = 26 },
-        .m2 = { .min = 6, .max = 16 },
-        .p = { .min = 4, .max = 128 },
-        .p1 = { .min = 1, .max = 6 },
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 930000, .max = 1400000 },
+       .n = { .min = 3, .max = 16 },
+       .m = { .min = 96, .max = 140 },
+       .m1 = { .min = 18, .max = 26 },
+       .m2 = { .min = 6, .max = 16 },
+       .p = { .min = 4, .max = 128 },
+       .p1 = { .min = 1, .max = 6 },
        .p2 = { .dot_limit = 165000,
                .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_sdvo = {
-        .dot = { .min = 20000, .max = 400000 },
-        .vco = { .min = 1400000, .max = 2800000 },
-        .n = { .min = 1, .max = 6 },
-        .m = { .min = 70, .max = 120 },
-        .m1 = { .min = 10, .max = 22 },
-        .m2 = { .min = 5, .max = 9 },
-        .p = { .min = 5, .max = 80 },
-        .p1 = { .min = 1, .max = 8 },
+       .dot = { .min = 20000, .max = 400000 },
+       .vco = { .min = 1400000, .max = 2800000 },
+       .n = { .min = 1, .max = 6 },
+       .m = { .min = 70, .max = 120 },
+       .m1 = { .min = 10, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8 },
        .p2 = { .dot_limit = 200000,
                .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_i9xx_lvds = {
-        .dot = { .min = 20000, .max = 400000 },
-        .vco = { .min = 1400000, .max = 2800000 },
-        .n = { .min = 1, .max = 6 },
-        .m = { .min = 70, .max = 120 },
-        .m1 = { .min = 10, .max = 22 },
-        .m2 = { .min = 5, .max = 9 },
-        .p = { .min = 7, .max = 98 },
-        .p1 = { .min = 1, .max = 8 },
+       .dot = { .min = 20000, .max = 400000 },
+       .vco = { .min = 1400000, .max = 2800000 },
+       .n = { .min = 1, .max = 6 },
+       .m = { .min = 70, .max = 120 },
+       .m1 = { .min = 10, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 7, .max = 98 },
+       .p1 = { .min = 1, .max = 8 },
        .p2 = { .dot_limit = 112000,
                .p2_slow = 14, .p2_fast = 7 },
        .find_pll = intel_find_best_PLL,
@@ -222,44 +223,44 @@ static const intel_limit_t intel_limits_g4x_dual_channel_lvds = {
 };
 
 static const intel_limit_t intel_limits_g4x_display_port = {
-        .dot = { .min = 161670, .max = 227000 },
-        .vco = { .min = 1750000, .max = 3500000},
-        .n = { .min = 1, .max = 2 },
-        .m = { .min = 97, .max = 108 },
-        .m1 = { .min = 0x10, .max = 0x12 },
-        .m2 = { .min = 0x05, .max = 0x06 },
-        .p = { .min = 10, .max = 20 },
-        .p1 = { .min = 1, .max = 2},
-        .p2 = { .dot_limit = 0,
+       .dot = { .min = 161670, .max = 227000 },
+       .vco = { .min = 1750000, .max = 3500000},
+       .n = { .min = 1, .max = 2 },
+       .m = { .min = 97, .max = 108 },
+       .m1 = { .min = 0x10, .max = 0x12 },
+       .m2 = { .min = 0x05, .max = 0x06 },
+       .p = { .min = 10, .max = 20 },
+       .p1 = { .min = 1, .max = 2},
+       .p2 = { .dot_limit = 0,
                .p2_slow = 10, .p2_fast = 10 },
-        .find_pll = intel_find_pll_g4x_dp,
+       .find_pll = intel_find_pll_g4x_dp,
 };
 
 static const intel_limit_t intel_limits_pineview_sdvo = {
-        .dot = { .min = 20000, .max = 400000},
-        .vco = { .min = 1700000, .max = 3500000 },
+       .dot = { .min = 20000, .max = 400000},
+       .vco = { .min = 1700000, .max = 3500000 },
        /* Pineview's Ncounter is a ring counter */
-        .n = { .min = 3, .max = 6 },
-        .m = { .min = 2, .max = 256 },
+       .n = { .min = 3, .max = 6 },
+       .m = { .min = 2, .max = 256 },
        /* Pineview only has one combined m divider, which we treat as m2. */
-        .m1 = { .min = 0, .max = 0 },
-        .m2 = { .min = 0, .max = 254 },
-        .p = { .min = 5, .max = 80 },
-        .p1 = { .min = 1, .max = 8 },
+       .m1 = { .min = 0, .max = 0 },
+       .m2 = { .min = 0, .max = 254 },
+       .p = { .min = 5, .max = 80 },
+       .p1 = { .min = 1, .max = 8 },
        .p2 = { .dot_limit = 200000,
                .p2_slow = 10, .p2_fast = 5 },
        .find_pll = intel_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_pineview_lvds = {
-        .dot = { .min = 20000, .max = 400000 },
-        .vco = { .min = 1700000, .max = 3500000 },
-        .n = { .min = 3, .max = 6 },
-        .m = { .min = 2, .max = 256 },
-        .m1 = { .min = 0, .max = 0 },
-        .m2 = { .min = 0, .max = 254 },
-        .p = { .min = 7, .max = 112 },
-        .p1 = { .min = 1, .max = 8 },
+       .dot = { .min = 20000, .max = 400000 },
+       .vco = { .min = 1700000, .max = 3500000 },
+       .n = { .min = 3, .max = 6 },
+       .m = { .min = 2, .max = 256 },
+       .m1 = { .min = 0, .max = 0 },
+       .m2 = { .min = 0, .max = 254 },
+       .p = { .min = 7, .max = 112 },
+       .p1 = { .min = 1, .max = 8 },
        .p2 = { .dot_limit = 112000,
                .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_find_best_PLL,
@@ -321,7 +322,7 @@ static const intel_limit_t intel_limits_ironlake_single_lvds_100m = {
        .m1 = { .min = 12, .max = 22 },
        .m2 = { .min = 5, .max = 9 },
        .p = { .min = 28, .max = 112 },
-       .p1 = { .min = 2,.max = 8 },
+       .p1 = { .min = 2, .max = 8 },
        .p2 = { .dot_limit = 225000,
                .p2_slow = 14, .p2_fast = 14 },
        .find_pll = intel_g4x_find_best_PLL,
@@ -335,24 +336,24 @@ static const intel_limit_t intel_limits_ironlake_dual_lvds_100m = {
        .m1 = { .min = 12, .max = 22 },
        .m2 = { .min = 5, .max = 9 },
        .p = { .min = 14, .max = 42 },
-       .p1 = { .min = 2,.max = 6 },
+       .p1 = { .min = 2, .max = 6 },
        .p2 = { .dot_limit = 225000,
                .p2_slow = 7, .p2_fast = 7 },
        .find_pll = intel_g4x_find_best_PLL,
 };
 
 static const intel_limit_t intel_limits_ironlake_display_port = {
-        .dot = { .min = 25000, .max = 350000 },
-        .vco = { .min = 1760000, .max = 3510000},
-        .n = { .min = 1, .max = 2 },
-        .m = { .min = 81, .max = 90 },
-        .m1 = { .min = 12, .max = 22 },
-        .m2 = { .min = 5, .max = 9 },
-        .p = { .min = 10, .max = 20 },
-        .p1 = { .min = 1, .max = 2},
-        .p2 = { .dot_limit = 0,
+       .dot = { .min = 25000, .max = 350000 },
+       .vco = { .min = 1760000, .max = 3510000},
+       .n = { .min = 1, .max = 2 },
+       .m = { .min = 81, .max = 90 },
+       .m1 = { .min = 12, .max = 22 },
+       .m2 = { .min = 5, .max = 9 },
+       .p = { .min = 10, .max = 20 },
+       .p1 = { .min = 1, .max = 2},
+       .p2 = { .dot_limit = 0,
                .p2_slow = 10, .p2_fast = 10 },
-        .find_pll = intel_find_pll_ironlake_dp,
+       .find_pll = intel_find_pll_ironlake_dp,
 };
 
 static const intel_limit_t *intel_ironlake_limit(struct drm_crtc *crtc,
@@ -404,7 +405,7 @@ static const intel_limit_t *intel_g4x_limit(struct drm_crtc *crtc)
                limit = &intel_limits_g4x_hdmi;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_SDVO)) {
                limit = &intel_limits_g4x_sdvo;
-       } else if (intel_pipe_has_type (crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+       } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
                limit = &intel_limits_g4x_display_port;
        } else /* The option is for other outputs */
                limit = &intel_limits_i9xx_sdvo;
@@ -488,26 +489,26 @@ static bool intel_PLL_is_valid(struct drm_device *dev,
                               const intel_clock_t *clock)
 {
        if (clock->p1  < limit->p1.min  || limit->p1.max  < clock->p1)
-               INTELPllInvalid ("p1 out of range\n");
+               INTELPllInvalid("p1 out of range\n");
        if (clock->p   < limit->p.min   || limit->p.max   < clock->p)
-               INTELPllInvalid ("p out of range\n");
+               INTELPllInvalid("p out of range\n");
        if (clock->m2  < limit->m2.min  || limit->m2.max  < clock->m2)
-               INTELPllInvalid ("m2 out of range\n");
+               INTELPllInvalid("m2 out of range\n");
        if (clock->m1  < limit->m1.min  || limit->m1.max  < clock->m1)
-               INTELPllInvalid ("m1 out of range\n");
+               INTELPllInvalid("m1 out of range\n");
        if (clock->m1 <= clock->m2 && !IS_PINEVIEW(dev))
-               INTELPllInvalid ("m1 <= m2\n");
+               INTELPllInvalid("m1 <= m2\n");
        if (clock->m   < limit->m.min   || limit->m.max   < clock->m)
-               INTELPllInvalid ("m out of range\n");
+               INTELPllInvalid("m out of range\n");
        if (clock->n   < limit->n.min   || limit->n.max   < clock->n)
-               INTELPllInvalid ("n out of range\n");
+               INTELPllInvalid("n out of range\n");
        if (clock->vco < limit->vco.min || limit->vco.max < clock->vco)
-               INTELPllInvalid ("vco out of range\n");
+               INTELPllInvalid("vco out of range\n");
        /* XXX: We may need to be checking "Dot clock" depending on the multiplier,
         * connector, etc., rather than just a single range.
         */
        if (clock->dot < limit->dot.min || limit->dot.max < clock->dot)
-               INTELPllInvalid ("dot out of range\n");
+               INTELPllInvalid("dot out of range\n");
 
        return true;
 }
@@ -542,7 +543,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
                        clock.p2 = limit->p2.p2_fast;
        }
 
-       memset (best_clock, 0, sizeof (*best_clock));
+       memset(best_clock, 0, sizeof(*best_clock));
 
        for (clock.m1 = limit->m1.min; clock.m1 <= limit->m1.max;
             clock.m1++) {
@@ -802,6 +803,19 @@ static void assert_pch_pll(struct drm_i915_private *dev_priv,
        u32 val;
        bool cur_state;
 
+       if (HAS_PCH_CPT(dev_priv->dev)) {
+               u32 pch_dpll;
+
+               pch_dpll = I915_READ(PCH_DPLL_SEL);
+
+               /* Make sure the selected PLL is enabled to the transcoder */
+               WARN(!((pch_dpll >> (4 * pipe)) & 8),
+                    "transcoder %d PLL not enabled\n", pipe);
+
+               /* Convert the transcoder pipe number to a pll pipe number */
+               pipe = (pch_dpll >> (4 * pipe)) & 1;
+       }
+
        reg = PCH_DPLL(pipe);
        val = I915_READ(reg);
        cur_state = !!(val & DPLL_VCO_ENABLE);
@@ -1171,6 +1185,9 @@ static void intel_enable_pch_pll(struct drm_i915_private *dev_priv,
        int reg;
        u32 val;
 
+       if (pipe > 1)
+               return;
+
        /* PCH only available on ILK+ */
        BUG_ON(dev_priv->info->gen < 5);
 
@@ -1191,6 +1208,9 @@ static void intel_disable_pch_pll(struct drm_i915_private *dev_priv,
        int reg;
        u32 val;
 
+       if (pipe > 1)
+               return;
+
        /* PCH only available on ILK+ */
        BUG_ON(dev_priv->info->gen < 5);
 
@@ -1256,7 +1276,7 @@ static void intel_disable_transcoder(struct drm_i915_private *dev_priv,
        I915_WRITE(reg, val);
        /* wait for PCH transcoder off, transcoder state */
        if (wait_for((I915_READ(reg) & TRANS_STATE_ENABLE) == 0, 50))
-               DRM_ERROR("failed to disable transcoder\n");
+               DRM_ERROR("failed to disable transcoder %d\n", pipe);
 }
 
 /**
@@ -2085,6 +2105,7 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
        switch (plane) {
        case 0:
        case 1:
+       case 2:
                break;
        default:
                DRM_ERROR("Can't update plane %d in SAREA\n", plane);
@@ -2184,6 +2205,10 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        case 0:
        case 1:
                break;
+       case 2:
+               if (IS_IVYBRIDGE(dev))
+                       break;
+               /* fall through otherwise */
        default:
                DRM_ERROR("no plane for crtc\n");
                return -EINVAL;
@@ -2440,7 +2465,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
 
 }
 
-static const int snb_b_fdi_train_param [] = {
+static const int snb_b_fdi_train_param[] = {
        FDI_LINK_TRAIN_400MV_0DB_SNB_B,
        FDI_LINK_TRAIN_400MV_6DB_SNB_B,
        FDI_LINK_TRAIN_600MV_3_5DB_SNB_B,
@@ -2496,7 +2521,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        if (HAS_PCH_CPT(dev))
                cpt_phase_pointer_enable(dev, pipe);
 
-       for (i = 0; i < 4; i++ ) {
+       for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2545,7 +2570,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
-       for (i = 0; i < 4; i++ ) {
+       for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2600,6 +2625,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
        temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
        temp |= FDI_LINK_TRAIN_400MV_0DB_SNB_B;
+       temp |= FDI_COMPOSITE_SYNC;
        I915_WRITE(reg, temp | FDI_TX_ENABLE);
 
        reg = FDI_RX_CTL(pipe);
@@ -2607,6 +2633,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        temp &= ~FDI_LINK_TRAIN_AUTO;
        temp &= ~FDI_LINK_TRAIN_PATTERN_MASK_CPT;
        temp |= FDI_LINK_TRAIN_PATTERN_1_CPT;
+       temp |= FDI_COMPOSITE_SYNC;
        I915_WRITE(reg, temp | FDI_RX_ENABLE);
 
        POSTING_READ(reg);
@@ -2615,7 +2642,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        if (HAS_PCH_CPT(dev))
                cpt_phase_pointer_enable(dev, pipe);
 
-       for (i = 0; i < 4; i++ ) {
+       for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2657,7 +2684,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
        POSTING_READ(reg);
        udelay(150);
 
-       for (i = 0; i < 4; i++ ) {
+       for (i = 0; i < 4; i++) {
                reg = FDI_TX_CTL(pipe);
                temp = I915_READ(reg);
                temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -2866,7 +2893,7 @@ static void ironlake_pch_enable(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;
+       u32 reg, temp, transc_sel;
 
        /* For PCH output, training FDI link */
        dev_priv->display.fdi_link_train(crtc);
@@ -2874,12 +2901,21 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        intel_enable_pch_pll(dev_priv, pipe);
 
        if (HAS_PCH_CPT(dev)) {
+               transc_sel = intel_crtc->use_pll_a ? TRANSC_DPLLA_SEL :
+                       TRANSC_DPLLB_SEL;
+
                /* Be sure PCH DPLL SEL is set */
                temp = I915_READ(PCH_DPLL_SEL);
-               if (pipe == 0 && (temp & TRANSA_DPLL_ENABLE) == 0)
+               if (pipe == 0) {
+                       temp &= ~(TRANSA_DPLLB_SEL);
                        temp |= (TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
-               else if (pipe == 1 && (temp & TRANSB_DPLL_ENABLE) == 0)
+               } else if (pipe == 1) {
+                       temp &= ~(TRANSB_DPLLB_SEL);
                        temp |= (TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
+               } else if (pipe == 2) {
+                       temp &= ~(TRANSC_DPLLB_SEL);
+                       temp |= (TRANSC_DPLL_ENABLE | transc_sel);
+               }
                I915_WRITE(PCH_DPLL_SEL, temp);
        }
 
@@ -2935,6 +2971,24 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
        intel_enable_transcoder(dev_priv, pipe);
 }
 
+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);
+       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);
+       }
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -3045,13 +3099,13 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
                temp = I915_READ(PCH_DPLL_SEL);
                switch (pipe) {
                case 0:
-                       temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL);
+                       temp &= ~(TRANSA_DPLL_ENABLE | TRANSA_DPLLB_SEL);
                        break;
                case 1:
                        temp &= ~(TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL);
                        break;
                case 2:
-                       /* FIXME: manage transcoder PLLs? */
+                       /* C shares PLL A or B */
                        temp &= ~(TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL);
                        break;
                default:
@@ -3061,7 +3115,8 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
        }
 
        /* disable PCH DPLL */
-       intel_disable_pch_pll(dev_priv, pipe);
+       if (!intel_crtc->no_pll)
+               intel_disable_pch_pll(dev_priv, pipe);
 
        /* Switch from PCDclk to Rawclk */
        reg = FDI_RX_CTL(pipe);
@@ -3293,18 +3348,25 @@ static void ironlake_crtc_commit(struct drm_crtc *crtc)
        ironlake_crtc_enable(crtc);
 }
 
-void intel_encoder_prepare (struct drm_encoder *encoder)
+void intel_encoder_prepare(struct drm_encoder *encoder)
 {
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
        /* lvds has its own version of prepare see intel_lvds_prepare */
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_OFF);
 }
 
-void intel_encoder_commit (struct drm_encoder *encoder)
+void intel_encoder_commit(struct drm_encoder *encoder)
 {
        struct drm_encoder_helper_funcs *encoder_funcs = encoder->helper_private;
+       struct drm_device *dev = encoder->dev;
+       struct intel_encoder *intel_encoder = to_intel_encoder(encoder);
+       struct intel_crtc *intel_crtc = to_intel_crtc(intel_encoder->base.crtc);
+
        /* lvds has its own version of commit see intel_lvds_commit */
        encoder_funcs->dpms(encoder, DRM_MODE_DPMS_ON);
+
+       if (HAS_PCH_CPT(dev))
+               intel_cpt_verify_modeset(dev, intel_crtc->pipe);
 }
 
 void intel_encoder_destroy(struct drm_encoder *encoder)
@@ -4478,6 +4540,20 @@ static void sandybridge_update_wm(struct drm_device *dev)
                enabled |= 2;
        }
 
+       /* IVB has 3 pipes */
+       if (IS_IVYBRIDGE(dev) &&
+           g4x_compute_wm0(dev, 2,
+                           &sandybridge_display_wm_info, latency,
+                           &sandybridge_cursor_wm_info, latency,
+                           &plane_wm, &cursor_wm)) {
+               I915_WRITE(WM0_PIPEC_IVB,
+                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
+               DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
+                             " plane %d, cursor: %d\n",
+                             plane_wm, cursor_wm);
+               enabled |= 3;
+       }
+
        /*
         * Calculate and update the self-refresh watermark only when one
         * display plane is used.
@@ -4584,7 +4660,9 @@ static void intel_update_watermarks(struct drm_device *dev)
 
 static inline bool intel_panel_use_ssc(struct drm_i915_private *dev_priv)
 {
-       return dev_priv->lvds_use_ssc && i915_panel_use_ssc
+       if (i915_panel_use_ssc >= 0)
+               return i915_panel_use_ssc != 0;
+       return dev_priv->lvds_use_ssc
                && !(dev_priv->quirks & QUIRK_LVDS_SSC_DISABLE);
 }
 
@@ -5107,36 +5185,52 @@ static int i9xx_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
-static void ironlake_update_pch_refclk(struct drm_device *dev)
+/*
+ * Initialize reference clocks when the driver loads
+ */
+void ironlake_init_pch_refclk(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_mode_config *mode_config = &dev->mode_config;
-       struct drm_crtc *crtc;
        struct intel_encoder *encoder;
-       struct intel_encoder *has_edp_encoder = NULL;
        u32 temp;
        bool has_lvds = false;
+       bool has_cpu_edp = false;
+       bool has_pch_edp = false;
+       bool has_panel = false;
+       bool has_ck505 = false;
+       bool can_ssc = false;
 
        /* We need to take the global config into account */
-       list_for_each_entry(crtc, &mode_config->crtc_list, head) {
-               if (!crtc->enabled)
-                       continue;
-
-               list_for_each_entry(encoder, &mode_config->encoder_list,
-                                   base.head) {
-                       if (encoder->base.crtc != crtc)
-                               continue;
-
-                       switch (encoder->type) {
-                       case INTEL_OUTPUT_LVDS:
-                               has_lvds = true;
-                       case INTEL_OUTPUT_EDP:
-                               has_edp_encoder = encoder;
-                               break;
-                       }
+       list_for_each_entry(encoder, &mode_config->encoder_list,
+                           base.head) {
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       has_panel = true;
+                       has_lvds = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       has_panel = true;
+                       if (intel_encoder_is_pch_edp(&encoder->base))
+                               has_pch_edp = true;
+                       else
+                               has_cpu_edp = true;
+                       break;
                }
        }
 
+       if (HAS_PCH_IBX(dev)) {
+               has_ck505 = dev_priv->display_clock_mode;
+               can_ssc = has_ck505;
+       } else {
+               has_ck505 = false;
+               can_ssc = true;
+       }
+
+       DRM_DEBUG_KMS("has_panel %d has_lvds %d has_pch_edp %d has_cpu_edp %d has_ck505 %d\n",
+                     has_panel, has_lvds, has_pch_edp, has_cpu_edp,
+                     has_ck505);
+
        /* Ironlake: try to setup display ref clock before DPLL
         * enabling. This is only under driver's control after
         * PCH B stepping, previous chipset stepping should be
@@ -5145,43 +5239,102 @@ static void ironlake_update_pch_refclk(struct drm_device *dev)
        temp = I915_READ(PCH_DREF_CONTROL);
        /* Always enable nonspread source */
        temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-       temp |= DREF_NONSPREAD_SOURCE_ENABLE;
-       temp &= ~DREF_SSC_SOURCE_MASK;
-       temp |= DREF_SSC_SOURCE_ENABLE;
-       I915_WRITE(PCH_DREF_CONTROL, temp);
 
-       POSTING_READ(PCH_DREF_CONTROL);
-       udelay(200);
+       if (has_ck505)
+               temp |= DREF_NONSPREAD_CK505_ENABLE;
+       else
+               temp |= DREF_NONSPREAD_SOURCE_ENABLE;
 
-       if (has_edp_encoder) {
-               if (intel_panel_use_ssc(dev_priv)) {
-                       temp |= DREF_SSC1_ENABLE;
-                       I915_WRITE(PCH_DREF_CONTROL, temp);
+       if (has_panel) {
+               temp &= ~DREF_SSC_SOURCE_MASK;
+               temp |= DREF_SSC_SOURCE_ENABLE;
 
-                       POSTING_READ(PCH_DREF_CONTROL);
-                       udelay(200);
+               /* SSC must be turned on before enabling the CPU output  */
+               if (intel_panel_use_ssc(dev_priv) && can_ssc) {
+                       DRM_DEBUG_KMS("Using SSC on panel\n");
+                       temp |= DREF_SSC1_ENABLE;
                }
+
+               /* Get SSC going before enabling the outputs */
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+
                temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
 
                /* Enable CPU source on CPU attached eDP */
-               if (!intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-                       if (intel_panel_use_ssc(dev_priv))
+               if (has_cpu_edp) {
+                       if (intel_panel_use_ssc(dev_priv) && can_ssc) {
+                               DRM_DEBUG_KMS("Using SSC on eDP\n");
                                temp |= DREF_CPU_SOURCE_OUTPUT_DOWNSPREAD;
+                       }
                        else
                                temp |= DREF_CPU_SOURCE_OUTPUT_NONSPREAD;
-               } else {
-                       /* Enable SSC on PCH eDP if needed */
-                       if (intel_panel_use_ssc(dev_priv)) {
-                               DRM_ERROR("enabling SSC on PCH\n");
-                               temp |= DREF_SUPERSPREAD_SOURCE_ENABLE;
-                       }
-               }
+               } else
+                       temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+       } else {
+               DRM_DEBUG_KMS("Disabling SSC entirely\n");
+
+               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
+
+               /* Turn off CPU output */
+               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
+
+               I915_WRITE(PCH_DREF_CONTROL, temp);
+               POSTING_READ(PCH_DREF_CONTROL);
+               udelay(200);
+
+               /* Turn off the SSC source */
+               temp &= ~DREF_SSC_SOURCE_MASK;
+               temp |= DREF_SSC_SOURCE_DISABLE;
+
+               /* Turn off SSC1 */
+               temp &= ~ DREF_SSC1_ENABLE;
+
                I915_WRITE(PCH_DREF_CONTROL, temp);
                POSTING_READ(PCH_DREF_CONTROL);
                udelay(200);
        }
 }
 
+static int ironlake_get_refclk(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_encoder *encoder;
+       struct drm_mode_config *mode_config = &dev->mode_config;
+       struct intel_encoder *edp_encoder = NULL;
+       int num_connectors = 0;
+       bool is_lvds = false;
+
+       list_for_each_entry(encoder, &mode_config->encoder_list, base.head) {
+               if (encoder->base.crtc != crtc)
+                       continue;
+
+               switch (encoder->type) {
+               case INTEL_OUTPUT_LVDS:
+                       is_lvds = true;
+                       break;
+               case INTEL_OUTPUT_EDP:
+                       edp_encoder = encoder;
+                       break;
+               }
+               num_connectors++;
+       }
+
+       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
+               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+                             dev_priv->lvds_ssc_freq);
+               return dev_priv->lvds_ssc_freq * 1000;
+       }
+
+       return 120000;
+}
+
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                                  struct drm_display_mode *mode,
                                  struct drm_display_mode *adjusted_mode,
@@ -5241,16 +5394,7 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                num_connectors++;
        }
 
-       if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               refclk = dev_priv->lvds_ssc_freq * 1000;
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                             refclk / 1000);
-       } else {
-               refclk = 96000;
-               if (!has_edp_encoder ||
-                   intel_encoder_is_pch_edp(&has_edp_encoder->base))
-                       refclk = 120000; /* 120Mhz refclk */
-       }
+       refclk = ironlake_get_refclk(crtc);
 
        /*
         * Returns a set of divisors for the desired target clock with the given
@@ -5377,8 +5521,6 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        ironlake_compute_m_n(intel_crtc->bpp, lane, target_clock, link_bw,
                             &m_n);
 
-       ironlake_update_pch_refclk(dev);
-
        fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
        if (has_reduced_clock)
                fp2 = reduced_clock.n << 16 | reduced_clock.m1 << 8 |
@@ -5450,39 +5592,32 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        /* Set up the display plane register */
        dspcntr = DISPPLANE_GAMMA_ENABLE;
 
-       DRM_DEBUG_KMS("Mode for pipe %c:\n", pipe == 0 ? 'A' : 'B');
+       DRM_DEBUG_KMS("Mode for pipe %d:\n", pipe);
        drm_mode_debug_printmodeline(mode);
 
        /* PCH eDP needs FDI, but CPU eDP does not */
-       if (!has_edp_encoder || intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
-               I915_WRITE(PCH_FP0(pipe), fp);
-               I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
-
-               POSTING_READ(PCH_DPLL(pipe));
-               udelay(150);
-       }
+       if (!intel_crtc->no_pll) {
+               if (!has_edp_encoder ||
+                   intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+                       I915_WRITE(PCH_FP0(pipe), fp);
+                       I915_WRITE(PCH_DPLL(pipe), dpll & ~DPLL_VCO_ENABLE);
 
-       /* enable transcoder DPLL */
-       if (HAS_PCH_CPT(dev)) {
-               temp = I915_READ(PCH_DPLL_SEL);
-               switch (pipe) {
-               case 0:
-                       temp |= TRANSA_DPLL_ENABLE | TRANSA_DPLLA_SEL;
-                       break;
-               case 1:
-                       temp |= TRANSB_DPLL_ENABLE | TRANSB_DPLLB_SEL;
-                       break;
-               case 2:
-                       /* FIXME: manage transcoder PLLs? */
-                       temp |= TRANSC_DPLL_ENABLE | TRANSC_DPLLB_SEL;
-                       break;
-               default:
-                       BUG();
+                       POSTING_READ(PCH_DPLL(pipe));
+                       udelay(150);
+               }
+       } else {
+               if (dpll == (I915_READ(PCH_DPLL(0)) & 0x7fffffff) &&
+                   fp == I915_READ(PCH_FP0(0))) {
+                       intel_crtc->use_pll_a = true;
+                       DRM_DEBUG_KMS("using pipe a dpll\n");
+               } else if (dpll == (I915_READ(PCH_DPLL(1)) & 0x7fffffff) &&
+                          fp == I915_READ(PCH_FP0(1))) {
+                       intel_crtc->use_pll_a = false;
+                       DRM_DEBUG_KMS("using pipe b dpll\n");
+               } else {
+                       DRM_DEBUG_KMS("no matching PLL configuration for pipe 2\n");
+                       return -EINVAL;
                }
-               I915_WRITE(PCH_DPLL_SEL, temp);
-
-               POSTING_READ(PCH_DPLL_SEL);
-               udelay(150);
        }
 
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
@@ -5492,17 +5627,13 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        if (is_lvds) {
                temp = I915_READ(PCH_LVDS);
                temp |= LVDS_PORT_EN | LVDS_A0A2_CLKA_POWER_UP;
-               if (pipe == 1) {
-                       if (HAS_PCH_CPT(dev))
-                               temp |= PORT_TRANS_B_SEL_CPT;
-                       else
-                               temp |= LVDS_PIPEB_SELECT;
-               } else {
-                       if (HAS_PCH_CPT(dev))
-                               temp &= ~PORT_TRANS_SEL_MASK;
-                       else
-                               temp &= ~LVDS_PIPEB_SELECT;
-               }
+               if (HAS_PCH_CPT(dev))
+                       temp |= PORT_TRANS_SEL_CPT(pipe);
+               else if (pipe == 1)
+                       temp |= LVDS_PIPEB_SELECT;
+               else
+                       temp &= ~LVDS_PIPEB_SELECT;
+
                /* set the corresponsding LVDS_BORDER bit */
                temp |= dev_priv->lvds_border_bits;
                /* Set the B0-B3 data pairs corresponding to whether we're going to
@@ -5552,8 +5683,9 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(TRANSDPLINK_N1(pipe), 0);
        }
 
-       if (!has_edp_encoder ||
-           intel_encoder_is_pch_edp(&has_edp_encoder->base)) {
+       if (!intel_crtc->no_pll &&
+           (!has_edp_encoder ||
+            intel_encoder_is_pch_edp(&has_edp_encoder->base))) {
                I915_WRITE(PCH_DPLL(pipe), dpll);
 
                /* Wait for the clocks to stabilize. */
@@ -5569,18 +5701,20 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
        }
 
        intel_crtc->lowfreq_avail = false;
-       if (is_lvds && has_reduced_clock && i915_powersave) {
-               I915_WRITE(PCH_FP1(pipe), fp2);
-               intel_crtc->lowfreq_avail = true;
-               if (HAS_PIPE_CXSR(dev)) {
-                       DRM_DEBUG_KMS("enabling CxSR downclocking\n");
-                       pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
-               }
-       } else {
-               I915_WRITE(PCH_FP1(pipe), fp);
-               if (HAS_PIPE_CXSR(dev)) {
-                       DRM_DEBUG_KMS("disabling CxSR downclocking\n");
-                       pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+       if (!intel_crtc->no_pll) {
+               if (is_lvds && has_reduced_clock && i915_powersave) {
+                       I915_WRITE(PCH_FP1(pipe), fp2);
+                       intel_crtc->lowfreq_avail = true;
+                       if (HAS_PIPE_CXSR(dev)) {
+                               DRM_DEBUG_KMS("enabling CxSR downclocking\n");
+                               pipeconf |= PIPECONF_CXSR_DOWNCLOCK;
+                       }
+               } else {
+                       I915_WRITE(PCH_FP1(pipe), fp);
+                       if (HAS_PIPE_CXSR(dev)) {
+                               DRM_DEBUG_KMS("disabling CxSR downclocking\n");
+                               pipeconf &= ~PIPECONF_CXSR_DOWNCLOCK;
+                       }
                }
        }
 
@@ -5677,6 +5811,131 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        return ret;
 }
 
+static void g4x_write_eld(struct drm_connector *connector,
+                         struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       uint32_t eldv;
+       uint32_t len;
+       uint32_t i;
+
+       i = I915_READ(G4X_AUD_VID_DID);
+
+       if (i == INTEL_AUDIO_DEVBLC || i == INTEL_AUDIO_DEVCL)
+               eldv = G4X_ELDV_DEVCL_DEVBLC;
+       else
+               eldv = G4X_ELDV_DEVCTG;
+
+       i = I915_READ(G4X_AUD_CNTL_ST);
+       i &= ~(eldv | G4X_ELD_ADDR);
+       len = (i >> 9) & 0x1f;          /* ELD buffer size */
+       I915_WRITE(G4X_AUD_CNTL_ST, i);
+
+       if (!eld[0])
+               return;
+
+       len = min_t(uint8_t, eld[2], len);
+       DRM_DEBUG_DRIVER("ELD size %d\n", len);
+       for (i = 0; i < len; i++)
+               I915_WRITE(G4X_HDMIW_HDMIEDID, *((uint32_t *)eld + i));
+
+       i = I915_READ(G4X_AUD_CNTL_ST);
+       i |= eldv;
+       I915_WRITE(G4X_AUD_CNTL_ST, i);
+}
+
+static void ironlake_write_eld(struct drm_connector *connector,
+                                    struct drm_crtc *crtc)
+{
+       struct drm_i915_private *dev_priv = connector->dev->dev_private;
+       uint8_t *eld = connector->eld;
+       uint32_t eldv;
+       uint32_t i;
+       int len;
+       int hdmiw_hdmiedid;
+       int aud_cntl_st;
+       int aud_cntrl_st2;
+
+       if (IS_IVYBRIDGE(connector->dev)) {
+               hdmiw_hdmiedid = GEN7_HDMIW_HDMIEDID_A;
+               aud_cntl_st = GEN7_AUD_CNTRL_ST_A;
+               aud_cntrl_st2 = GEN7_AUD_CNTRL_ST2;
+       } else {
+               hdmiw_hdmiedid = GEN5_HDMIW_HDMIEDID_A;
+               aud_cntl_st = GEN5_AUD_CNTL_ST_A;
+               aud_cntrl_st2 = GEN5_AUD_CNTL_ST2;
+       }
+
+       i = to_intel_crtc(crtc)->pipe;
+       hdmiw_hdmiedid += i * 0x100;
+       aud_cntl_st += i * 0x100;
+
+       DRM_DEBUG_DRIVER("ELD on pipe %c\n", pipe_name(i));
+
+       i = I915_READ(aud_cntl_st);
+       i = (i >> 29) & 0x3;            /* DIP_Port_Select, 0x1 = PortB */
+       if (!i) {
+               DRM_DEBUG_DRIVER("Audio directed to unknown port\n");
+               /* operate blindly on all ports */
+               eldv = GEN5_ELD_VALIDB;
+               eldv |= GEN5_ELD_VALIDB << 4;
+               eldv |= GEN5_ELD_VALIDB << 8;
+       } else {
+               DRM_DEBUG_DRIVER("ELD on port %c\n", 'A' + i);
+               eldv = GEN5_ELD_VALIDB << ((i - 1) * 4);
+       }
+
+       i = I915_READ(aud_cntrl_st2);
+       i &= ~eldv;
+       I915_WRITE(aud_cntrl_st2, i);
+
+       if (!eld[0])
+               return;
+
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT)) {
+               DRM_DEBUG_DRIVER("ELD: DisplayPort detected\n");
+               eld[5] |= (1 << 2);     /* Conn_Type, 0x1 = DisplayPort */
+       }
+
+       i = I915_READ(aud_cntl_st);
+       i &= ~GEN5_ELD_ADDRESS;
+       I915_WRITE(aud_cntl_st, i);
+
+       len = min_t(uint8_t, eld[2], 21);       /* 84 bytes of hw ELD buffer */
+       DRM_DEBUG_DRIVER("ELD size %d\n", len);
+       for (i = 0; i < len; i++)
+               I915_WRITE(hdmiw_hdmiedid, *((uint32_t *)eld + i));
+
+       i = I915_READ(aud_cntrl_st2);
+       i |= eldv;
+       I915_WRITE(aud_cntrl_st2, i);
+}
+
+void intel_write_eld(struct drm_encoder *encoder,
+                    struct drm_display_mode *mode)
+{
+       struct drm_crtc *crtc = encoder->crtc;
+       struct drm_connector *connector;
+       struct drm_device *dev = encoder->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       connector = drm_select_eld(encoder, mode);
+       if (!connector)
+               return;
+
+       DRM_DEBUG_DRIVER("ELD on [CONNECTOR:%d:%s], [ENCODER:%d:%s]\n",
+                        connector->base.id,
+                        drm_get_connector_name(connector),
+                        connector->encoder->base.id,
+                        drm_get_encoder_name(connector->encoder));
+
+       connector->eld[6] = drm_av_sync_delay(connector, mode) / 2;
+
+       if (dev_priv->display.write_eld)
+               dev_priv->display.write_eld(connector, crtc);
+}
+
 /** Loads the palette/gamma unit for the CRTC with the prepared values */
 void intel_crtc_load_lut(struct drm_crtc *crtc)
 {
@@ -5758,6 +6017,31 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
        I915_WRITE(CURBASE(pipe), base);
 }
 
+static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int pipe = intel_crtc->pipe;
+       bool visible = base != 0;
+
+       if (intel_crtc->cursor_visible != visible) {
+               uint32_t cntl = I915_READ(CURCNTR_IVB(pipe));
+               if (base) {
+                       cntl &= ~CURSOR_MODE;
+                       cntl |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE;
+               } else {
+                       cntl &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE);
+                       cntl |= CURSOR_MODE_DISABLE;
+               }
+               I915_WRITE(CURCNTR_IVB(pipe), cntl);
+
+               intel_crtc->cursor_visible = visible;
+       }
+       /* and commit changes on next vblank */
+       I915_WRITE(CURBASE_IVB(pipe), base);
+}
+
 /* If no-part of the cursor is visible on the framebuffer, then the GPU may hang... */
 static void intel_crtc_update_cursor(struct drm_crtc *crtc,
                                     bool on)
@@ -5805,11 +6089,16 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
        if (!visible && !intel_crtc->cursor_visible)
                return;
 
-       I915_WRITE(CURPOS(pipe), pos);
-       if (IS_845G(dev) || IS_I865G(dev))
-               i845_update_cursor(crtc, base);
-       else
-               i9xx_update_cursor(crtc, base);
+       if (IS_IVYBRIDGE(dev)) {
+               I915_WRITE(CURPOS_IVB(pipe), pos);
+               ivb_update_cursor(crtc, base);
+       } else {
+               I915_WRITE(CURPOS(pipe), pos);
+               if (IS_845G(dev) || IS_I865G(dev))
+                       i845_update_cursor(crtc, base);
+               else
+                       i9xx_update_cursor(crtc, base);
+       }
 
        if (visible)
                intel_mark_busy(dev, to_intel_framebuffer(crtc->fb)->obj);
@@ -7071,6 +7360,8 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
        intel_crtc->bpp = 24; /* default for pre-Ironlake */
 
        if (HAS_PCH_SPLIT(dev)) {
+               if (pipe == 2 && IS_IVYBRIDGE(dev))
+                       intel_crtc->no_pll = true;
                intel_helper_funcs.prepare = ironlake_crtc_prepare;
                intel_helper_funcs.commit = ironlake_crtc_commit;
        } else {
@@ -7250,6 +7541,9 @@ static void intel_setup_outputs(struct drm_device *dev)
 
        /* disable all the possible outputs/crtcs before entering KMS mode */
        drm_helper_disable_unused_functions(dev);
+
+       if (HAS_PCH_SPLIT(dev))
+               ironlake_init_pch_refclk(dev);
 }
 
 static void intel_user_framebuffer_destroy(struct drm_framebuffer *fb)
@@ -7494,6 +7788,10 @@ void gen6_disable_rps(struct drm_device *dev)
        I915_WRITE(GEN6_RPNSWREQ, 1 << 31);
        I915_WRITE(GEN6_PMINTRMSK, 0xffffffff);
        I915_WRITE(GEN6_PMIER, 0);
+       /* Complete PM interrupt masking here doesn't race with the rps work
+        * item again unmasking PM interrupts because that is using a different
+        * register (PMIMR) to mask PM interrupts. The only risk is in leaving
+        * stale bits in PMIIR and PMIMR which gen6_enable_rps will clean up. */
 
        spin_lock_irq(&dev_priv->rps_lock);
        dev_priv->pm_iir = 0;
@@ -8154,7 +8452,7 @@ static void intel_init_display(struct drm_device *dev)
        }
 
        /* Returns the core display clock speed */
-       if (IS_I945G(dev) || (IS_G33(dev) && ! IS_PINEVIEW_M(dev)))
+       if (IS_I945G(dev) || (IS_G33(dev) && !IS_PINEVIEW_M(dev)))
                dev_priv->display.get_display_clock_speed =
                        i945_get_display_clock_speed;
        else if (IS_I915G(dev))
@@ -8193,6 +8491,7 @@ static void intel_init_display(struct drm_device *dev)
                        }
                        dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
                        dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
+                       dev_priv->display.write_eld = ironlake_write_eld;
                } else if (IS_GEN6(dev)) {
                        if (SNB_READ_WM0_LATENCY()) {
                                dev_priv->display.update_wm = sandybridge_update_wm;
@@ -8203,6 +8502,7 @@ static void intel_init_display(struct drm_device *dev)
                        }
                        dev_priv->display.fdi_link_train = gen6_fdi_link_train;
                        dev_priv->display.init_clock_gating = gen6_init_clock_gating;
+                       dev_priv->display.write_eld = ironlake_write_eld;
                } else if (IS_IVYBRIDGE(dev)) {
                        /* FIXME: detect B0+ stepping and use auto training */
                        dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
@@ -8214,7 +8514,7 @@ static void intel_init_display(struct drm_device *dev)
                                dev_priv->display.update_wm = NULL;
                        }
                        dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
-
+                       dev_priv->display.write_eld = ironlake_write_eld;
                } else
                        dev_priv->display.update_wm = NULL;
        } else if (IS_PINEVIEW(dev)) {
@@ -8225,7 +8525,7 @@ static void intel_init_display(struct drm_device *dev)
                        DRM_INFO("failed to find known CxSR latency "
                                 "(found ddr%s fsb freq %d, mem freq %d), "
                                 "disabling CxSR\n",
-                                (dev_priv->is_ddr3 == 1) ? "3": "2",
+                                (dev_priv->is_ddr3 == 1) ? "3" : "2",
                                 dev_priv->fsb_freq, dev_priv->mem_freq);
                        /* Disable CxSR and never update its watermark again */
                        pineview_disable_cxsr(dev);
@@ -8234,6 +8534,7 @@ static void intel_init_display(struct drm_device *dev)
                        dev_priv->display.update_wm = pineview_update_wm;
                dev_priv->display.init_clock_gating = gen3_init_clock_gating;
        } else if (IS_G4X(dev)) {
+               dev_priv->display.write_eld = g4x_write_eld;
                dev_priv->display.update_wm = g4x_update_wm;
                dev_priv->display.init_clock_gating = g4x_init_clock_gating;
        } else if (IS_GEN4(dev)) {
@@ -8294,7 +8595,7 @@ static void intel_init_display(struct drm_device *dev)
  * resume, or other times.  This quirk makes sure that's the case for
  * affected systems.
  */
-static void quirk_pipea_force (struct drm_device *dev)
+static void quirk_pipea_force(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
@@ -8322,7 +8623,7 @@ struct intel_quirk intel_quirks[] = {
        /* HP Compaq 2730p needs pipe A force quirk (LP: #291555) */
        { 0x2a42, 0x103c, 0x30eb, quirk_pipea_force },
        /* HP Mini needs pipe A force quirk (LP: #322104) */
-       { 0x27ae,0x103c, 0x361a, quirk_pipea_force },
+       { 0x27ae, 0x103c, 0x361a, quirk_pipea_force },
 
        /* Thinkpad R31 needs pipe A force quirk */
        { 0x3577, 0x1014, 0x0505, quirk_pipea_force },
@@ -8488,6 +8789,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
         * enqueue unpin/hotplug work. */
        drm_irq_uninstall(dev);
        cancel_work_sync(&dev_priv->hotplug_work);
+       cancel_work_sync(&dev_priv->rps_work);
 
        /* flush any delayed tasks or pending work */
        flush_scheduled_work();
@@ -8573,7 +8875,7 @@ struct intel_display_error_state {
 struct intel_display_error_state *
 intel_display_capture_error_state(struct drm_device *dev)
 {
-        drm_i915_private_t *dev_priv = dev->dev_private;
+       drm_i915_private_t *dev_priv = dev->dev_private;
        struct intel_display_error_state *error;
        int i;
 
@@ -8589,7 +8891,7 @@ intel_display_capture_error_state(struct drm_device *dev)
                error->plane[i].control = I915_READ(DSPCNTR(i));
                error->plane[i].stride = I915_READ(DSPSTRIDE(i));
                error->plane[i].size = I915_READ(DSPSIZE(i));
-               error->plane[i].pos= I915_READ(DSPPOS(i));
+               error->plane[i].pos = I915_READ(DSPPOS(i));
                error->plane[i].addr = I915_READ(DSPADDR(i));
                if (INTEL_INFO(dev)->gen >= 4) {
                        error->plane[i].surface = I915_READ(DSPSURF(i));