| From f6a1906674005377b64ee5431c1418077c1b2425 Mon Sep 17 00:00:00 2001 |
| From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> |
| Date: Thu, 16 Oct 2014 20:46:09 +0300 |
| Subject: drm/i915: Do a dummy DPCD read before the actual read |
| MIME-Version: 1.0 |
| Content-Type: text/plain; charset=UTF-8 |
| Content-Transfer-Encoding: 8bit |
| |
| From: =?UTF-8?q?Ville=20Syrj=C3=A4l=C3=A4?= <ville.syrjala@linux.intel.com> |
| |
| commit f6a1906674005377b64ee5431c1418077c1b2425 upstream. |
| |
| Sometimes we seem to get utter garbage from DPCD reads. The resulting |
| buffer is filled with the same byte, and the operation completed without |
| errors. My HP ZR24w monitor seems particularly susceptible to this |
| problem once it's gone into a sleep mode. |
| |
| The issue seems to happen only for the first AUX message that wakes the |
| sink up. But as the first AUX read we often do is the DPCD receiver |
| cap it does wreak a bit of havoc with subsequent link training etc. when |
| the receiver cap bw/lane/etc. information is garbage. |
| |
| A sufficient workaround seems to be to perform a single byte dummy read |
| before reading the actual data. I suppose that just wakes up the sink |
| sufficiently and we can just throw away the returned data in case it's |
| crap. DP_DPCD_REV seems like a sufficiently safe location to read here. |
| |
| Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com> |
| Reviewed-by: Todd Previte <tprevite@gmail.com> |
| Signed-off-by: Jani Nikula <jani.nikula@intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/gpu/drm/i915/intel_dp.c | 7 +++++++ |
| 1 file changed, 7 insertions(+) |
| |
| --- a/drivers/gpu/drm/i915/intel_dp.c |
| +++ b/drivers/gpu/drm/i915/intel_dp.c |
| @@ -2364,6 +2364,13 @@ intel_dp_dpcd_read_wake(struct drm_dp_au |
| ssize_t ret; |
| int i; |
| |
| + /* |
| + * Sometime we just get the same incorrect byte repeated |
| + * over the entire buffer. Doing just one throw away read |
| + * initially seems to "solve" it. |
| + */ |
| + drm_dp_dpcd_read(aux, DP_DPCD_REV, buffer, 1); |
| + |
| for (i = 0; i < 3; i++) { |
| ret = drm_dp_dpcd_read(aux, offset, buffer, size); |
| if (ret == size) |