diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_dp.c')
| -rw-r--r-- | drivers/gpu/drm/i915/intel_dp.c | 43 | 
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 5ede4e8e290d..2688f6d64bb9 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,  	int i, ret, recv_bytes;  	uint32_t status;  	int try, precharge, clock = 0; -	bool has_aux_irq = true; +	bool has_aux_irq = HAS_AUX_IRQ(dev);  	uint32_t timeout;  	/* dp aux is extremely sensitive to irq latency, hence request the @@ -537,6 +537,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,  	uint8_t	msg[20];  	int msg_bytes;  	uint8_t	ack; +	int retry;  	if (WARN_ON(send_bytes > 16))  		return -E2BIG; @@ -548,19 +549,21 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,  	msg[3] = send_bytes - 1;  	memcpy(&msg[4], send, send_bytes);  	msg_bytes = send_bytes + 4; -	for (;;) { +	for (retry = 0; retry < 7; retry++) {  		ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);  		if (ret < 0)  			return ret;  		ack >>= 4;  		if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) -			break; +			return send_bytes;  		else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) -			udelay(100); +			usleep_range(400, 500);  		else  			return -EIO;  	} -	return send_bytes; + +	DRM_ERROR("too many retries, giving up\n"); +	return -EIO;  }  /* Write a single byte to the aux channel in native mode */ @@ -582,6 +585,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,  	int reply_bytes;  	uint8_t ack;  	int ret; +	int retry;  	if (WARN_ON(recv_bytes > 19))  		return -E2BIG; @@ -595,7 +599,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,  	msg_bytes = 4;  	reply_bytes = recv_bytes + 1; -	for (;;) { +	for (retry = 0; retry < 7; retry++) {  		ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes,  				      reply, reply_bytes);  		if (ret == 0) @@ -608,10 +612,13 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,  			return ret - 1;  		}  		else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER) -			udelay(100); +			usleep_range(400, 500);  		else  			return -EIO;  	} + +	DRM_ERROR("too many retries, giving up\n"); +	return -EIO;  }  static int @@ -1242,17 +1249,24 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)  	DRM_DEBUG_KMS("Turn eDP power off\n"); +	WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n"); +  	pp = ironlake_get_pp_control(intel_dp);  	/* We need to switch off panel power _and_ force vdd, for otherwise some  	 * panels get very unhappy and cease to work. */ -	pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE); +	pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);  	pp_ctrl_reg = _pp_ctrl_reg(intel_dp);  	I915_WRITE(pp_ctrl_reg, pp);  	POSTING_READ(pp_ctrl_reg); +	intel_dp->want_panel_vdd = false; +  	ironlake_wait_panel_off(intel_dp); + +	/* We got a reference when we enabled the VDD. */ +	intel_runtime_pm_put(dev_priv);  }  void ironlake_edp_backlight_on(struct intel_dp *intel_dp) @@ -1632,7 +1646,7 @@ static void intel_edp_psr_enable_source(struct intel_dp *intel_dp)  		val |= EDP_PSR_LINK_DISABLE;  	I915_WRITE(EDP_PSR_CTL(dev), val | -		   IS_BROADWELL(dev) ? 0 : link_entry_time | +		   (IS_BROADWELL(dev) ? 0 : link_entry_time) |  		   max_sleep_time << EDP_PSR_MAX_SLEEP_TIME_SHIFT |  		   idle_frames << EDP_PSR_IDLE_FRAME_SHIFT |  		   EDP_PSR_ENABLE); @@ -1777,6 +1791,7 @@ static void intel_disable_dp(struct intel_encoder *encoder)  	/* Make sure the panel is off before trying to change the mode. But also  	 * ensure that we have vdd while we switch off the panel. */ +	ironlake_edp_panel_vdd_on(intel_dp);  	ironlake_edp_backlight_off(intel_dp);  	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);  	ironlake_edp_panel_off(intel_dp); @@ -1869,10 +1884,12 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)  	mutex_unlock(&dev_priv->dpio_lock); -	/* init power sequencer on this pipe and port */ -	intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); -	intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, -						      &power_seq); +	if (is_edp(intel_dp)) { +		/* init power sequencer on this pipe and port */ +		intel_dp_init_panel_power_sequencer(dev, intel_dp, &power_seq); +		intel_dp_init_panel_power_sequencer_registers(dev, intel_dp, +							      &power_seq); +	}  	intel_enable_dp(encoder);  | 
