diff mbox

[v1] drm/i915: Try EDID bitbanging on HDMI after failed read

Message ID 013b6732-f3d7-41e0-9710-97c0c7133f47@rwthex-w2-a.rwth-ad.de (mailing list archive)
State New, archived
Headers show

Commit Message

Stefan Brüns Dec. 24, 2017, 9:45 p.m. UTC
The ACK/NACK implementation as found in e.g. the G965 has the falling
clock edge and the release of the data line to ACK the received byte
happen at the same time.

Some HDMI-to-VGA converters apparently read the ACK not in the middle of
the clock high phase, but at the rising clock edge, so instead of an ACK
sometimes a NACK is read and the slave (i.e. the EDID ROM) ends the
transfer.

The bitbanging releases the data line for the ACK only 1/4 bit time after
the falling clock edge, so a slave will see the correct value no matter
if is samples at the rising or the falling clock edge or in the center.

Fallback to bitbanging is already done for the CRT connector.

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92685

Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>

---

 drivers/gpu/drm/i915/intel_hdmi.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

Comments

Daniel Vetter Jan. 9, 2018, 9 a.m. UTC | #1
On Sun, Dec 24, 2017 at 10:45:24PM +0100, Stefan Brüns wrote:
> The ACK/NACK implementation as found in e.g. the G965 has the falling
> clock edge and the release of the data line to ACK the received byte
> happen at the same time.
> 
> Some HDMI-to-VGA converters apparently read the ACK not in the middle of
> the clock high phase, but at the rising clock edge, so instead of an ACK
> sometimes a NACK is read and the slave (i.e. the EDID ROM) ends the
> transfer.
> 
> The bitbanging releases the data line for the ACK only 1/4 bit time after
> the falling clock edge, so a slave will see the correct value no matter
> if is samples at the rising or the falling clock edge or in the center.
> 
> Fallback to bitbanging is already done for the CRT connector.
> 
> Bug: https://bugs.freedesktop.org/show_bug.cgi?id=92685
> 
> Signed-off-by: Stefan Brüns <stefan.bruens@rwth-aachen.de>

Applied with a Cc: stable so it gets backported.

Thanks, Daniel

> 
> ---
> 
>  drivers/gpu/drm/i915/intel_hdmi.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
> index 4dea833f9d1b..847cda4c017c 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -1573,12 +1573,20 @@ intel_hdmi_set_edid(struct drm_connector *connector)
>  	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
>  	struct edid *edid;
>  	bool connected = false;
> +	struct i2c_adapter *i2c;
>  
>  	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
>  
> -	edid = drm_get_edid(connector,
> -			    intel_gmbus_get_adapter(dev_priv,
> -			    intel_hdmi->ddc_bus));
> +	i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
> +
> +	edid = drm_get_edid(connector, i2c);
> +
> +	if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
> +		DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
> +		intel_gmbus_force_bit(i2c, true);
> +		edid = drm_get_edid(connector, i2c);
> +		intel_gmbus_force_bit(i2c, false);
> +	}
>  
>  	intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);
>  
> -- 
> 2.15.1
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
diff mbox

Patch

diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 4dea833f9d1b..847cda4c017c 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -1573,12 +1573,20 @@  intel_hdmi_set_edid(struct drm_connector *connector)
 	struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);
 	struct edid *edid;
 	bool connected = false;
+	struct i2c_adapter *i2c;
 
 	intel_display_power_get(dev_priv, POWER_DOMAIN_GMBUS);
 
-	edid = drm_get_edid(connector,
-			    intel_gmbus_get_adapter(dev_priv,
-			    intel_hdmi->ddc_bus));
+	i2c = intel_gmbus_get_adapter(dev_priv, intel_hdmi->ddc_bus);
+
+	edid = drm_get_edid(connector, i2c);
+
+	if (!edid && !intel_gmbus_is_forced_bit(i2c)) {
+		DRM_DEBUG_KMS("HDMI GMBUS EDID read failed, retry using GPIO bit-banging\n");
+		intel_gmbus_force_bit(i2c, true);
+		edid = drm_get_edid(connector, i2c);
+		intel_gmbus_force_bit(i2c, false);
+	}
 
 	intel_hdmi_dp_dual_mode_detect(connector, edid != NULL);