At the beginning of the aux transfer a check for aux control busy bit is done. Then as per the spec on aux transfer timeout, need to retry freshly for 3 times with a delay which is taken care by the control register. On each of these 3 trials a check for busy has to be done so as to start freshly. v2: updated the commit message v4: check for SEND_BUSY after write (Imre) v5: reverted the send_ctl to the while loop (Jani) v6: Fixed the BAT failure Signed-off-by: Arun R Murthy <arun.r.murthy@xxxxxxxxx> --- drivers/gpu/drm/i915/display/intel_dp_aux.c | 36 ++++++++++++++------- 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_dp_aux.c b/drivers/gpu/drm/i915/display/intel_dp_aux.c index 197c6e81db14..14a0704fb4b4 100644 --- a/drivers/gpu/drm/i915/display/intel_dp_aux.c +++ b/drivers/gpu/drm/i915/display/intel_dp_aux.c @@ -37,7 +37,7 @@ static void intel_dp_aux_unpack(u32 src, u8 *dst, int dst_bytes) } static u32 -intel_dp_aux_wait_done(struct intel_dp *intel_dp) +intel_dp_aux_wait_for(struct intel_dp *intel_dp, u32 mask, u32 val) { struct drm_i915_private *i915 = dp_to_i915(intel_dp); i915_reg_t ch_ctl = intel_dp->aux_ch_ctl_reg(intel_dp); @@ -45,8 +45,7 @@ intel_dp_aux_wait_done(struct intel_dp *intel_dp) u32 status; int ret; - ret = __intel_de_wait_for_register(i915, ch_ctl, - DP_AUX_CH_CTL_SEND_BUSY, 0, + ret = __intel_de_wait_for_register(i915, ch_ctl, mask, val, 2, timeout_ms, &status); if (ret == -ETIMEDOUT) @@ -321,13 +320,8 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, /* Send the command and wait for it to complete */ intel_de_write(i915, ch_ctl, send_ctl); - status = intel_dp_aux_wait_done(intel_dp); - - /* Clear done status and any errors */ - intel_de_write(i915, ch_ctl, - status | DP_AUX_CH_CTL_DONE | - DP_AUX_CH_CTL_TIME_OUT_ERROR | - DP_AUX_CH_CTL_RECEIVE_ERROR); + status = intel_dp_aux_wait_for(intel_dp, + DP_AUX_CH_CTL_SEND_BUSY, 0); /* * DP CTS 1.2 Core Rev 1.1, 4.2.1.1 & 4.2.1.2 @@ -335,15 +329,33 @@ intel_dp_aux_xfer(struct intel_dp *intel_dp, * Timeout errors from the HW already meet this * requirement so skip to next iteration */ - if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) + if (status & DP_AUX_CH_CTL_TIME_OUT_ERROR) { + /* Clear the timeout error */ + intel_de_rmw(i915, ch_ctl, DP_AUX_CH_CTL_TIME_OUT_ERROR, 0); + + /* Clear all errors */ + status = intel_de_read(i915, ch_ctl); + intel_de_write(i915, ch_ctl, status); continue; + } if (status & DP_AUX_CH_CTL_RECEIVE_ERROR) { + /* Clear the reveive error */ + intel_de_rmw(i915, ch_ctl, DP_AUX_CH_CTL_RECEIVE_ERROR, 0); usleep_range(400, 500); + /* Clear all errors */ + status = intel_de_read(i915, ch_ctl); + intel_de_write(i915, ch_ctl, status); continue; } - if (status & DP_AUX_CH_CTL_DONE) + if (status & DP_AUX_CH_CTL_DONE) { + /* Clear aux done */ + intel_de_rmw(i915, ch_ctl, DP_AUX_CH_CTL_DONE, 0); + /* Clear all errors */ + status = intel_de_read(i915, ch_ctl); + intel_de_write(i915, ch_ctl, status); goto done; + } } } -- 2.25.1