diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 77 | 
1 files changed, 48 insertions, 29 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index fb2fbc1e08b..3d704b706a8 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -702,6 +702,9 @@ intel_dp_compute_config(struct intel_encoder *encoder,  	/* Walk through all bpp values. Luckily they're all nicely spaced with 2  	 * bpc in between. */  	bpp = min_t(int, 8*3, pipe_config->pipe_bpp); +	if (is_edp(intel_dp) && dev_priv->edp.bpp) +		bpp = min_t(int, bpp, dev_priv->edp.bpp); +  	for (; bpp >= 6*3; bpp -= 2*3) {  		mode_rate = intel_dp_link_required(target_clock, bpp); @@ -739,6 +742,7 @@ found:  	intel_dp->link_bw = bws[clock];  	intel_dp->lane_count = lane_count;  	adjusted_mode->clock = drm_dp_bw_code_to_link_rate(intel_dp->link_bw); +	pipe_config->pipe_bpp = bpp;  	pipe_config->pixel_target_clock = target_clock;  	DRM_DEBUG_KMS("DP link bw %02x lane count %d clock %d bpp %d\n", @@ -751,20 +755,6 @@ found:  			       target_clock, adjusted_mode->clock,  			       &pipe_config->dp_m_n); -	/* -	 * XXX: We have a strange regression where using the vbt edp bpp value -	 * for the link bw computation results in black screens, the panel only -	 * works when we do the computation at the usual 24bpp (but still -	 * requires us to use 18bpp). Until that's fully debugged, stay -	 * bug-for-bug compatible with the old code. -	 */ -	if (is_edp(intel_dp) && dev_priv->edp.bpp) { -		DRM_DEBUG_KMS("clamping display bpc (was %d) to eDP (%d)\n", -			      bpp, dev_priv->edp.bpp); -		bpp = min_t(int, bpp, dev_priv->edp.bpp); -	} -	pipe_config->pipe_bpp = bpp; -  	return true;  } @@ -1389,6 +1379,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)  	ironlake_edp_panel_on(intel_dp);  	ironlake_edp_panel_vdd_off(intel_dp, true);  	intel_dp_complete_link_train(intel_dp); +	intel_dp_stop_link_train(intel_dp);  	ironlake_edp_backlight_on(intel_dp);  } @@ -1711,10 +1702,9 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,  	struct drm_i915_private *dev_priv = dev->dev_private;  	enum port port = intel_dig_port->port;  	int ret; -	uint32_t temp;  	if (HAS_DDI(dev)) { -		temp = I915_READ(DP_TP_CTL(port)); +		uint32_t temp = I915_READ(DP_TP_CTL(port));  		if (dp_train_pat & DP_LINK_SCRAMBLING_DISABLE)  			temp |= DP_TP_CTL_SCRAMBLE_DISABLE; @@ -1724,18 +1714,6 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,  		temp &= ~DP_TP_CTL_LINK_TRAIN_MASK;  		switch (dp_train_pat & DP_TRAINING_PATTERN_MASK) {  		case DP_TRAINING_PATTERN_DISABLE: - -			if (port != PORT_A) { -				temp |= DP_TP_CTL_LINK_TRAIN_IDLE; -				I915_WRITE(DP_TP_CTL(port), temp); - -				if (wait_for((I915_READ(DP_TP_STATUS(port)) & -					      DP_TP_STATUS_IDLE_DONE), 1)) -					DRM_ERROR("Timed out waiting for DP idle patterns\n"); - -				temp &= ~DP_TP_CTL_LINK_TRAIN_MASK; -			} -  			temp |= DP_TP_CTL_LINK_TRAIN_NORMAL;  			break; @@ -1811,6 +1789,37 @@ intel_dp_set_link_train(struct intel_dp *intel_dp,  	return true;  } +static void intel_dp_set_idle_link_train(struct intel_dp *intel_dp) +{ +	struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp); +	struct drm_device *dev = intel_dig_port->base.base.dev; +	struct drm_i915_private *dev_priv = dev->dev_private; +	enum port port = intel_dig_port->port; +	uint32_t val; + +	if (!HAS_DDI(dev)) +		return; + +	val = I915_READ(DP_TP_CTL(port)); +	val &= ~DP_TP_CTL_LINK_TRAIN_MASK; +	val |= DP_TP_CTL_LINK_TRAIN_IDLE; +	I915_WRITE(DP_TP_CTL(port), val); + +	/* +	 * On PORT_A we can have only eDP in SST mode. There the only reason +	 * we need to set idle transmission mode is to work around a HW issue +	 * where we enable the pipe while not in idle link-training mode. +	 * In this case there is requirement to wait for a minimum number of +	 * idle patterns to be sent. +	 */ +	if (port == PORT_A) +		return; + +	if (wait_for((I915_READ(DP_TP_STATUS(port)) & DP_TP_STATUS_IDLE_DONE), +		     1)) +		DRM_ERROR("Timed out waiting for DP idle patterns\n"); +} +  /* Enable corresponding port and start training pattern 1 */  void  intel_dp_start_link_train(struct intel_dp *intel_dp) @@ -1953,10 +1962,19 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)  		++tries;  	} +	intel_dp_set_idle_link_train(intel_dp); + +	intel_dp->DP = DP; +  	if (channel_eq)  		DRM_DEBUG_KMS("Channel EQ done. DP Training successful\n"); -	intel_dp_set_link_train(intel_dp, DP, DP_TRAINING_PATTERN_DISABLE); +} + +void intel_dp_stop_link_train(struct intel_dp *intel_dp) +{ +	intel_dp_set_link_train(intel_dp, intel_dp->DP, +				DP_TRAINING_PATTERN_DISABLE);  }  static void @@ -2164,6 +2182,7 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)  			      drm_get_encoder_name(&intel_encoder->base));  		intel_dp_start_link_train(intel_dp);  		intel_dp_complete_link_train(intel_dp); +		intel_dp_stop_link_train(intel_dp);  	}  }  |