Merge branch 'topic/ice1724-pm' into for-linus
[pandora-kernel.git] / drivers / gpu / drm / i915 / intel_display.c
index 34c5046..748ed50 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "drm_crtc_helper.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_update_watermarks(struct drm_device *dev);
 
@@ -88,7 +90,7 @@ struct intel_limit {
 #define I8XX_P2_SLOW                 4
 #define I8XX_P2_FAST                 2
 #define I8XX_P2_LVDS_SLOW            14
-#define I8XX_P2_LVDS_FAST            14 /* No fast option */
+#define I8XX_P2_LVDS_FAST            7
 #define I8XX_P2_SLOW_LIMIT      165000
 
 #define I9XX_DOT_MIN             20000
@@ -601,6 +603,23 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
     return false;
 }
 
+struct drm_connector *
+intel_pipe_get_output (struct drm_crtc *crtc)
+{
+    struct drm_device *dev = crtc->dev;
+    struct drm_mode_config *mode_config = &dev->mode_config;
+    struct drm_connector *l_entry, *ret = NULL;
+
+    list_for_each_entry(l_entry, &mode_config->connector_list, head) {
+           if (l_entry->encoder &&
+               l_entry->encoder->crtc == crtc) {
+                   ret = l_entry;
+                   break;
+           }
+    }
+    return ret;
+}
+
 #define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
 /**
  * Returns whether the given set of divisors are valid for a given refclk with
@@ -647,7 +666,7 @@ intel_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        intel_clock_t clock;
        int err = target;
 
-       if (IS_I9XX(dev) && intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
+       if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
            (I915_READ(LVDS)) != 0) {
                /*
                 * For LVDS, if the panel is on, just rely on its current
@@ -790,6 +809,10 @@ intel_igdng_find_best_PLL(const intel_limit_t *limit, struct drm_crtc *crtc,
        int err_most = 47;
        found = false;
 
+       /* eDP has only 2 clock choice, no n/m/p setting */
+       if (HAS_eDP)
+               return true;
+
        if (intel_pipe_has_type(crtc, INTEL_OUTPUT_DISPLAYPORT))
                return intel_find_pll_igdng_dp(limit, crtc, target,
                                               refclk, best_clock);
@@ -1052,6 +1075,67 @@ static void i915_disable_vga (struct drm_device *dev)
        I915_WRITE(vga_reg, VGA_DISP_DISABLE);
 }
 
+static void igdng_disable_pll_edp (struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dpa_ctl;
+
+       DRM_DEBUG("\n");
+       dpa_ctl = I915_READ(DP_A);
+       dpa_ctl &= ~DP_PLL_ENABLE;
+       I915_WRITE(DP_A, dpa_ctl);
+}
+
+static void igdng_enable_pll_edp (struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dpa_ctl;
+
+       dpa_ctl = I915_READ(DP_A);
+       dpa_ctl |= DP_PLL_ENABLE;
+       I915_WRITE(DP_A, dpa_ctl);
+       udelay(200);
+}
+
+
+static void igdng_set_pll_edp (struct drm_crtc *crtc, int clock)
+{
+       struct drm_device *dev = crtc->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 dpa_ctl;
+
+       DRM_DEBUG("eDP PLL enable for clock %d\n", clock);
+       dpa_ctl = I915_READ(DP_A);
+       dpa_ctl &= ~DP_PLL_FREQ_MASK;
+
+       if (clock < 200000) {
+               u32 temp;
+               dpa_ctl |= DP_PLL_FREQ_160MHZ;
+               /* workaround for 160Mhz:
+                  1) program 0x4600c bits 15:0 = 0x8124
+                  2) program 0x46010 bit 0 = 1
+                  3) program 0x46034 bit 24 = 1
+                  4) program 0x64000 bit 14 = 1
+                  */
+               temp = I915_READ(0x4600c);
+               temp &= 0xffff0000;
+               I915_WRITE(0x4600c, temp | 0x8124);
+
+               temp = I915_READ(0x46010);
+               I915_WRITE(0x46010, temp | 1);
+
+               temp = I915_READ(0x46034);
+               I915_WRITE(0x46034, temp | (1 << 24));
+       } else {
+               dpa_ctl |= DP_PLL_FREQ_270MHZ;
+       }
+       I915_WRITE(DP_A, dpa_ctl);
+
+       udelay(500);
+}
+
 static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
 {
        struct drm_device *dev = crtc->dev;
@@ -1093,27 +1177,32 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
        case DRM_MODE_DPMS_STANDBY:
        case DRM_MODE_DPMS_SUSPEND:
                DRM_DEBUG("crtc %d dpms on\n", pipe);
-               /* enable PCH DPLL */
-               temp = I915_READ(pch_dpll_reg);
-               if ((temp & DPLL_VCO_ENABLE) == 0) {
-                       I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
-                       I915_READ(pch_dpll_reg);
-               }
-
-               /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
-               temp = I915_READ(fdi_rx_reg);
-               I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
-                               FDI_SEL_PCDCLK |
-                               FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
-               I915_READ(fdi_rx_reg);
-               udelay(200);
+               if (HAS_eDP) {
+                       /* enable eDP PLL */
+                       igdng_enable_pll_edp(crtc);
+               } else {
+                       /* enable PCH DPLL */
+                       temp = I915_READ(pch_dpll_reg);
+                       if ((temp & DPLL_VCO_ENABLE) == 0) {
+                               I915_WRITE(pch_dpll_reg, temp | DPLL_VCO_ENABLE);
+                               I915_READ(pch_dpll_reg);
+                       }
 
-               /* Enable CPU FDI TX PLL, always on for IGDNG */
-               temp = I915_READ(fdi_tx_reg);
-               if ((temp & FDI_TX_PLL_ENABLE) == 0) {
-                       I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
-                       I915_READ(fdi_tx_reg);
-                       udelay(100);
+                       /* enable PCH FDI RX PLL, wait warmup plus DMI latency */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE |
+                                       FDI_SEL_PCDCLK |
+                                       FDI_DP_PORT_WIDTH_X4); /* default 4 lanes */
+                       I915_READ(fdi_rx_reg);
+                       udelay(200);
+
+                       /* Enable CPU FDI TX PLL, always on for IGDNG */
+                       temp = I915_READ(fdi_tx_reg);
+                       if ((temp & FDI_TX_PLL_ENABLE) == 0) {
+                               I915_WRITE(fdi_tx_reg, temp | FDI_TX_PLL_ENABLE);
+                               I915_READ(fdi_tx_reg);
+                               udelay(100);
+                       }
                }
 
                /* Enable CPU pipe */
@@ -1132,122 +1221,126 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                        I915_WRITE(dspbase_reg, I915_READ(dspbase_reg));
                }
 
-               /* enable CPU FDI TX and PCH FDI RX */
-               temp = I915_READ(fdi_tx_reg);
-               temp |= FDI_TX_ENABLE;
-               temp |= FDI_DP_PORT_WIDTH_X4; /* default */
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_1;
-               I915_WRITE(fdi_tx_reg, temp);
-               I915_READ(fdi_tx_reg);
+               if (!HAS_eDP) {
+                       /* enable CPU FDI TX and PCH FDI RX */
+                       temp = I915_READ(fdi_tx_reg);
+                       temp |= FDI_TX_ENABLE;
+                       temp |= FDI_DP_PORT_WIDTH_X4; /* default */
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+                       I915_WRITE(fdi_tx_reg, temp);
+                       I915_READ(fdi_tx_reg);
 
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_1;
-               I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
-               I915_READ(fdi_rx_reg);
+                       temp = I915_READ(fdi_rx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_1;
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_ENABLE);
+                       I915_READ(fdi_rx_reg);
 
-               udelay(150);
+                       udelay(150);
 
-               /* Train FDI. */
-               /* umask FDI RX Interrupt symbol_lock and bit_lock bit
-                  for train result */
-               temp = I915_READ(fdi_rx_imr_reg);
-               temp &= ~FDI_RX_SYMBOL_LOCK;
-               temp &= ~FDI_RX_BIT_LOCK;
-               I915_WRITE(fdi_rx_imr_reg, temp);
-               I915_READ(fdi_rx_imr_reg);
-               udelay(150);
+                       /* Train FDI. */
+                       /* umask FDI RX Interrupt symbol_lock and bit_lock bit
+                          for train result */
+                       temp = I915_READ(fdi_rx_imr_reg);
+                       temp &= ~FDI_RX_SYMBOL_LOCK;
+                       temp &= ~FDI_RX_BIT_LOCK;
+                       I915_WRITE(fdi_rx_imr_reg, temp);
+                       I915_READ(fdi_rx_imr_reg);
+                       udelay(150);
 
-               temp = I915_READ(fdi_rx_iir_reg);
-               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                       temp = I915_READ(fdi_rx_iir_reg);
+                       DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
 
-               if ((temp & FDI_RX_BIT_LOCK) == 0) {
-                       for (j = 0; j < tries; j++) {
-                               temp = I915_READ(fdi_rx_iir_reg);
-                               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
-                               if (temp & FDI_RX_BIT_LOCK)
-                                       break;
-                               udelay(200);
-                       }
-                       if (j != tries)
+                       if ((temp & FDI_RX_BIT_LOCK) == 0) {
+                               for (j = 0; j < tries; j++) {
+                                       temp = I915_READ(fdi_rx_iir_reg);
+                                       DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                                       if (temp & FDI_RX_BIT_LOCK)
+                                               break;
+                                       udelay(200);
+                               }
+                               if (j != tries)
+                                       I915_WRITE(fdi_rx_iir_reg,
+                                                       temp | FDI_RX_BIT_LOCK);
+                               else
+                                       DRM_DEBUG("train 1 fail\n");
+                       } else {
                                I915_WRITE(fdi_rx_iir_reg,
                                                temp | FDI_RX_BIT_LOCK);
-                       else
-                               DRM_DEBUG("train 1 fail\n");
-               } else {
-                       I915_WRITE(fdi_rx_iir_reg,
-                                       temp | FDI_RX_BIT_LOCK);
-                       DRM_DEBUG("train 1 ok 2!\n");
-               }
-               temp = I915_READ(fdi_tx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_2;
-               I915_WRITE(fdi_tx_reg, temp);
-
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               temp |= FDI_LINK_TRAIN_PATTERN_2;
-               I915_WRITE(fdi_rx_reg, temp);
+                               DRM_DEBUG("train 1 ok 2!\n");
+                       }
+                       temp = I915_READ(fdi_tx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_2;
+                       I915_WRITE(fdi_tx_reg, temp);
+
+                       temp = I915_READ(fdi_rx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       temp |= FDI_LINK_TRAIN_PATTERN_2;
+                       I915_WRITE(fdi_rx_reg, temp);
 
-               udelay(150);
+                       udelay(150);
 
-               temp = I915_READ(fdi_rx_iir_reg);
-               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                       temp = I915_READ(fdi_rx_iir_reg);
+                       DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
 
-               if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
-                       for (j = 0; j < tries; j++) {
-                               temp = I915_READ(fdi_rx_iir_reg);
-                               DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
-                               if (temp & FDI_RX_SYMBOL_LOCK)
-                                       break;
-                               udelay(200);
-                       }
-                       if (j != tries) {
+                       if ((temp & FDI_RX_SYMBOL_LOCK) == 0) {
+                               for (j = 0; j < tries; j++) {
+                                       temp = I915_READ(fdi_rx_iir_reg);
+                                       DRM_DEBUG("FDI_RX_IIR 0x%x\n", temp);
+                                       if (temp & FDI_RX_SYMBOL_LOCK)
+                                               break;
+                                       udelay(200);
+                               }
+                               if (j != tries) {
+                                       I915_WRITE(fdi_rx_iir_reg,
+                                                       temp | FDI_RX_SYMBOL_LOCK);
+                                       DRM_DEBUG("train 2 ok 1!\n");
+                               } else
+                                       DRM_DEBUG("train 2 fail\n");
+                       } else {
                                I915_WRITE(fdi_rx_iir_reg,
                                                temp | FDI_RX_SYMBOL_LOCK);
-                               DRM_DEBUG("train 2 ok 1!\n");
-                       } else
-                               DRM_DEBUG("train 2 fail\n");
-               } else {
-                       I915_WRITE(fdi_rx_iir_reg, temp | FDI_RX_SYMBOL_LOCK);
-                       DRM_DEBUG("train 2 ok 2!\n");
-               }
-               DRM_DEBUG("train done\n");
+                               DRM_DEBUG("train 2 ok 2!\n");
+                       }
+                       DRM_DEBUG("train done\n");
 
-               /* set transcoder timing */
-               I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
-               I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
-               I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
+                       /* set transcoder timing */
+                       I915_WRITE(trans_htot_reg, I915_READ(cpu_htot_reg));
+                       I915_WRITE(trans_hblank_reg, I915_READ(cpu_hblank_reg));
+                       I915_WRITE(trans_hsync_reg, I915_READ(cpu_hsync_reg));
 
-               I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
-               I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
-               I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
+                       I915_WRITE(trans_vtot_reg, I915_READ(cpu_vtot_reg));
+                       I915_WRITE(trans_vblank_reg, I915_READ(cpu_vblank_reg));
+                       I915_WRITE(trans_vsync_reg, I915_READ(cpu_vsync_reg));
 
-               /* enable PCH transcoder */
-               temp = I915_READ(transconf_reg);
-               I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
-               I915_READ(transconf_reg);
+                       /* enable PCH transcoder */
+                       temp = I915_READ(transconf_reg);
+                       I915_WRITE(transconf_reg, temp | TRANS_ENABLE);
+                       I915_READ(transconf_reg);
 
-               while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
-                       ;
+                       while ((I915_READ(transconf_reg) & TRANS_STATE_ENABLE) == 0)
+                               ;
 
-               /* enable normal */
+                       /* enable normal */
 
-               temp = I915_READ(fdi_tx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
-                               FDI_TX_ENHANCE_FRAME_ENABLE);
-               I915_READ(fdi_tx_reg);
+                       temp = I915_READ(fdi_tx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       I915_WRITE(fdi_tx_reg, temp | FDI_LINK_TRAIN_NONE |
+                                       FDI_TX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_tx_reg);
 
-               temp = I915_READ(fdi_rx_reg);
-               temp &= ~FDI_LINK_TRAIN_NONE;
-               I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
-                               FDI_RX_ENHANCE_FRAME_ENABLE);
-               I915_READ(fdi_rx_reg);
+                       temp = I915_READ(fdi_rx_reg);
+                       temp &= ~FDI_LINK_TRAIN_NONE;
+                       I915_WRITE(fdi_rx_reg, temp | FDI_LINK_TRAIN_NONE |
+                                       FDI_RX_ENHANCE_FRAME_ENABLE);
+                       I915_READ(fdi_rx_reg);
 
-               /* wait one idle pattern time */
-               udelay(100);
+                       /* wait one idle pattern time */
+                       udelay(100);
+
+               }
 
                intel_crtc_load_lut(crtc);
 
@@ -1286,6 +1379,10 @@ static void igdng_crtc_dpms(struct drm_crtc *crtc, int mode)
                } else
                        DRM_DEBUG("crtc %d is disabled\n", pipe);
 
+               if (HAS_eDP) {
+                       igdng_disable_pll_edp(crtc);
+               }
+
                /* disable CPU FDI tx and PCH FDI rx */
                temp = I915_READ(fdi_tx_reg);
                I915_WRITE(fdi_tx_reg, temp & ~FDI_TX_ENABLE);
@@ -1908,7 +2005,21 @@ static void igd_enable_cxsr(struct drm_device *dev, unsigned long clock,
        return;
 }
 
-const static int latency_ns = 3000; /* default for non-igd platforms */
+/*
+ * Latency for FIFO fetches is dependent on several factors:
+ *   - memory configuration (speed, channels)
+ *   - chipset
+ *   - current MCH state
+ * It can be fairly high in some situations, so here we assume a fairly
+ * pessimal value.  It's a tradeoff between extra memory fetches (if we
+ * set this value too high, the FIFO will fetch frequently to stay full)
+ * and power consumption (set it too low to save power and we might see
+ * FIFO underruns and display "flicker").
+ *
+ * A value of 5us seems to be a good balance; safe for very low end
+ * platforms but not overly aggressive on lower latency configs.
+ */
+const static int latency_ns = 5000;
 
 static int intel_get_fifo_size(struct drm_device *dev, int plane)
 {
@@ -1929,6 +2040,9 @@ static int intel_get_fifo_size(struct drm_device *dev, int plane)
                        size = ((dsparb >> DSPARB_BEND_SHIFT) & 0x1ff) -
                                (dsparb & 0x1ff);
                size >>= 1; /* Convert to cachelines */
+       } else if (IS_845G(dev)) {
+               size = dsparb & 0x7f;
+               size >>= 2; /* Convert to cachelines */
        } else {
                size = dsparb & 0x7f;
                size >>= 1; /* Convert to cachelines */
@@ -2028,14 +2142,16 @@ static void i830_update_wm(struct drm_device *dev, int planea_clock,
                           int pixel_size)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t fwater_lo = I915_READ(FW_BLC) & MM_FIFO_WATERMARK;
+       uint32_t fwater_lo = I915_READ(FW_BLC) & ~0xfff;
        int planea_wm;
 
        i830_wm_info.fifo_size = intel_get_fifo_size(dev, 0);
 
        planea_wm = intel_calculate_wm(planea_clock, &i830_wm_info,
                                       pixel_size, latency_ns);
-       fwater_lo = fwater_lo | planea_wm;
+       fwater_lo |= (3<<8) | planea_wm;
+
+       DRM_DEBUG("Setting FIFO watermarks - A: %d\n", planea_wm);
 
        I915_WRITE(FW_BLC, fwater_lo);
 }
@@ -2152,6 +2268,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        u32 dpll = 0, fp = 0, dspcntr, pipeconf;
        bool ok, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false, is_dp = false;
+       bool is_edp = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
        const intel_limit_t *limit;
@@ -2199,6 +2316,9 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                case INTEL_OUTPUT_DISPLAYPORT:
                        is_dp = true;
                        break;
+               case INTEL_OUTPUT_EDP:
+                       is_edp = true;
+                       break;
                }
 
                num_outputs++;
@@ -2251,16 +2371,27 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 
        /* FDI link */
        if (IS_IGDNG(dev)) {
-               /* DP over FDI requires target mode clock
-                  instead of link clock */
-               if (is_dp)
+               int lane, link_bw;
+               /* eDP doesn't require FDI link, so just set DP M/N
+                  according to current link config */
+               if (is_edp) {
+                       struct drm_connector *edp;
                        target_clock = mode->clock;
-               else
-                       target_clock = adjusted_mode->clock;
-               igdng_compute_m_n(3, 4, /* lane num 4 */
-                               target_clock,
-                               270000, /* lane clock */
-                               &m_n);
+                       edp = intel_pipe_get_output(crtc);
+                       intel_edp_link_config(to_intel_output(edp),
+                                       &lane, &link_bw);
+               } else {
+                       /* DP over FDI requires target mode clock
+                          instead of link clock */
+                       if (is_dp)
+                               target_clock = mode->clock;
+                       else
+                               target_clock = adjusted_mode->clock;
+                       lane = 4;
+                       link_bw = 270000;
+               }
+               igdng_compute_m_n(3, lane, target_clock,
+                                 link_bw, &m_n);
        }
 
        if (IS_IGD(dev))
@@ -2279,7 +2410,7 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                if (is_sdvo) {
                        dpll |= DPLL_DVO_HIGH_SPEED;
                        sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-                       if (IS_I945G(dev) || IS_I945GM(dev))
+                       if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << SDVO_MULTIPLIER_SHIFT_HIRES;
                        else if (IS_IGDNG(dev))
                                dpll |= (sdvo_pixel_multiply - 1) << PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
@@ -2382,29 +2513,15 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                dpll_reg = pch_dpll_reg;
        }
 
-       if (dpll & DPLL_VCO_ENABLE) {
+       if (is_edp) {
+               igdng_disable_pll_edp(crtc);
+       } else if ((dpll & DPLL_VCO_ENABLE)) {
                I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll & ~DPLL_VCO_ENABLE);
                I915_READ(dpll_reg);
                udelay(150);
        }
 
-       if (IS_IGDNG(dev)) {
-               /* enable PCH clock reference source */
-               /* XXX need to change the setting for other outputs */
-               u32 temp;
-               temp = I915_READ(PCH_DREF_CONTROL);
-               temp &= ~DREF_NONSPREAD_SOURCE_MASK;
-               temp |= DREF_NONSPREAD_CK505_ENABLE;
-               temp &= ~DREF_SSC_SOURCE_MASK;
-               temp |= DREF_SSC_SOURCE_ENABLE;
-               temp &= ~DREF_SSC1_ENABLE;
-               /* if no eDP, disable source output to CPU */
-               temp &= ~DREF_CPU_SOURCE_OUTPUT_MASK;
-               temp |= DREF_CPU_SOURCE_OUTPUT_DISABLE;
-               I915_WRITE(PCH_DREF_CONTROL, temp);
-       }
-
        /* The LVDS pin pair needs to be on before the DPLLs are enabled.
         * This is an exception to the general rule that mode_set doesn't turn
         * things on.
@@ -2436,23 +2553,25 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
        if (is_dp)
                intel_dp_set_m_n(crtc, mode, adjusted_mode);
 
-       I915_WRITE(fp_reg, fp);
-       I915_WRITE(dpll_reg, dpll);
-       I915_READ(dpll_reg);
-       /* Wait for the clocks to stabilize. */
-       udelay(150);
-
-       if (IS_I965G(dev) && !IS_IGDNG(dev)) {
-               sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
-               I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
-                          ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
-       } else {
-               /* write it again -- the BIOS does, after all */
+       if (!is_edp) {
+               I915_WRITE(fp_reg, fp);
                I915_WRITE(dpll_reg, dpll);
+               I915_READ(dpll_reg);
+               /* Wait for the clocks to stabilize. */
+               udelay(150);
+
+               if (IS_I965G(dev) && !IS_IGDNG(dev)) {
+                       sdvo_pixel_multiply = adjusted_mode->clock / mode->clock;
+                       I915_WRITE(dpll_md_reg, (0 << DPLL_MD_UDI_DIVIDER_SHIFT) |
+                                       ((sdvo_pixel_multiply - 1) << DPLL_MD_UDI_MULTIPLIER_SHIFT));
+               } else {
+                       /* write it again -- the BIOS does, after all */
+                       I915_WRITE(dpll_reg, dpll);
+               }
+               I915_READ(dpll_reg);
+               /* Wait for the clocks to stabilize. */
+               udelay(150);
        }
-       I915_READ(dpll_reg);
-       /* Wait for the clocks to stabilize. */
-       udelay(150);
 
        I915_WRITE(htot_reg, (adjusted_mode->crtc_hdisplay - 1) |
                   ((adjusted_mode->crtc_htotal - 1) << 16));
@@ -2482,10 +2601,14 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
                I915_WRITE(link_m1_reg, m_n.link_m);
                I915_WRITE(link_n1_reg, m_n.link_n);
 
-                /* enable FDI RX PLL too */
-               temp = I915_READ(fdi_rx_reg);
-               I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
-               udelay(200);
+               if (is_edp) {
+                       igdng_set_pll_edp(crtc, adjusted_mode->clock);
+               } else {
+                       /* enable FDI RX PLL too */
+                       temp = I915_READ(fdi_rx_reg);
+                       I915_WRITE(fdi_rx_reg, temp | FDI_RX_PLL_ENABLE);
+                       udelay(200);
+               }
        }
 
        I915_WRITE(pipeconf_reg, pipeconf);
@@ -3061,7 +3184,7 @@ static int intel_connector_clones(struct drm_device *dev, int type_mask)
 
         list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct intel_output *intel_output = to_intel_output(connector);
-               if (type_mask & (1 << intel_output->type))
+               if (type_mask & intel_output->clone_mask)
                        index_mask |= (1 << entry);
                entry++;
        }
@@ -3083,6 +3206,9 @@ static void intel_setup_outputs(struct drm_device *dev)
        if (IS_IGDNG(dev)) {
                int found;
 
+               if (IS_MOBILE(dev) && (I915_READ(DP_A) & DP_DETECTED))
+                       intel_dp_init(dev, DP_A);
+
                if (I915_READ(HDMIB) & PORT_DETECTED) {
                        /* check SDVOB */
                        /* found = intel_sdvo_init(dev, HDMIB); */
@@ -3106,30 +3232,30 @@ static void intel_setup_outputs(struct drm_device *dev)
                        intel_dp_init(dev, PCH_DP_D);
 
        } else if (IS_I9XX(dev)) {
-               int found;
-               u32 reg;
+               bool found = false;
 
                if (I915_READ(SDVOB) & SDVO_DETECTED) {
                        found = intel_sdvo_init(dev, SDVOB);
                        if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOB);
+
                        if (!found && SUPPORTS_INTEGRATED_DP(dev))
                                intel_dp_init(dev, DP_B);
                }
 
                /* Before G4X SDVOC doesn't have its own detect register */
-               if (IS_G4X(dev))
-                       reg = SDVOC;
-               else
-                       reg = SDVOB;
 
-               if (I915_READ(reg) & SDVO_DETECTED) {
+               if (I915_READ(SDVOB) & SDVO_DETECTED)
                        found = intel_sdvo_init(dev, SDVOC);
-                       if (!found && SUPPORTS_INTEGRATED_HDMI(dev))
+
+               if (!found && (I915_READ(SDVOC) & SDVO_DETECTED)) {
+
+                       if (SUPPORTS_INTEGRATED_HDMI(dev))
                                intel_hdmi_init(dev, SDVOC);
-                       if (!found && SUPPORTS_INTEGRATED_DP(dev))
+                       if (SUPPORTS_INTEGRATED_DP(dev))
                                intel_dp_init(dev, DP_C);
                }
+
                if (SUPPORTS_INTEGRATED_DP(dev) && (I915_READ(DP_D) & DP_DETECTED))
                        intel_dp_init(dev, DP_D);
        } else
@@ -3141,47 +3267,10 @@ static void intel_setup_outputs(struct drm_device *dev)
        list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
                struct intel_output *intel_output = to_intel_output(connector);
                struct drm_encoder *encoder = &intel_output->enc;
-               int crtc_mask = 0, clone_mask = 0;
 
-               /* valid crtcs */
-               switch(intel_output->type) {
-               case INTEL_OUTPUT_HDMI:
-                       crtc_mask = ((1 << 0)|
-                                    (1 << 1));
-                       clone_mask = ((1 << INTEL_OUTPUT_HDMI));
-                       break;
-               case INTEL_OUTPUT_DVO:
-               case INTEL_OUTPUT_SDVO:
-                       crtc_mask = ((1 << 0)|
-                                    (1 << 1));
-                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
-                                     (1 << INTEL_OUTPUT_DVO) |
-                                     (1 << INTEL_OUTPUT_SDVO));
-                       break;
-               case INTEL_OUTPUT_ANALOG:
-                       crtc_mask = ((1 << 0)|
-                                    (1 << 1));
-                       clone_mask = ((1 << INTEL_OUTPUT_ANALOG) |
-                                     (1 << INTEL_OUTPUT_DVO) |
-                                     (1 << INTEL_OUTPUT_SDVO));
-                       break;
-               case INTEL_OUTPUT_LVDS:
-                       crtc_mask = (1 << 1);
-                       clone_mask = (1 << INTEL_OUTPUT_LVDS);
-                       break;
-               case INTEL_OUTPUT_TVOUT:
-                       crtc_mask = ((1 << 0) |
-                                    (1 << 1));
-                       clone_mask = (1 << INTEL_OUTPUT_TVOUT);
-                       break;
-               case INTEL_OUTPUT_DISPLAYPORT:
-                       crtc_mask = ((1 << 0) |
-                                    (1 << 1));
-                       clone_mask = (1 << INTEL_OUTPUT_DISPLAYPORT);
-                       break;
-               }
-               encoder->possible_crtcs = crtc_mask;
-               encoder->possible_clones = intel_connector_clones(dev, clone_mask);
+               encoder->possible_crtcs = intel_output->crtc_mask;
+               encoder->possible_clones = intel_connector_clones(dev,
+                                               intel_output->clone_mask);
        }
 }