mirror of https://gitee.com/openkylin/linux.git
drm/i915/dp: Really try 5 times before giving up.
Only stop trying if the aux channel sucessfully reports that the transmission was completed, otherwise try again. On the 5th failure, bail and report that something is amiss. This fixes a sporadic failure in reading the EDID for my external panel over DP. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: stable@kernel.org
This commit is contained in:
parent
b66d842467
commit
4f7f7b7eb9
|
@ -239,7 +239,6 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|||
uint32_t ch_data = ch_ctl + 4;
|
||||
int i;
|
||||
int recv_bytes;
|
||||
uint32_t ctl;
|
||||
uint32_t status;
|
||||
uint32_t aux_clock_divider;
|
||||
int try, precharge;
|
||||
|
@ -263,41 +262,43 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|||
else
|
||||
precharge = 5;
|
||||
|
||||
if (I915_READ(ch_ctl) & DP_AUX_CH_CTL_SEND_BUSY) {
|
||||
DRM_ERROR("dp_aux_ch not started status 0x%08x\n",
|
||||
I915_READ(ch_ctl));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* Must try at least 3 times according to DP spec */
|
||||
for (try = 0; try < 5; try++) {
|
||||
/* Load the send data into the aux channel data registers */
|
||||
for (i = 0; i < send_bytes; i += 4) {
|
||||
uint32_t d = pack_aux(send + i, send_bytes - i);
|
||||
|
||||
I915_WRITE(ch_data + i, d);
|
||||
}
|
||||
|
||||
ctl = (DP_AUX_CH_CTL_SEND_BUSY |
|
||||
DP_AUX_CH_CTL_TIME_OUT_400us |
|
||||
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
||||
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
|
||||
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR);
|
||||
for (i = 0; i < send_bytes; i += 4)
|
||||
I915_WRITE(ch_data + i,
|
||||
pack_aux(send + i, send_bytes - i));
|
||||
|
||||
/* Send the command and wait for it to complete */
|
||||
I915_WRITE(ch_ctl, ctl);
|
||||
(void) I915_READ(ch_ctl);
|
||||
I915_WRITE(ch_ctl,
|
||||
DP_AUX_CH_CTL_SEND_BUSY |
|
||||
DP_AUX_CH_CTL_TIME_OUT_400us |
|
||||
(send_bytes << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
|
||||
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
|
||||
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT) |
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR);
|
||||
for (;;) {
|
||||
udelay(100);
|
||||
status = I915_READ(ch_ctl);
|
||||
if ((status & DP_AUX_CH_CTL_SEND_BUSY) == 0)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
/* Clear done status and any errors */
|
||||
I915_WRITE(ch_ctl, (status |
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR));
|
||||
(void) I915_READ(ch_ctl);
|
||||
if ((status & DP_AUX_CH_CTL_TIME_OUT_ERROR) == 0)
|
||||
I915_WRITE(ch_ctl,
|
||||
status |
|
||||
DP_AUX_CH_CTL_DONE |
|
||||
DP_AUX_CH_CTL_TIME_OUT_ERROR |
|
||||
DP_AUX_CH_CTL_RECEIVE_ERROR);
|
||||
if (status & DP_AUX_CH_CTL_DONE)
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -324,15 +325,12 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
|
|||
/* Unload any bytes sent back from the other side */
|
||||
recv_bytes = ((status & DP_AUX_CH_CTL_MESSAGE_SIZE_MASK) >>
|
||||
DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
|
||||
|
||||
if (recv_bytes > recv_size)
|
||||
recv_bytes = recv_size;
|
||||
|
||||
for (i = 0; i < recv_bytes; i += 4) {
|
||||
uint32_t d = I915_READ(ch_data + i);
|
||||
|
||||
unpack_aux(d, recv + i, recv_bytes - i);
|
||||
}
|
||||
for (i = 0; i < recv_bytes; i += 4)
|
||||
unpack_aux(I915_READ(ch_data + i),
|
||||
recv + i, recv_bytes - i);
|
||||
|
||||
return recv_bytes;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue