|
@@ -208,13 +208,15 @@ intel_dp_link_clock(uint8_t link_bw)
|
|
|
*/
|
|
|
|
|
|
static int
|
|
|
-intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock)
|
|
|
+intel_dp_link_required(struct intel_dp *intel_dp, int pixel_clock, int check_bpp)
|
|
|
{
|
|
|
struct drm_crtc *crtc = intel_dp->base.base.crtc;
|
|
|
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
|
|
|
int bpp = 24;
|
|
|
|
|
|
- if (intel_crtc)
|
|
|
+ if (check_bpp)
|
|
|
+ bpp = check_bpp;
|
|
|
+ else if (intel_crtc)
|
|
|
bpp = intel_crtc->bpp;
|
|
|
|
|
|
return (pixel_clock * bpp + 9) / 10;
|
|
@@ -233,6 +235,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|
|
struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
int max_link_clock = intel_dp_link_clock(intel_dp_max_link_bw(intel_dp));
|
|
|
int max_lanes = intel_dp_max_lane_count(intel_dp);
|
|
|
+ int max_rate, mode_rate;
|
|
|
|
|
|
if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
|
|
|
if (mode->hdisplay > intel_dp->panel_fixed_mode->hdisplay)
|
|
@@ -242,9 +245,17 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|
|
return MODE_PANEL;
|
|
|
}
|
|
|
|
|
|
- if (intel_dp_link_required(intel_dp, mode->clock)
|
|
|
- > intel_dp_max_data_rate(max_link_clock, max_lanes))
|
|
|
- return MODE_CLOCK_HIGH;
|
|
|
+ mode_rate = intel_dp_link_required(intel_dp, mode->clock, 0);
|
|
|
+ max_rate = intel_dp_max_data_rate(max_link_clock, max_lanes);
|
|
|
+
|
|
|
+ if (mode_rate > max_rate) {
|
|
|
+ mode_rate = intel_dp_link_required(intel_dp,
|
|
|
+ mode->clock, 18);
|
|
|
+ if (mode_rate > max_rate)
|
|
|
+ return MODE_CLOCK_HIGH;
|
|
|
+ else
|
|
|
+ mode->private_flags |= INTEL_MODE_DP_FORCE_6BPC;
|
|
|
+ }
|
|
|
|
|
|
if (mode->clock < 10000)
|
|
|
return MODE_CLOCK_LOW;
|
|
@@ -362,8 +373,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))
|
|
@@ -672,6 +683,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
int lane_count, clock;
|
|
|
int max_lane_count = intel_dp_max_lane_count(intel_dp);
|
|
|
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
|
|
|
+ int bpp = mode->private_flags & INTEL_MODE_DP_FORCE_6BPC ? 18 : 0;
|
|
|
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
|
|
|
|
|
|
if (is_edp(intel_dp) && intel_dp->panel_fixed_mode) {
|
|
@@ -689,7 +701,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
for (clock = 0; clock <= max_clock; clock++) {
|
|
|
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
|
|
|
|
|
|
- if (intel_dp_link_required(intel_dp, mode->clock)
|
|
|
+ if (intel_dp_link_required(intel_dp, mode->clock, bpp)
|
|
|
<= link_avail) {
|
|
|
intel_dp->link_bw = bws[clock];
|
|
|
intel_dp->lane_count = lane_count;
|
|
@@ -817,10 +829,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 +886,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 +1406,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 +1470,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 +1548,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 +1684,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 +1699,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 +1712,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 +1793,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 +1804,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 +1845,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 +1875,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 +1887,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;
|