drm/i915/dp: Really try 5 times before giving up.
authorChris Wilson <chris@chris-wilson.co.uk>
Wed, 18 Aug 2010 17:12:56 +0000 (18:12 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Tue, 7 Sep 2010 10:14:17 +0000 (11:14 +0100)
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
drivers/gpu/drm/i915/intel_dp.c

index 9caccd03dccb6841fea4be4c5fa43f5e8822ee33..51d142939a26e9abe76fdfe8a90aa94ff0f3b612 100644 (file)
@@ -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;
 }