drm/i915: Hook up Ivybridge eDP
authorKeith Packard <keithp@keithp.com>
Thu, 17 Nov 2011 00:26:07 +0000 (16:26 -0800)
committerKeith Packard <keithp@keithp.com>
Wed, 23 Nov 2011 21:07:12 +0000 (13:07 -0800)
The Ivybridge eDP control register looks like a cross between a
Cougarpoint PCH DP control register and a Sandybridge eDP control
register.

Where things trivially match, share the code. Where there are any
tricky bits, just split things out into two obviously separate code paths.

Signed-off-by: Keith Packard <keithp@keithp.com>
Tested-by: Fang Xun <xunx.fang@intel.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=41991

drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_dp.c

index 8990057e384c409125c4dd8e65815a8a7aa9aced..6ef68c74189dc2f8127bc06dfb4bd23432efc3c7 100644 (file)
 #define  EDP_LINK_TRAIN_800_1200MV_0DB_SNB_B   (0x38<<22)
 #define  EDP_LINK_TRAIN_VOL_EMP_MASK_SNB       (0x3f<<22)
 
+/* IVB */
+#define EDP_LINK_TRAIN_400MV_0DB_IVB           (0x24 <<22)
+#define EDP_LINK_TRAIN_400MV_3_5DB_IVB         (0x2a <<22)
+#define EDP_LINK_TRAIN_400MV_6DB_IVB           (0x2f <<22)
+#define EDP_LINK_TRAIN_600MV_0DB_IVB           (0x30 <<22)
+#define EDP_LINK_TRAIN_600MV_3_5DB_IVB         (0x36 <<22)
+#define EDP_LINK_TRAIN_800MV_0DB_IVB           (0x38 <<22)
+#define EDP_LINK_TRAIN_800MV_3_5DB_IVB         (0x33 <<22)
+
+/* legacy values */
+#define EDP_LINK_TRAIN_500MV_0DB_IVB           (0x00 <<22)
+#define EDP_LINK_TRAIN_1000MV_0DB_IVB          (0x20 <<22)
+#define EDP_LINK_TRAIN_500MV_3_5DB_IVB         (0x02 <<22)
+#define EDP_LINK_TRAIN_1000MV_3_5DB_IVB                (0x22 <<22)
+#define EDP_LINK_TRAIN_1000MV_6DB_IVB          (0x23 <<22)
+
+#define  EDP_LINK_TRAIN_VOL_EMP_MASK_IVB       (0x3f<<22)
+
 #define  FORCEWAKE                             0xA18C
 #define  FORCEWAKE_ACK                         0x130090
 #define  FORCEWAKE_MT                          0xa188 /* multi-threaded */
index 4d0358fad93795c31dd9d4229daa3c7c2ecedcc5..294f55788f0b3c30dde8689cadee2a5837228866 100644 (file)
@@ -362,8 +362,8 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
         * clock divider.
         */
        if (is_cpu_edp(intel_dp)) {
-               if (IS_GEN6(dev))
-                       aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
+               if (IS_GEN6(dev) || IS_GEN7(dev))
+                       aux_clock_divider = 200; /* SNB & IVB eDP input clock at 400Mhz */
                else
                        aux_clock_divider = 225; /* eDP input clock at 450Mhz */
        } else if (HAS_PCH_SPLIT(dev))
@@ -817,10 +817,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
        }
 
        /*
-        * There are three kinds of DP registers:
+        * There are four kinds of DP registers:
         *
         *      IBX PCH
-        *      CPU
+        *      SNB CPU
+        *      IVB CPU
         *      CPT PCH
         *
         * IBX PCH and CPU are the same for almost everything,
@@ -873,7 +874,25 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
 
        /* Split out the IBX/CPU vs CPT settings */
 
-       if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
+       if (is_cpu_edp(intel_dp) && IS_GEN7(dev)) {
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
+                       intel_dp->DP |= DP_SYNC_HS_HIGH;
+               if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
+                       intel_dp->DP |= DP_SYNC_VS_HIGH;
+               intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
+
+               if (intel_dp->link_configuration[1] & DP_LANE_COUNT_ENHANCED_FRAME_EN)
+                       intel_dp->DP |= DP_ENHANCED_FRAMING;
+
+               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
+                       intel_dp->DP |= DP_PLL_FREQ_270MHZ;
+       } else if (!HAS_PCH_CPT(dev) || is_cpu_edp(intel_dp)) {
                intel_dp->DP |= intel_dp->color_range;
 
                if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
@@ -1375,34 +1394,59 @@ static char     *link_train_names[] = {
  * These are source-specific values; current Intel hardware supports
  * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
  */
-#define I830_DP_VOLTAGE_MAX        DP_TRAIN_VOLTAGE_SWING_800
-#define I830_DP_VOLTAGE_MAX_CPT            DP_TRAIN_VOLTAGE_SWING_1200
 
 static uint8_t
-intel_dp_pre_emphasis_max(uint8_t voltage_swing)
+intel_dp_voltage_max(struct intel_dp *intel_dp)
 {
-       switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
-       case DP_TRAIN_VOLTAGE_SWING_400:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_600:
-               return DP_TRAIN_PRE_EMPHASIS_6;
-       case DP_TRAIN_VOLTAGE_SWING_800:
-               return DP_TRAIN_PRE_EMPHASIS_3_5;
-       case DP_TRAIN_VOLTAGE_SWING_1200:
-       default:
-               return DP_TRAIN_PRE_EMPHASIS_0;
+       struct drm_device *dev = intel_dp->base.base.dev;
+
+       if (IS_GEN7(dev) && is_cpu_edp(intel_dp))
+               return DP_TRAIN_VOLTAGE_SWING_800;
+       else if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+               return DP_TRAIN_VOLTAGE_SWING_1200;
+       else
+               return DP_TRAIN_VOLTAGE_SWING_800;
+}
+
+static uint8_t
+intel_dp_pre_emphasis_max(struct intel_dp *intel_dp, uint8_t voltage_swing)
+{
+       struct drm_device *dev = intel_dp->base.base.dev;
+
+       if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_400:
+                       return DP_TRAIN_PRE_EMPHASIS_6;
+               case DP_TRAIN_VOLTAGE_SWING_600:
+               case DP_TRAIN_VOLTAGE_SWING_800:
+                       return DP_TRAIN_PRE_EMPHASIS_3_5;
+               default:
+                       return DP_TRAIN_PRE_EMPHASIS_0;
+               }
+       } else {
+               switch (voltage_swing & DP_TRAIN_VOLTAGE_SWING_MASK) {
+               case DP_TRAIN_VOLTAGE_SWING_400:
+                       return DP_TRAIN_PRE_EMPHASIS_6;
+               case DP_TRAIN_VOLTAGE_SWING_600:
+                       return DP_TRAIN_PRE_EMPHASIS_6;
+               case DP_TRAIN_VOLTAGE_SWING_800:
+                       return DP_TRAIN_PRE_EMPHASIS_3_5;
+               case DP_TRAIN_VOLTAGE_SWING_1200:
+               default:
+                       return DP_TRAIN_PRE_EMPHASIS_0;
+               }
        }
 }
 
 static void
 intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_STATUS_SIZE])
 {
-       struct drm_device *dev = intel_dp->base.base.dev;
        uint8_t v = 0;
        uint8_t p = 0;
        int lane;
        uint8_t *adjust_request = link_status + (DP_ADJUST_REQUEST_LANE0_1 - DP_LANE0_1_STATUS);
-       int voltage_max;
+       uint8_t voltage_max;
+       uint8_t preemph_max;
 
        for (lane = 0; lane < intel_dp->lane_count; lane++) {
                uint8_t this_v = intel_get_adjust_request_voltage(adjust_request, lane);
@@ -1414,15 +1458,13 @@ intel_get_adjust_train(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_ST
                        p = this_p;
        }
 
-       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
-               voltage_max = I830_DP_VOLTAGE_MAX_CPT;
-       else
-               voltage_max = I830_DP_VOLTAGE_MAX;
+       voltage_max = intel_dp_voltage_max(intel_dp);
        if (v >= voltage_max)
                v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
 
-       if (p >= intel_dp_pre_emphasis_max(v))
-               p = intel_dp_pre_emphasis_max(v) | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
+       preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
+       if (p >= preemph_max)
+               p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 
        for (lane = 0; lane < 4; lane++)
                intel_dp->train_set[lane] = v | p;
@@ -1494,6 +1536,37 @@ intel_gen6_edp_signal_levels(uint8_t train_set)
        }
 }
 
+/* Gen7's DP voltage swing and pre-emphasis control */
+static uint32_t
+intel_gen7_edp_signal_levels(uint8_t train_set)
+{
+       int signal_levels = train_set & (DP_TRAIN_VOLTAGE_SWING_MASK |
+                                        DP_TRAIN_PRE_EMPHASIS_MASK);
+       switch (signal_levels) {
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_0:
+               return EDP_LINK_TRAIN_400MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return EDP_LINK_TRAIN_400MV_3_5DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_400 | DP_TRAIN_PRE_EMPHASIS_6:
+               return EDP_LINK_TRAIN_400MV_6DB_IVB;
+
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_0:
+               return EDP_LINK_TRAIN_600MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_600 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return EDP_LINK_TRAIN_600MV_3_5DB_IVB;
+
+       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_0:
+               return EDP_LINK_TRAIN_800MV_0DB_IVB;
+       case DP_TRAIN_VOLTAGE_SWING_800 | DP_TRAIN_PRE_EMPHASIS_3_5:
+               return EDP_LINK_TRAIN_800MV_3_5DB_IVB;
+
+       default:
+               DRM_DEBUG_KMS("Unsupported voltage swing/pre-emphasis level:"
+                             "0x%x\n", signal_levels);
+               return EDP_LINK_TRAIN_500MV_0DB_IVB;
+       }
+}
+
 static uint8_t
 intel_get_lane_status(uint8_t link_status[DP_LINK_STATUS_SIZE],
                      int lane)
@@ -1599,7 +1672,8 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
                                  DP_LINK_CONFIGURATION_SIZE);
 
        DP |= DP_PORT_EN;
-       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+
+       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;
@@ -1613,7 +1687,11 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
                uint8_t     link_status[DP_LINK_STATUS_SIZE];
                uint32_t    signal_levels;
 
-               if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
+
+               if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
+                       signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
+                       DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
+               } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
                        signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
@@ -1622,7 +1700,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_cpu_edp(intel_dp))
+               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;
@@ -1703,7 +1781,10 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                        break;
                }
 
-               if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
+               if (IS_GEN7(dev) && is_cpu_edp(intel_dp)) {
+                       signal_levels = intel_gen7_edp_signal_levels(intel_dp->train_set[0]);
+                       DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_IVB) | signal_levels;
+               } else if (IS_GEN6(dev) && is_cpu_edp(intel_dp)) {
                        signal_levels = intel_gen6_edp_signal_levels(intel_dp->train_set[0]);
                        DP = (DP & ~EDP_LINK_TRAIN_VOL_EMP_MASK_SNB) | signal_levels;
                } else {
@@ -1711,7 +1792,7 @@ 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_cpu_edp(intel_dp))
+               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;
@@ -1752,7 +1833,7 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
                ++tries;
        }
 
-       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp))
+       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;
@@ -1782,7 +1863,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
                udelay(100);
        }
 
-       if (HAS_PCH_CPT(dev) && !is_cpu_edp(intel_dp)) {
+       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);
        } else {
@@ -1794,7 +1875,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
        msleep(17);
 
        if (is_edp(intel_dp)) {
-               if (HAS_PCH_CPT(dev) && !is_cpu_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;