|
@@ -42,15 +42,13 @@
|
|
|
|
|
|
#define DP_LINK_CONFIGURATION_SIZE 9
|
|
|
|
|
|
-#define IS_eDP(i) ((i)->base.type == INTEL_OUTPUT_EDP)
|
|
|
-#define IS_PCH_eDP(i) ((i)->is_pch_edp)
|
|
|
-
|
|
|
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;
|
|
|
+ int force_audio;
|
|
|
int dpms_mode;
|
|
|
uint8_t link_bw;
|
|
|
uint8_t lane_count;
|
|
@@ -60,8 +58,35 @@ struct intel_dp {
|
|
|
bool is_pch_edp;
|
|
|
uint8_t train_set[4];
|
|
|
uint8_t link_status[DP_LINK_STATUS_SIZE];
|
|
|
+
|
|
|
+ struct drm_property *force_audio_property;
|
|
|
};
|
|
|
|
|
|
+/**
|
|
|
+ * is_edp - is the given port attached to an eDP panel (either CPU or PCH)
|
|
|
+ * @intel_dp: DP struct
|
|
|
+ *
|
|
|
+ * If a CPU or PCH DP output is attached to an eDP panel, this function
|
|
|
+ * will return true, and false otherwise.
|
|
|
+ */
|
|
|
+static bool is_edp(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ return intel_dp->base.type == INTEL_OUTPUT_EDP;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * is_pch_edp - is the port on the PCH and attached to an eDP panel?
|
|
|
+ * @intel_dp: DP struct
|
|
|
+ *
|
|
|
+ * Returns true if the given DP struct corresponds to a PCH DP port attached
|
|
|
+ * to an eDP panel, false otherwise. Helpful for determining whether we
|
|
|
+ * may need FDI resources for a given DP output or not.
|
|
|
+ */
|
|
|
+static bool is_pch_edp(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ return intel_dp->is_pch_edp;
|
|
|
+}
|
|
|
+
|
|
|
static struct intel_dp *enc_to_intel_dp(struct drm_encoder *encoder)
|
|
|
{
|
|
|
return container_of(encoder, struct intel_dp, base.base);
|
|
@@ -73,6 +98,25 @@ static struct intel_dp *intel_attached_dp(struct drm_connector *connector)
|
|
|
struct intel_dp, base);
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * intel_encoder_is_pch_edp - is the given encoder a PCH attached eDP?
|
|
|
+ * @encoder: DRM encoder
|
|
|
+ *
|
|
|
+ * Return true if @encoder corresponds to a PCH attached eDP panel. Needed
|
|
|
+ * by intel_display.c.
|
|
|
+ */
|
|
|
+bool intel_encoder_is_pch_edp(struct drm_encoder *encoder)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp;
|
|
|
+
|
|
|
+ if (!encoder)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ intel_dp = enc_to_intel_dp(encoder);
|
|
|
+
|
|
|
+ return is_pch_edp(intel_dp);
|
|
|
+}
|
|
|
+
|
|
|
static void intel_dp_start_link_train(struct intel_dp *intel_dp);
|
|
|
static void intel_dp_complete_link_train(struct intel_dp *intel_dp);
|
|
|
static void intel_dp_link_down(struct intel_dp *intel_dp);
|
|
@@ -138,7 +182,7 @@ intel_dp_link_required(struct drm_device *dev, struct intel_dp *intel_dp, int pi
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
+ if (is_edp(intel_dp))
|
|
|
return (pixel_clock * dev_priv->edp.bpp + 7) / 8;
|
|
|
else
|
|
|
return pixel_clock * 3;
|
|
@@ -160,8 +204,7 @@ intel_dp_mode_valid(struct drm_connector *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);
|
|
|
|
|
|
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
|
|
|
- dev_priv->panel_fixed_mode) {
|
|
|
+ if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
|
|
|
if (mode->hdisplay > dev_priv->panel_fixed_mode->hdisplay)
|
|
|
return MODE_PANEL;
|
|
|
|
|
@@ -171,7 +214,7 @@ intel_dp_mode_valid(struct drm_connector *connector,
|
|
|
|
|
|
/* only refuse the mode on non eDP since we have seen some wierd eDP panels
|
|
|
which are outside spec tolerances but somehow work by magic */
|
|
|
- if (!IS_eDP(intel_dp) &&
|
|
|
+ if (!is_edp(intel_dp) &&
|
|
|
(intel_dp_link_required(connector->dev, intel_dp, mode->clock)
|
|
|
> intel_dp_max_data_rate(max_link_clock, max_lanes)))
|
|
|
return MODE_CLOCK_HIGH;
|
|
@@ -258,7 +301,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|
|
* Note that PCH attached eDP panels should use a 125MHz input
|
|
|
* clock divider.
|
|
|
*/
|
|
|
- if (IS_eDP(intel_dp) && !IS_PCH_eDP(intel_dp)) {
|
|
|
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
|
|
|
if (IS_GEN6(dev))
|
|
|
aux_clock_divider = 200; /* SNB eDP input clock at 400Mhz */
|
|
|
else
|
|
@@ -530,8 +573,7 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
int max_clock = intel_dp_max_link_bw(intel_dp) == DP_LINK_BW_2_7 ? 1 : 0;
|
|
|
static int bws[2] = { DP_LINK_BW_1_62, DP_LINK_BW_2_7 };
|
|
|
|
|
|
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
|
|
|
- dev_priv->panel_fixed_mode) {
|
|
|
+ if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
|
|
|
intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
|
|
|
intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
|
|
|
mode, adjusted_mode);
|
|
@@ -542,6 +584,17 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
mode->clock = dev_priv->panel_fixed_mode->clock;
|
|
|
}
|
|
|
|
|
|
+ /* Just use VBT values for eDP */
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
+ intel_dp->lane_count = dev_priv->edp.lanes;
|
|
|
+ intel_dp->link_bw = dev_priv->edp.rate;
|
|
|
+ adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
|
|
|
+ DRM_DEBUG_KMS("eDP link bw %02x lane count %d clock %d\n",
|
|
|
+ intel_dp->link_bw, intel_dp->lane_count,
|
|
|
+ adjusted_mode->clock);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
for (lane_count = 1; lane_count <= max_lane_count; lane_count <<= 1) {
|
|
|
for (clock = 0; clock <= max_clock; clock++) {
|
|
|
int link_avail = intel_dp_max_data_rate(intel_dp_link_clock(bws[clock]), lane_count);
|
|
@@ -560,19 +613,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
|
|
|
- /* okay we failed just pick the highest */
|
|
|
- intel_dp->lane_count = max_lane_count;
|
|
|
- intel_dp->link_bw = bws[max_clock];
|
|
|
- adjusted_mode->clock = intel_dp_link_clock(intel_dp->link_bw);
|
|
|
- DRM_DEBUG_KMS("Force picking display port link bw %02x lane "
|
|
|
- "count %d clock %d\n",
|
|
|
- intel_dp->link_bw, intel_dp->lane_count,
|
|
|
- adjusted_mode->clock);
|
|
|
-
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -609,25 +649,6 @@ intel_dp_compute_m_n(int bpp,
|
|
|
intel_reduce_ratio(&m_n->link_m, &m_n->link_n);
|
|
|
}
|
|
|
|
|
|
-bool intel_pch_has_edp(struct drm_crtc *crtc)
|
|
|
-{
|
|
|
- struct drm_device *dev = crtc->dev;
|
|
|
- struct drm_mode_config *mode_config = &dev->mode_config;
|
|
|
- struct drm_encoder *encoder;
|
|
|
-
|
|
|
- list_for_each_entry(encoder, &mode_config->encoder_list, head) {
|
|
|
- struct intel_dp *intel_dp;
|
|
|
-
|
|
|
- if (encoder->crtc != crtc)
|
|
|
- continue;
|
|
|
-
|
|
|
- intel_dp = enc_to_intel_dp(encoder);
|
|
|
- if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT)
|
|
|
- return intel_dp->is_pch_edp;
|
|
|
- }
|
|
|
- return false;
|
|
|
-}
|
|
|
-
|
|
|
void
|
|
|
intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|
|
struct drm_display_mode *adjusted_mode)
|
|
@@ -652,8 +673,10 @@ intel_dp_set_m_n(struct drm_crtc *crtc, struct drm_display_mode *mode,
|
|
|
intel_dp = enc_to_intel_dp(encoder);
|
|
|
if (intel_dp->base.type == INTEL_OUTPUT_DISPLAYPORT) {
|
|
|
lane_count = intel_dp->lane_count;
|
|
|
- if (IS_PCH_eDP(intel_dp))
|
|
|
- bpp = dev_priv->edp.bpp;
|
|
|
+ break;
|
|
|
+ } else if (is_edp(intel_dp)) {
|
|
|
+ lane_count = dev_priv->edp.lanes;
|
|
|
+ bpp = dev_priv->edp.bpp;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
@@ -720,7 +743,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
if (adjusted_mode->flags & DRM_MODE_FLAG_PVSYNC)
|
|
|
intel_dp->DP |= DP_SYNC_VS_HIGH;
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
intel_dp->DP |= DP_LINK_TRAIN_OFF_CPT;
|
|
|
else
|
|
|
intel_dp->DP |= DP_LINK_TRAIN_OFF;
|
|
@@ -755,7 +778,7 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
if (intel_crtc->pipe == 1 && !HAS_PCH_CPT(dev))
|
|
|
intel_dp->DP |= DP_PIPEB_SELECT;
|
|
|
|
|
|
- if (IS_eDP(intel_dp)) {
|
|
|
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp)) {
|
|
|
/* don't miss out required setting for eDP */
|
|
|
intel_dp->DP |= DP_PLL_ENABLE;
|
|
|
if (adjusted_mode->clock < 200000)
|
|
@@ -766,10 +789,11 @@ intel_dp_mode_set(struct drm_encoder *encoder, struct drm_display_mode *mode,
|
|
|
}
|
|
|
|
|
|
/* Returns true if the panel was already on when called */
|
|
|
-static bool ironlake_edp_panel_on (struct drm_device *dev)
|
|
|
+static bool ironlake_edp_panel_on (struct intel_dp *intel_dp)
|
|
|
{
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- u32 pp;
|
|
|
+ u32 pp, idle_on_mask = PP_ON | PP_SEQUENCE_STATE_ON_IDLE;
|
|
|
|
|
|
if (I915_READ(PCH_PP_STATUS) & PP_ON)
|
|
|
return true;
|
|
@@ -781,19 +805,20 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
|
- pp |= POWER_TARGET_ON;
|
|
|
+ pp |= PANEL_UNLOCK_REGS | POWER_TARGET_ON;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
|
/* Ouch. We need to wait here for some panels, like Dell e6510
|
|
|
* https://bugs.freedesktop.org/show_bug.cgi?id=29278i
|
|
|
*/
|
|
|
msleep(300);
|
|
|
|
|
|
- if (wait_for(I915_READ(PCH_PP_STATUS) & PP_ON, 5000))
|
|
|
+ if (wait_for((I915_READ(PCH_PP_STATUS) & idle_on_mask) == idle_on_mask,
|
|
|
+ 5000))
|
|
|
DRM_ERROR("panel on wait timed out: 0x%08x\n",
|
|
|
I915_READ(PCH_PP_STATUS));
|
|
|
|
|
|
- pp &= ~(PANEL_UNLOCK_REGS);
|
|
|
pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
@@ -804,7 +829,8 @@ static bool ironlake_edp_panel_on (struct drm_device *dev)
|
|
|
static void ironlake_edp_panel_off (struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- u32 pp;
|
|
|
+ u32 pp, idle_off_mask = PP_ON | PP_SEQUENCE_MASK |
|
|
|
+ PP_CYCLE_DELAY_ACTIVE | PP_SEQUENCE_STATE_MASK;
|
|
|
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
|
|
@@ -815,12 +841,12 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
|
|
|
|
|
|
pp &= ~POWER_TARGET_ON;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
+ POSTING_READ(PCH_PP_CONTROL);
|
|
|
|
|
|
- if (wait_for((I915_READ(PCH_PP_STATUS) & PP_ON) == 0, 5000))
|
|
|
+ if (wait_for((I915_READ(PCH_PP_STATUS) & idle_off_mask) == 0, 5000))
|
|
|
DRM_ERROR("panel off wait timed out: 0x%08x\n",
|
|
|
I915_READ(PCH_PP_STATUS));
|
|
|
|
|
|
- /* Make sure VDD is enabled so DP AUX will work */
|
|
|
pp |= PANEL_POWER_RESET; /* restore panel reset bit */
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
POSTING_READ(PCH_PP_CONTROL);
|
|
@@ -831,36 +857,19 @@ static void ironlake_edp_panel_off (struct drm_device *dev)
|
|
|
msleep(300);
|
|
|
}
|
|
|
|
|
|
-static void ironlake_edp_panel_vdd_on(struct drm_device *dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- u32 pp;
|
|
|
-
|
|
|
- pp = I915_READ(PCH_PP_CONTROL);
|
|
|
- pp |= EDP_FORCE_VDD;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- msleep(300);
|
|
|
-}
|
|
|
-
|
|
|
-static void ironlake_edp_panel_vdd_off(struct drm_device *dev)
|
|
|
-{
|
|
|
- struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- u32 pp;
|
|
|
-
|
|
|
- pp = I915_READ(PCH_PP_CONTROL);
|
|
|
- pp &= ~EDP_FORCE_VDD;
|
|
|
- I915_WRITE(PCH_PP_CONTROL, pp);
|
|
|
- POSTING_READ(PCH_PP_CONTROL);
|
|
|
- msleep(300);
|
|
|
-}
|
|
|
-
|
|
|
static void ironlake_edp_backlight_on (struct drm_device *dev)
|
|
|
{
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
u32 pp;
|
|
|
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
+ /*
|
|
|
+ * If we enable the backlight right away following a panel power
|
|
|
+ * on, we may see slight flicker as the panel syncs with the eDP
|
|
|
+ * link. So delay a bit to make sure the image is solid before
|
|
|
+ * allowing it to appear.
|
|
|
+ */
|
|
|
+ msleep(300);
|
|
|
pp = I915_READ(PCH_PP_CONTROL);
|
|
|
pp |= EDP_BLC_ENABLE;
|
|
|
I915_WRITE(PCH_PP_CONTROL, pp);
|
|
@@ -885,8 +894,10 @@ static void ironlake_edp_pll_on(struct drm_encoder *encoder)
|
|
|
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
dpa_ctl = I915_READ(DP_A);
|
|
|
- dpa_ctl &= ~DP_PLL_ENABLE;
|
|
|
+ dpa_ctl |= DP_PLL_ENABLE;
|
|
|
I915_WRITE(DP_A, dpa_ctl);
|
|
|
+ POSTING_READ(DP_A);
|
|
|
+ udelay(200);
|
|
|
}
|
|
|
|
|
|
static void ironlake_edp_pll_off(struct drm_encoder *encoder)
|
|
@@ -896,7 +907,7 @@ static void ironlake_edp_pll_off(struct drm_encoder *encoder)
|
|
|
u32 dpa_ctl;
|
|
|
|
|
|
dpa_ctl = I915_READ(DP_A);
|
|
|
- dpa_ctl |= DP_PLL_ENABLE;
|
|
|
+ dpa_ctl &= ~DP_PLL_ENABLE;
|
|
|
I915_WRITE(DP_A, dpa_ctl);
|
|
|
POSTING_READ(DP_A);
|
|
|
udelay(200);
|
|
@@ -906,17 +917,16 @@ static void intel_dp_prepare(struct drm_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);
|
|
|
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
|
|
|
- ironlake_edp_panel_off(dev);
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
ironlake_edp_backlight_off(dev);
|
|
|
- ironlake_edp_panel_vdd_on(dev);
|
|
|
- ironlake_edp_pll_on(encoder);
|
|
|
+ ironlake_edp_panel_on(intel_dp);
|
|
|
+ if (!is_pch_edp(intel_dp))
|
|
|
+ ironlake_edp_pll_on(encoder);
|
|
|
+ else
|
|
|
+ ironlake_edp_pll_off(encoder);
|
|
|
}
|
|
|
- if (dp_reg & DP_PORT_EN)
|
|
|
- intel_dp_link_down(intel_dp);
|
|
|
+ intel_dp_link_down(intel_dp);
|
|
|
}
|
|
|
|
|
|
static void intel_dp_commit(struct drm_encoder *encoder)
|
|
@@ -926,14 +936,13 @@ static void intel_dp_commit(struct drm_encoder *encoder)
|
|
|
|
|
|
intel_dp_start_link_train(intel_dp);
|
|
|
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
- ironlake_edp_panel_on(dev);
|
|
|
+ if (is_edp(intel_dp))
|
|
|
+ ironlake_edp_panel_on(intel_dp);
|
|
|
|
|
|
intel_dp_complete_link_train(intel_dp);
|
|
|
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
+ if (is_edp(intel_dp))
|
|
|
ironlake_edp_backlight_on(dev);
|
|
|
- intel_dp->dpms_mode = DRM_MODE_DPMS_ON;
|
|
|
}
|
|
|
|
|
|
static void
|
|
@@ -945,23 +954,22 @@ intel_dp_dpms(struct drm_encoder *encoder, int mode)
|
|
|
uint32_t dp_reg = I915_READ(intel_dp->output_reg);
|
|
|
|
|
|
if (mode != DRM_MODE_DPMS_ON) {
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
|
|
|
+ if (is_edp(intel_dp))
|
|
|
ironlake_edp_backlight_off(dev);
|
|
|
+ intel_dp_link_down(intel_dp);
|
|
|
+ if (is_edp(intel_dp))
|
|
|
ironlake_edp_panel_off(dev);
|
|
|
- }
|
|
|
- if (dp_reg & DP_PORT_EN)
|
|
|
- intel_dp_link_down(intel_dp);
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
+ if (is_edp(intel_dp) && !is_pch_edp(intel_dp))
|
|
|
ironlake_edp_pll_off(encoder);
|
|
|
} else {
|
|
|
+ if (is_edp(intel_dp))
|
|
|
+ ironlake_edp_panel_on(intel_dp);
|
|
|
if (!(dp_reg & DP_PORT_EN)) {
|
|
|
intel_dp_start_link_train(intel_dp);
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
- ironlake_edp_panel_on(dev);
|
|
|
intel_dp_complete_link_train(intel_dp);
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
- ironlake_edp_backlight_on(dev);
|
|
|
}
|
|
|
+ if (is_edp(intel_dp))
|
|
|
+ ironlake_edp_backlight_on(dev);
|
|
|
}
|
|
|
intel_dp->dpms_mode = mode;
|
|
|
}
|
|
@@ -1079,11 +1087,21 @@ intel_get_adjust_train(struct intel_dp *intel_dp)
|
|
|
}
|
|
|
|
|
|
static uint32_t
|
|
|
-intel_dp_signal_levels(uint8_t train_set, int lane_count)
|
|
|
+intel_dp_signal_levels(struct intel_dp *intel_dp)
|
|
|
{
|
|
|
- uint32_t signal_levels = 0;
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+ uint32_t signal_levels = 0;
|
|
|
+ u8 train_set = intel_dp->train_set[0];
|
|
|
+ u32 vswing = train_set & DP_TRAIN_VOLTAGE_SWING_MASK;
|
|
|
+ u32 preemphasis = train_set & DP_TRAIN_PRE_EMPHASIS_MASK;
|
|
|
+
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
+ vswing = dev_priv->edp.vswing;
|
|
|
+ preemphasis = dev_priv->edp.preemphasis;
|
|
|
+ }
|
|
|
|
|
|
- switch (train_set & DP_TRAIN_VOLTAGE_SWING_MASK) {
|
|
|
+ switch (vswing) {
|
|
|
case DP_TRAIN_VOLTAGE_SWING_400:
|
|
|
default:
|
|
|
signal_levels |= DP_VOLTAGE_0_4;
|
|
@@ -1098,7 +1116,7 @@ intel_dp_signal_levels(uint8_t train_set, int lane_count)
|
|
|
signal_levels |= DP_VOLTAGE_1_2;
|
|
|
break;
|
|
|
}
|
|
|
- switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
|
|
|
+ switch (preemphasis) {
|
|
|
case DP_TRAIN_PRE_EMPHASIS_0:
|
|
|
default:
|
|
|
signal_levels |= DP_PRE_EMPHASIS_0;
|
|
@@ -1184,6 +1202,18 @@ intel_channel_eq_ok(struct intel_dp *intel_dp)
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+static bool
|
|
|
+intel_dp_aux_handshake_required(struct intel_dp *intel_dp)
|
|
|
+{
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
+
|
|
|
+ if (is_edp(intel_dp) && dev_priv->no_aux_handshake)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static bool
|
|
|
intel_dp_set_link_train(struct intel_dp *intel_dp,
|
|
|
uint32_t dp_reg_value,
|
|
@@ -1196,6 +1226,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,
|
|
|
I915_WRITE(intel_dp->output_reg, dp_reg_value);
|
|
|
POSTING_READ(intel_dp->output_reg);
|
|
|
|
|
|
+ if (!intel_dp_aux_handshake_required(intel_dp))
|
|
|
+ return true;
|
|
|
+
|
|
|
intel_dp_aux_native_write_1(intel_dp,
|
|
|
DP_TRAINING_PATTERN_SET,
|
|
|
dp_train_pat);
|
|
@@ -1228,13 +1261,14 @@ intel_dp_start_link_train(struct intel_dp *intel_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,
|
|
|
- DP_LINK_CONFIGURATION_SIZE);
|
|
|
+ if (intel_dp_aux_handshake_required(intel_dp))
|
|
|
+ /* Write the link configuration data */
|
|
|
+ intel_dp_aux_native_write(intel_dp, DP_LINK_BW_SET,
|
|
|
+ intel_dp->link_configuration,
|
|
|
+ DP_LINK_CONFIGURATION_SIZE);
|
|
|
|
|
|
DP |= DP_PORT_EN;
|
|
|
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
DP &= ~DP_LINK_TRAIN_MASK_CPT;
|
|
|
else
|
|
|
DP &= ~DP_LINK_TRAIN_MASK;
|
|
@@ -1245,15 +1279,15 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
|
|
for (;;) {
|
|
|
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
|
|
|
uint32_t signal_levels;
|
|
|
- if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
|
|
|
+ if (IS_GEN6(dev) && is_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 {
|
|
|
- signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
|
|
|
+ signal_levels = intel_dp_signal_levels(intel_dp);
|
|
|
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_1_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_1;
|
|
@@ -1263,33 +1297,37 @@ intel_dp_start_link_train(struct intel_dp *intel_dp)
|
|
|
break;
|
|
|
/* Set training pattern 1 */
|
|
|
|
|
|
- udelay(100);
|
|
|
- if (!intel_dp_get_link_status(intel_dp))
|
|
|
- break;
|
|
|
-
|
|
|
- if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
|
|
|
- clock_recovery = true;
|
|
|
+ udelay(500);
|
|
|
+ if (intel_dp_aux_handshake_required(intel_dp)) {
|
|
|
break;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ if (!intel_dp_get_link_status(intel_dp))
|
|
|
+ break;
|
|
|
|
|
|
- /* Check to see if we've tried the max voltage */
|
|
|
- for (i = 0; i < intel_dp->lane_count; i++)
|
|
|
- if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
|
|
|
+ if (intel_clock_recovery_ok(intel_dp->link_status, intel_dp->lane_count)) {
|
|
|
+ clock_recovery = true;
|
|
|
break;
|
|
|
- if (i == intel_dp->lane_count)
|
|
|
- break;
|
|
|
+ }
|
|
|
|
|
|
- /* Check to see if we've tried the same voltage 5 times */
|
|
|
- if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
|
|
|
- ++tries;
|
|
|
- if (tries == 5)
|
|
|
+ /* Check to see if we've tried the max voltage */
|
|
|
+ for (i = 0; i < intel_dp->lane_count; i++)
|
|
|
+ if ((intel_dp->train_set[i] & DP_TRAIN_MAX_SWING_REACHED) == 0)
|
|
|
+ break;
|
|
|
+ if (i == intel_dp->lane_count)
|
|
|
break;
|
|
|
- } else
|
|
|
- tries = 0;
|
|
|
- voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
|
|
|
|
|
|
- /* Compute new intel_dp->train_set as requested by target */
|
|
|
- intel_get_adjust_train(intel_dp);
|
|
|
+ /* Check to see if we've tried the same voltage 5 times */
|
|
|
+ if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) == voltage) {
|
|
|
+ ++tries;
|
|
|
+ if (tries == 5)
|
|
|
+ break;
|
|
|
+ } else
|
|
|
+ tries = 0;
|
|
|
+ voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
|
|
|
+
|
|
|
+ /* Compute new intel_dp->train_set as requested by target */
|
|
|
+ intel_get_adjust_train(intel_dp);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
intel_dp->DP = DP;
|
|
@@ -1312,15 +1350,15 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
|
|
/* Use intel_dp->train_set[0] to set the voltage and pre emphasis values */
|
|
|
uint32_t signal_levels;
|
|
|
|
|
|
- if (IS_GEN6(dev) && IS_eDP(intel_dp)) {
|
|
|
+ if (IS_GEN6(dev) && is_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 {
|
|
|
- signal_levels = intel_dp_signal_levels(intel_dp->train_set[0], intel_dp->lane_count);
|
|
|
+ signal_levels = intel_dp_signal_levels(intel_dp);
|
|
|
DP = (DP & ~(DP_VOLTAGE_MASK|DP_PRE_EMPHASIS_MASK)) | signal_levels;
|
|
|
}
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_2_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_PAT_2;
|
|
@@ -1330,25 +1368,29 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
|
|
|
DP_TRAINING_PATTERN_2))
|
|
|
break;
|
|
|
|
|
|
- udelay(400);
|
|
|
- if (!intel_dp_get_link_status(intel_dp))
|
|
|
- break;
|
|
|
+ udelay(500);
|
|
|
|
|
|
- if (intel_channel_eq_ok(intel_dp)) {
|
|
|
- channel_eq = true;
|
|
|
+ if (!intel_dp_aux_handshake_required(intel_dp)) {
|
|
|
break;
|
|
|
- }
|
|
|
+ } else {
|
|
|
+ if (!intel_dp_get_link_status(intel_dp))
|
|
|
+ break;
|
|
|
|
|
|
- /* Try 5 times */
|
|
|
- if (tries > 5)
|
|
|
- break;
|
|
|
+ if (intel_channel_eq_ok(intel_dp)) {
|
|
|
+ channel_eq = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- /* Compute new intel_dp->train_set as requested by target */
|
|
|
- intel_get_adjust_train(intel_dp);
|
|
|
- ++tries;
|
|
|
- }
|
|
|
+ /* Try 5 times */
|
|
|
+ if (tries > 5)
|
|
|
+ break;
|
|
|
|
|
|
- if (HAS_PCH_CPT(dev) && !IS_eDP(intel_dp))
|
|
|
+ /* Compute new intel_dp->train_set as requested by target */
|
|
|
+ intel_get_adjust_train(intel_dp);
|
|
|
+ ++tries;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp))
|
|
|
reg = DP | DP_LINK_TRAIN_OFF_CPT;
|
|
|
else
|
|
|
reg = DP | DP_LINK_TRAIN_OFF;
|
|
@@ -1368,14 +1410,14 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|
|
|
|
|
DRM_DEBUG_KMS("\n");
|
|
|
|
|
|
- if (IS_eDP(intel_dp)) {
|
|
|
+ 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_eDP(intel_dp)) {
|
|
|
+ if (HAS_PCH_CPT(dev) && !is_edp(intel_dp)) {
|
|
|
DP &= ~DP_LINK_TRAIN_MASK_CPT;
|
|
|
I915_WRITE(intel_dp->output_reg, DP | DP_LINK_TRAIN_PAT_IDLE_CPT);
|
|
|
} else {
|
|
@@ -1386,7 +1428,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
|
|
|
|
|
|
msleep(17);
|
|
|
|
|
|
- if (IS_eDP(intel_dp))
|
|
|
+ if (is_edp(intel_dp))
|
|
|
DP |= DP_LINK_TRAIN_OFF;
|
|
|
I915_WRITE(intel_dp->output_reg, DP & ~DP_PORT_EN);
|
|
|
POSTING_READ(intel_dp->output_reg);
|
|
@@ -1419,48 +1461,34 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
|
|
|
}
|
|
|
|
|
|
static enum drm_connector_status
|
|
|
-ironlake_dp_detect(struct drm_connector *connector)
|
|
|
+ironlake_dp_detect(struct intel_dp *intel_dp)
|
|
|
{
|
|
|
- struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
enum drm_connector_status status;
|
|
|
|
|
|
- /* Panel needs power for AUX to work */
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
- ironlake_edp_panel_vdd_on(connector->dev);
|
|
|
+ /* Can't disconnect eDP */
|
|
|
+ if (is_edp(intel_dp))
|
|
|
+ return connector_status_connected;
|
|
|
+
|
|
|
status = connector_status_disconnected;
|
|
|
if (intel_dp_aux_native_read(intel_dp,
|
|
|
0x000, intel_dp->dpcd,
|
|
|
- sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
|
|
|
- {
|
|
|
+ sizeof (intel_dp->dpcd))
|
|
|
+ == sizeof(intel_dp->dpcd)) {
|
|
|
if (intel_dp->dpcd[0] != 0)
|
|
|
status = connector_status_connected;
|
|
|
}
|
|
|
DRM_DEBUG_KMS("DPCD: %hx%hx%hx%hx\n", intel_dp->dpcd[0],
|
|
|
intel_dp->dpcd[1], intel_dp->dpcd[2], intel_dp->dpcd[3]);
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp))
|
|
|
- ironlake_edp_panel_vdd_off(connector->dev);
|
|
|
return status;
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
|
|
|
- *
|
|
|
- * \return true if DP port is connected.
|
|
|
- * \return false if DP port is disconnected.
|
|
|
- */
|
|
|
static enum drm_connector_status
|
|
|
-intel_dp_detect(struct drm_connector *connector, bool force)
|
|
|
+g4x_dp_detect(struct intel_dp *intel_dp)
|
|
|
{
|
|
|
- struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
struct drm_i915_private *dev_priv = dev->dev_private;
|
|
|
- uint32_t temp, bit;
|
|
|
enum drm_connector_status status;
|
|
|
-
|
|
|
- intel_dp->has_audio = false;
|
|
|
-
|
|
|
- if (HAS_PCH_SPLIT(dev))
|
|
|
- return ironlake_dp_detect(connector);
|
|
|
+ uint32_t temp, bit;
|
|
|
|
|
|
switch (intel_dp->output_reg) {
|
|
|
case DP_B:
|
|
@@ -1482,14 +1510,51 @@ intel_dp_detect(struct drm_connector *connector, bool force)
|
|
|
return connector_status_disconnected;
|
|
|
|
|
|
status = connector_status_disconnected;
|
|
|
- if (intel_dp_aux_native_read(intel_dp,
|
|
|
- 0x000, intel_dp->dpcd,
|
|
|
+ if (intel_dp_aux_native_read(intel_dp, 0x000, intel_dp->dpcd,
|
|
|
sizeof (intel_dp->dpcd)) == sizeof (intel_dp->dpcd))
|
|
|
{
|
|
|
if (intel_dp->dpcd[0] != 0)
|
|
|
status = connector_status_connected;
|
|
|
}
|
|
|
- return status;
|
|
|
+
|
|
|
+ return bit;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Uses CRT_HOTPLUG_EN and CRT_HOTPLUG_STAT to detect DP connection.
|
|
|
+ *
|
|
|
+ * \return true if DP port is connected.
|
|
|
+ * \return false if DP port is disconnected.
|
|
|
+ */
|
|
|
+static enum drm_connector_status
|
|
|
+intel_dp_detect(struct drm_connector *connector, bool force)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
+ struct drm_device *dev = intel_dp->base.base.dev;
|
|
|
+ enum drm_connector_status status;
|
|
|
+ struct edid *edid = NULL;
|
|
|
+
|
|
|
+ intel_dp->has_audio = false;
|
|
|
+
|
|
|
+ if (HAS_PCH_SPLIT(dev))
|
|
|
+ status = ironlake_dp_detect(intel_dp);
|
|
|
+ else
|
|
|
+ status = g4x_dp_detect(intel_dp);
|
|
|
+ if (status != connector_status_connected)
|
|
|
+ return status;
|
|
|
+
|
|
|
+ if (intel_dp->force_audio) {
|
|
|
+ intel_dp->has_audio = intel_dp->force_audio > 0;
|
|
|
+ } else {
|
|
|
+ edid = drm_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);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return connector_status_connected;
|
|
|
}
|
|
|
|
|
|
static int intel_dp_get_modes(struct drm_connector *connector)
|
|
@@ -1504,8 +1569,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
|
|
|
|
|
|
ret = intel_ddc_get_modes(connector, &intel_dp->adapter);
|
|
|
if (ret) {
|
|
|
- if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
|
|
|
- !dev_priv->panel_fixed_mode) {
|
|
|
+ if (is_edp(intel_dp) && !dev_priv->panel_fixed_mode) {
|
|
|
struct drm_display_mode *newmode;
|
|
|
list_for_each_entry(newmode, &connector->probed_modes,
|
|
|
head) {
|
|
@@ -1521,7 +1585,7 @@ static int intel_dp_get_modes(struct drm_connector *connector)
|
|
|
}
|
|
|
|
|
|
/* if eDP has no EDID, try to use fixed panel mode from VBT */
|
|
|
- if (IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) {
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
if (dev_priv->panel_fixed_mode != NULL) {
|
|
|
struct drm_display_mode *mode;
|
|
|
mode = drm_mode_duplicate(dev, dev_priv->panel_fixed_mode);
|
|
@@ -1532,6 +1596,46 @@ static int intel_dp_get_modes(struct drm_connector *connector)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+static int
|
|
|
+intel_dp_set_property(struct drm_connector *connector,
|
|
|
+ struct drm_property *property,
|
|
|
+ uint64_t val)
|
|
|
+{
|
|
|
+ struct intel_dp *intel_dp = intel_attached_dp(connector);
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ ret = drm_connector_property_set_value(connector, property, val);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ if (property == intel_dp->force_audio_property) {
|
|
|
+ if (val == intel_dp->force_audio)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ intel_dp->force_audio = val;
|
|
|
+
|
|
|
+ if (val > 0 && intel_dp->has_audio)
|
|
|
+ return 0;
|
|
|
+ if (val < 0 && !intel_dp->has_audio)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ intel_dp->has_audio = val > 0;
|
|
|
+ goto done;
|
|
|
+ }
|
|
|
+
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+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);
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void
|
|
|
intel_dp_destroy (struct drm_connector *connector)
|
|
|
{
|
|
@@ -1561,6 +1665,7 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
|
|
|
.dpms = drm_helper_connector_dpms,
|
|
|
.detect = intel_dp_detect,
|
|
|
.fill_modes = drm_helper_probe_single_connector_modes,
|
|
|
+ .set_property = intel_dp_set_property,
|
|
|
.destroy = intel_dp_destroy,
|
|
|
};
|
|
|
|
|
@@ -1625,6 +1730,20 @@ bool intel_dpd_is_edp(struct drm_device *dev)
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
+static void
|
|
|
+intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector)
|
|
|
+{
|
|
|
+ struct drm_device *dev = connector->dev;
|
|
|
+
|
|
|
+ intel_dp->force_audio_property =
|
|
|
+ drm_property_create(dev, DRM_MODE_PROP_RANGE, "force_audio", 2);
|
|
|
+ if (intel_dp->force_audio_property) {
|
|
|
+ intel_dp->force_audio_property->values[0] = -1;
|
|
|
+ intel_dp->force_audio_property->values[1] = 1;
|
|
|
+ drm_connector_attach_property(connector, intel_dp->force_audio_property, 0);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
void
|
|
|
intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
{
|
|
@@ -1651,7 +1770,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
if (intel_dpd_is_edp(dev))
|
|
|
intel_dp->is_pch_edp = true;
|
|
|
|
|
|
- if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
|
|
|
+ if (output_reg == DP_A || is_pch_edp(intel_dp)) {
|
|
|
type = DRM_MODE_CONNECTOR_eDP;
|
|
|
intel_encoder->type = INTEL_OUTPUT_EDP;
|
|
|
} else {
|
|
@@ -1672,7 +1791,7 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
else if (output_reg == DP_D || output_reg == PCH_DP_D)
|
|
|
intel_encoder->clone_mask = (1 << INTEL_DP_D_CLONE_BIT);
|
|
|
|
|
|
- if (IS_eDP(intel_dp))
|
|
|
+ if (is_edp(intel_dp))
|
|
|
intel_encoder->clone_mask = (1 << INTEL_EDP_CLONE_BIT);
|
|
|
|
|
|
intel_encoder->crtc_mask = (1 << 0) | (1 << 1);
|
|
@@ -1717,9 +1836,29 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
|
|
|
intel_dp_i2c_init(intel_dp, intel_connector, name);
|
|
|
|
|
|
+ /* Cache some DPCD data in the eDP case */
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
+ int ret;
|
|
|
+ bool was_on;
|
|
|
+
|
|
|
+ was_on = ironlake_edp_panel_on(intel_dp);
|
|
|
+ ret = intel_dp_aux_native_read(intel_dp, DP_DPCD_REV,
|
|
|
+ intel_dp->dpcd,
|
|
|
+ sizeof(intel_dp->dpcd));
|
|
|
+ if (ret == sizeof(intel_dp->dpcd)) {
|
|
|
+ if (intel_dp->dpcd[0] >= 0x11)
|
|
|
+ dev_priv->no_aux_handshake = intel_dp->dpcd[3] &
|
|
|
+ DP_NO_AUX_HANDSHAKE_LINK_TRAINING;
|
|
|
+ } else {
|
|
|
+ DRM_ERROR("failed to retrieve link info\n");
|
|
|
+ }
|
|
|
+ if (!was_on)
|
|
|
+ ironlake_edp_panel_off(dev);
|
|
|
+ }
|
|
|
+
|
|
|
intel_encoder->hot_plug = intel_dp_hot_plug;
|
|
|
|
|
|
- if (output_reg == DP_A || IS_PCH_eDP(intel_dp)) {
|
|
|
+ if (is_edp(intel_dp)) {
|
|
|
/* initialize panel mode from VBT if available for eDP */
|
|
|
if (dev_priv->lfp_lvds_vbt_mode) {
|
|
|
dev_priv->panel_fixed_mode =
|
|
@@ -1731,6 +1870,8 @@ intel_dp_init(struct drm_device *dev, int output_reg)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ intel_dp_add_properties(intel_dp, connector);
|
|
|
+
|
|
|
/* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written
|
|
|
* 0xd. Failure to do so will result in spurious interrupts being
|
|
|
* generated on the port when a cable is not attached.
|