Merge branch 'drm-next' of git://people.freedesktop.org/~airlied/linux
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_dp.c
index f1bd4f4..6c8746c 100644 (file)
 #include "intel_drv.h"
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
-#include <drm/drm_dp_helper.h>
 
-#define DP_RECEIVER_CAP_SIZE   0xf
 #define DP_LINK_STATUS_SIZE    6
 #define DP_LINK_CHECK_TIMEOUT  (10 * 1000)
 
-#define DP_LINK_CONFIGURATION_SIZE     9
-
-struct intel_dp {
-       struct intel_encoder base;
-       uint32_t output_reg;
-       uint32_t DP;
-       uint8_t  link_configuration[DP_LINK_CONFIGURATION_SIZE];
-       bool has_audio;
-       enum hdmi_force_audio force_audio;
-       uint32_t color_range;
-       int dpms_mode;
-       uint8_t link_bw;
-       uint8_t lane_count;
-       uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
-       struct i2c_adapter adapter;
-       struct i2c_algo_dp_aux_data algo;
-       bool is_pch_edp;
-       uint8_t train_set[4];
-       int panel_power_up_delay;
-       int panel_power_down_delay;
-       int panel_power_cycle_delay;
-       int backlight_on_delay;
-       int backlight_off_delay;
-       struct drm_display_mode *panel_fixed_mode;  /* for eDP */
-       struct delayed_work panel_vdd_work;
-       bool want_panel_vdd;
-       struct edid *edid; /* cached EDID for eDP */
-       int edid_mode_count;
-};
-
 /**
  * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
  * @intel_dp: DP struct
@@ -839,9 +807,6 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
        }
 }
 
-static void ironlake_edp_pll_on(struct drm_encoder *encoder);
-static void ironlake_edp_pll_off(struct drm_encoder *encoder);
-
 static void
 intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                  struct drm_display_mode *adjusted_mode)
@@ -852,14 +817,6 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
-       /* Turn on the eDP PLL if needed */
-       if (is_edp(intel_dp)) {
-               if (!is_pch_edp(intel_dp))
-                       ironlake_edp_pll_on(encoder);
-               else
-                       ironlake_edp_pll_off(encoder);
-       }
-
        /*
         * There are four kinds of DP registers:
         *
@@ -881,10 +838,8 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
         * supposed to be read-only.
         */
        intel_dp->DP = I915_READ(intel_dp->output_reg) & DP_DETECTED;
-       intel_dp->DP |=  DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
 
        /* Handle DP bits in common between all three register formats */
-
        intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
 
        switch (intel_dp->lane_count) {
@@ -931,7 +886,6 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
                intel_dp->DP |= intel_crtc->pipe << 29;
 
                /* don't miss out required setting for eDP */
-               intel_dp->DP |= DP_PLL_ENABLE;
                if (adjusted_mode->clock < 200000)
                        intel_dp->DP |= DP_PLL_FREQ_160MHZ;
                else
@@ -953,7 +907,6 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 
                if (is_cpu_edp(intel_dp)) {
                        /* don't miss out required setting for eDP */
-                       intel_dp->DP |= DP_PLL_ENABLE;
                        if (adjusted_mode->clock < 200000)
                                intel_dp->DP |= DP_PLL_FREQ_160MHZ;
                        else
@@ -1224,27 +1177,49 @@ static void ironlake_edp_backlight_off(struct intel_dp *intel_dp)
        msleep(intel_dp->backlight_off_delay);
 }
 
-static void ironlake_edp_pll_on(struct drm_encoder *encoder)
+static void ironlake_edp_pll_on(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 dpa_ctl;
 
+       assert_pipe_disabled(dev_priv,
+                            to_intel_crtc(crtc)->pipe);
+
        DRM_DEBUG_KMS("\n");
        dpa_ctl = I915_READ(DP_A);
-       dpa_ctl |= DP_PLL_ENABLE;
-       I915_WRITE(DP_A, dpa_ctl);
+       WARN(dpa_ctl & DP_PLL_ENABLE, "dp pll on, should be off\n");
+       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+
+       /* We don't adjust intel_dp->DP while tearing down the link, to
+        * facilitate link retraining (e.g. after hotplug). Hence clear all
+        * enable bits here to ensure that we don't enable too much. */
+       intel_dp->DP &= ~(DP_PORT_EN | DP_AUDIO_OUTPUT_ENABLE);
+       intel_dp->DP |= DP_PLL_ENABLE;
+       I915_WRITE(DP_A, intel_dp->DP);
        POSTING_READ(DP_A);
        udelay(200);
 }
 
-static void ironlake_edp_pll_off(struct drm_encoder *encoder)
+static void ironlake_edp_pll_off(struct intel_dp *intel_dp)
 {
-       struct drm_device *dev = encoder->dev;
+       struct drm_device *dev = intel_dp->base.base.dev;
+       struct drm_crtc *crtc = intel_dp->base.base.crtc;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 dpa_ctl;
 
+       assert_pipe_disabled(dev_priv,
+                            to_intel_crtc(crtc)->pipe);
+
        dpa_ctl = I915_READ(DP_A);
+       WARN((dpa_ctl & DP_PLL_ENABLE) == 0,
+            "dp pll off, should be on\n");
+       WARN(dpa_ctl & DP_PORT_EN, "dp port still on, should be off\n");
+
+       /* We can't rely on the value tracked for the DP register in
+        * intel_dp->DP because link_down must not change that (otherwise link
+        * re-training will fail. */
        dpa_ctl &= ~DP_PLL_ENABLE;
        I915_WRITE(DP_A, dpa_ctl);
        POSTING_READ(DP_A);
@@ -1281,10 +1256,57 @@ static void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode)
        }
 }
 
-static void intel_dp_prepare(struct drm_encoder *encoder)
+static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
+                                 enum pipe *pipe)
 {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp = I915_READ(intel_dp->output_reg);
 
+       if (!(tmp & DP_PORT_EN))
+               return false;
+
+       if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
+               *pipe = PORT_TO_PIPE_CPT(tmp);
+       } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+               *pipe = PORT_TO_PIPE(tmp);
+       } else {
+               u32 trans_sel;
+               u32 trans_dp;
+               int i;
+
+               switch (intel_dp->output_reg) {
+               case PCH_DP_B:
+                       trans_sel = TRANS_DP_PORT_SEL_B;
+                       break;
+               case PCH_DP_C:
+                       trans_sel = TRANS_DP_PORT_SEL_C;
+                       break;
+               case PCH_DP_D:
+                       trans_sel = TRANS_DP_PORT_SEL_D;
+                       break;
+               default:
+                       return true;
+               }
+
+               for_each_pipe(i) {
+                       trans_dp = I915_READ(TRANS_DP_CTL(i));
+                       if ((trans_dp & TRANS_DP_PORT_SEL_MASK) == trans_sel) {
+                               *pipe = i;
+                               return true;
+                       }
+               }
+       }
+
+       DRM_DEBUG_KMS("No pipe for dp port 0x%x found\n", intel_dp->output_reg);
+
+       return true;
+}
+
+static void intel_disable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
@@ -1292,14 +1314,31 @@ static void intel_dp_prepare(struct drm_encoder *encoder)
        ironlake_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
        ironlake_edp_panel_off(intel_dp);
-       intel_dp_link_down(intel_dp);
+
+       /* cpu edp my only be disable _after_ the cpu pipe/plane is disabled. */
+       if (!is_cpu_edp(intel_dp))
+               intel_dp_link_down(intel_dp);
 }
 
-static void intel_dp_commit(struct drm_encoder *encoder)
+static void intel_post_disable_dp(struct intel_encoder *encoder)
 {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+
+       if (is_cpu_edp(intel_dp)) {
+               intel_dp_link_down(intel_dp);
+               ironlake_edp_pll_off(intel_dp);
+       }
+}
+
+static void intel_enable_dp(struct intel_encoder *encoder)
+{
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+
+       if (WARN_ON(dp_reg & DP_PORT_EN))
+               return;
 
        ironlake_edp_panel_vdd_on(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_ON);
@@ -1308,47 +1347,14 @@ static void intel_dp_commit(struct drm_encoder *encoder)
        ironlake_edp_panel_vdd_off(intel_dp, true);
        intel_dp_complete_link_train(intel_dp);
        ironlake_edp_backlight_on(intel_dp);
-
-       intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
-
-       if (HAS_PCH_CPT(dev))
-               intel_cpt_verify_modeset(dev, intel_crtc->pipe);
 }
 
-static void
-intel_dp_dpms(struct drm_encoder *encoder, int mode)
+static void intel_pre_enable_dp(struct intel_encoder *encoder)
 {
-       struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-       struct drm_device *dev = encoder->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dp_reg = I915_READ(intel_dp->output_reg);
+       struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
-       if (mode != DRM_MODE_DPMS_ON) {
-               /* Switching the panel off requires vdd. */
-               ironlake_edp_panel_vdd_on(intel_dp);
-               ironlake_edp_backlight_off(intel_dp);
-               intel_dp_sink_dpms(intel_dp, mode);
-               ironlake_edp_panel_off(intel_dp);
-               intel_dp_link_down(intel_dp);
-
-               if (is_cpu_edp(intel_dp))
-                       ironlake_edp_pll_off(encoder);
-       } else {
-               if (is_cpu_edp(intel_dp))
-                       ironlake_edp_pll_on(encoder);
-
-               ironlake_edp_panel_vdd_on(intel_dp);
-               intel_dp_sink_dpms(intel_dp, mode);
-               if (!(dp_reg & DP_PORT_EN)) {
-                       intel_dp_start_link_train(intel_dp);
-                       ironlake_edp_panel_on(intel_dp);
-                       ironlake_edp_panel_vdd_off(intel_dp, true);
-                       intel_dp_complete_link_train(intel_dp);
-               } else
-                       ironlake_edp_panel_vdd_off(intel_dp, false);
-               ironlake_edp_backlight_on(intel_dp);
-       }
-       intel_dp->dpms_mode = mode;
+       if (is_cpu_edp(intel_dp))
+               ironlake_edp_pll_on(intel_dp);
 }
 
 /*
@@ -1667,6 +1673,45 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
+               dp_reg_value &= ~DP_LINK_TRAIN_MASK_CPT;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       dp_reg_value |= DP_LINK_TRAIN_OFF_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_1_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2_CPT;
+                       break;
+               }
+
+       } else {
+               dp_reg_value &= ~DP_LINK_TRAIN_MASK;
+
+               switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {
+               case DP_TRAINING_PATTERN_DISABLE:
+                       dp_reg_value |= DP_LINK_TRAIN_OFF;
+                       break;
+               case DP_TRAINING_PATTERN_1:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_1;
+                       break;
+               case DP_TRAINING_PATTERN_2:
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               case DP_TRAINING_PATTERN_3:
+                       DRM_ERROR("DP training pattern 3 not supported\n");
+                       dp_reg_value |= DP_LINK_TRAIN_PAT_2;
+                       break;
+               }
+       }
+
        I915_WRITE(intel_dp->output_reg, dp_reg_value);
        POSTING_READ(intel_dp->output_reg);
 
@@ -1674,12 +1719,15 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
                                    DP_TRAINING_PATTERN_SET,
                                    dp_train_pat);
 
-       ret = intel_dp_aux_native_write(intel_dp,
-                                       DP_TRAINING_LANE0_SET,
-                                       intel_dp->train_set,
-                                       intel_dp->lane_count);
-       if (ret != intel_dp->lane_count)
-               return false;
+       if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) !=
+           DP_TRAINING_PATTERN_DISABLE) {
+               ret = intel_dp_aux_native_write(intel_dp,
+                                               DP_TRAINING_LANE0_SET,
+                                               intel_dp->train_set,
+                                               intel_dp->lane_count);
+               if (ret != intel_dp->lane_count)
+                       return false;
+       }
 
        return true;
 }
@@ -1689,26 +1737,12 @@ static void
 intel_dp_start_link_train(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(intel_dp->base.base.crtc);
        int i;
        uint8_t voltage;
        bool clock_recovery = false;
        int voltage_tries, loop_tries;
-       u32 reg;
        uint32_t DP = intel_dp->DP;
 
-       /*
-        * On CPT we have to enable the port in training pattern 1, which
-        * will happen below in intel_dp_set_link_train.  Otherwise, enable
-        * the port and wait for it to become active.
-        */
-       if (!HAS_PCH_CPT(dev)) {
-               I915_WRITE(intel_dp->output_reg, intel_dp->DP);
-               POSTING_READ(intel_dp->output_reg);
-               intel_wait_for_vblank(dev, intel_crtc->pipe);
-       }
-
        /* Write the link configuration data */
        intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
                                  intel_dp->link_configuration,
@@ -1716,10 +1750,6 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
 
        DP |= DP_PORT_EN;
 
-       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-               DP &= ~DP_LINK_TRAIN_MASK_CPT;
-       else
-               DP &= ~DP_LINK_TRAIN_MASK;
        memset(intel_dp->train_set, 0, 4);
        voltage = 0xff;
        voltage_tries = 0;
@@ -1743,12 +1773,7 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
-               else
-                       reg = DP | DP_LINK_TRAIN_PAT_1;
-
-               if (!intel_dp_set_link_train(intel_dp, reg,
+               if (!intel_dp_set_link_train(intel_dp, DP,
                                             DP_TRAINING_PATTERN_1 |
                                             DP_LINK_SCRAMBLING_DISABLE))
                        break;
@@ -1803,10 +1828,8 @@ static void
 intel_dp_complete_link_train(struct intel_dp *intel_dp)
 {
        struct drm_device *dev = intel_dp->base.base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        bool channel_eq = false;
        int tries, cr_tries;
-       u32 reg;
        uint32_t DP = intel_dp->DP;
 
        /* channel equalization */
@@ -1835,13 +1858,8 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                        DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
                }
 
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
-               else
-                       reg = DP | DP_LINK_TRAIN_PAT_2;
-
                /* channel eq pattern */
-               if (!intel_dp_set_link_train(intel_dp, reg,
+               if (!intel_dp_set_link_train(intel_dp, DP,
                                             DP_TRAINING_PATTERN_2 |
                                             DP_LINK_SCRAMBLING_DISABLE))
                        break;
@@ -1876,15 +1894,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                ++tries;
        }
 
-       if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-               reg = DP | DP_LINK_TRAIN_OFF_CPT;
-       else
-               reg = DP | DP_LINK_TRAIN_OFF;
-
-       I915_WRITE(intel_dp->output_reg, reg);
-       POSTING_READ(intel_dp->output_reg);
-       intel_dp_aux_native_write_1(intel_dp,
-                                   DP_TRAINING_PATTERN_SET, DP_TRAINING_PATTERN_DISABLE);
+       intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE);
 }
 
 static void
@@ -1894,18 +1904,11 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t DP = intel_dp->DP;
 
-       if ((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0)
+       if (WARN_ON((I915_READ(intel_dp->output_reg) & DP_PORT_EN) == 0))
                return;
 
        DRM_DEBUG_KMS("\n");
 
-       if (is_edp(intel_dp)) {
-               DP &= ~DP_PLL_ENABLE;
-               I915_WRITE(intel_dp->output_reg, DP);
-               POSTING_READ(intel_dp->output_reg);
-               udelay(100);
-       }
-
        if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp))) {
                DP &= ~DP_LINK_TRAIN_MASK_CPT;
                I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
@@ -1917,13 +1920,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
 
        msleep(17);
 
-       if (is_edp(intel_dp)) {
-               if (HAS_PCH_CPT(dev) && (IS_GEN7(dev) || !is_cpu_edp(intel_dp)))
-                       DP |= DP_LINK_TRAIN_OFF_CPT;
-               else
-                       DP |= DP_LINK_TRAIN_OFF;
-       }
-
        if (HAS_PCH_IBX(dev) &&
            I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
                struct drm_crtc *crtc = intel_dp->base.base.crtc;
@@ -2032,10 +2028,10 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
        u8 sink_irq_vector;
        u8 link_status[DP_LINK_STATUS_SIZE];
 
-       if (intel_dp->dpms_mode != DRM_MODE_DPMS_ON)
+       if (!intel_dp->base.connectors_active)
                return;
 
-       if (!intel_dp->base.base.crtc)
+       if (WARN_ON(!intel_dp->base.base.crtc))
                return;
 
        /* Try to read receiver status if the link appears to be up */
@@ -2159,7 +2155,6 @@ intel_dp_get_edid_modes(struct drm_connector *connector, struct i2c_adapter *ada
                ret = drm_add_edid_modes(connector, intel_dp->edid);
                drm_edid_to_eld(connector,
                                intel_dp->edid);
-               connector->display_info.raw_edid = NULL;
                return intel_dp->edid_mode_count;
        }
 
@@ -2205,7 +2200,6 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                edid = intel_dp_get_edid(connector, &intel_dp->adapter);
                if (edid) {
                        intel_dp->has_audio = drm_detect_monitor_audio(edid);
-                       connector->display_info.raw_edid = NULL;
                        kfree(edid);
                }
        }
@@ -2270,8 +2264,6 @@ intel_dp_detect_audio(struct drm_connector *connector)
        edid = intel_dp_get_edid(connector, &intel_dp->adapter);
        if (edid) {
                has_audio = drm_detect_monitor_audio(edid);
-
-               connector->display_info.raw_edid = NULL;
                kfree(edid);
        }
 
@@ -2325,9 +2317,8 @@ intel_dp_set_property(struct drm_connector *connector,
 done:
        if (intel_dp->base.base.crtc) {
                struct drm_crtc *crtc = intel_dp->base.base.crtc;
-               drm_crtc_helper_set_mode(crtc, &crtc->mode,
-                                        crtc->x, crtc->y,
-                                        crtc->fb);
+               intel_set_mode(crtc, &crtc->mode,
+                              crtc->x, crtc->y, crtc->fb);
        }
 
        return 0;
@@ -2361,15 +2352,13 @@ static void intel_dp_encoder_destroy(struct drm_encoder *encoder)
 }
 
 static const struct drm_encoder_helper_funcs intel_dp_helper_funcs = {
-       .dpms = intel_dp_dpms,
        .mode_fixup = intel_dp_mode_fixup,
-       .prepare = intel_dp_prepare,
        .mode_set = intel_dp_mode_set,
-       .commit = intel_dp_commit,
+       .disable = intel_encoder_noop,
 };
 
 static const struct drm_connector_funcs intel_dp_connector_funcs = {
-       .dpms = drm_helper_connector_dpms,
+       .dpms = intel_connector_dpms,
        .detect = intel_dp_detect,
        .fill_modes = drm_helper_probe_single_connector_modes,
        .set_property = intel_dp_set_property,
@@ -2440,7 +2429,7 @@ intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connect
 }
 
 void
-intel_dp_init(struct drm_device *dev, int output_reg)
+intel_dp_init(struct drm_device *dev, int output_reg, enum port port)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_connector *connector;
@@ -2455,7 +2444,9 @@ intel_dp_init(struct drm_device *dev, int output_reg)
                return;
 
        intel_dp->output_reg = output_reg;
-       intel_dp->dpms_mode = -1;
+       intel_dp->port = port;
+       /* Preserve the current hw state. */
+       intel_dp->DP = I915_READ(intel_dp->output_reg);
 
        intel_connector = kzalloc(sizeof(struct intel_connector), GFP_KERNEL);
        if (!intel_connector) {
@@ -2482,18 +2473,10 @@ intel_dp_init(struct drm_device *dev, int output_reg)
 
        connector->polled = DRM_CONNECTOR_POLL_HPD;
 
-       if (output_reg == DP_B || output_reg == PCH_DP_B)
-               intel_encoder->clone_mask = (1 << INTEL_DP_B_CLONE_BIT);
-       else if (output_reg == DP_C || output_reg == PCH_DP_C)
-               intel_encoder->clone_mask = (1 << INTEL_DP_C_CLONE_BIT);
-       else if (output_reg == DP_D || output_reg == PCH_DP_D)
-               intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
+       intel_encoder->cloneable = false;
 
-       if (is_edp(intel_dp)) {
-               intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
-               INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
-                                 ironlake_panel_vdd_work);
-       }
+       INIT_DELAYED_WORK(&intel_dp->panel_vdd_work,
+                         ironlake_panel_vdd_work);
 
        intel_encoder->crtc_mask = (1 << 0) | (1 << 1) | (1 << 2);
 
@@ -2507,29 +2490,33 @@ intel_dp_init(struct drm_device *dev, int output_reg)
        intel_connector_attach_encoder(intel_connector, intel_encoder);
        drm_sysfs_connector_add(connector);
 
+       intel_encoder->enable = intel_enable_dp;
+       intel_encoder->pre_enable = intel_pre_enable_dp;
+       intel_encoder->disable = intel_disable_dp;
+       intel_encoder->post_disable = intel_post_disable_dp;
+       intel_encoder->get_hw_state = intel_dp_get_hw_state;
+       intel_connector->get_hw_state = intel_connector_get_hw_state;
+
        /* Set up the DDC bus. */
-       switch (output_reg) {
-               case DP_A:
-                       name = "DPDDC-A";
-                       break;
-               case DP_B:
-               case PCH_DP_B:
-                       dev_priv->hotplug_supported_mask |=
-                               DPB_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-B";
-                       break;
-               case DP_C:
-               case PCH_DP_C:
-                       dev_priv->hotplug_supported_mask |=
-                               DPC_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-C";
-                       break;
-               case DP_D:
-               case PCH_DP_D:
-                       dev_priv->hotplug_supported_mask |=
-                               DPD_HOTPLUG_INT_STATUS;
-                       name = "DPDDC-D";
-                       break;
+       switch (port) {
+       case PORT_A:
+               name = "DPDDC-A";
+               break;
+       case PORT_B:
+               dev_priv->hotplug_supported_mask |= DPB_HOTPLUG_INT_STATUS;
+               name = "DPDDC-B";
+               break;
+       case PORT_C:
+               dev_priv->hotplug_supported_mask |= DPC_HOTPLUG_INT_STATUS;
+               name = "DPDDC-C";
+               break;
+       case PORT_D:
+               dev_priv->hotplug_supported_mask |= DPD_HOTPLUG_INT_STATUS;
+               name = "DPDDC-D";
+               break;
+       default:
+               WARN(1, "Invalid port %c\n", port_name(port));
+               break;
        }
 
        /* Cache some DPCD data in the eDP case */