<div dir="ltr">I liked the approach and agree with Daniel, so with his suggestions feel free to use:<div><span style="font-size:13.1999998092651px;line-height:19.7999992370605px">Reviewed-by: Rodrigo Vivi <<a href="mailto:rodrigo.vivi@intel.com">rodrigo.vivi@intel.com</a>></span><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Fri, Sep 4, 2015 at 7:46 AM Daniel Vetter <<a href="mailto:daniel@ffwll.ch">daniel@ffwll.ch</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On Fri, Sep 04, 2015 at 06:56:12PM +0530, Sonika Jindal wrote:<br>
> From: Shashank Sharma <<a href="mailto:shashank.sharma@intel.com" target="_blank">shashank.sharma@intel.com</a>><br>
><br>
> This patch adds a separate probe function for HDMI<br>
> EDID read over DDC channel. This function has been<br>
> registered as a .hot_plug handler for HDMI encoder.<br>
><br>
> The current implementation of hdmi_detect()<br>
> function re-sets the cached HDMI edid (in connector->detect_edid) in<br>
> every detect call.This function gets called many times, sometimes<br>
> directly from userspace probes, forcing drivers to read EDID every<br>
> detect function call.This causes several problems like:<br>
><br>
> 1. Race conditions in multiple hot_plug / unplug cases, between<br>
>    interrupts bottom halves and userspace detections.<br>
> 2. Many Un-necessary EDID reads for single hotplug/unplug<br>
> 3. HDMI complaince failures which expects only one EDID read per hotplug<br>
><br>
> This function will be serving the purpose of really reading the EDID<br>
> by really probing the DDC channel, and updating the cached EDID.<br>
><br>
> The plan is to:<br>
> 1. i915 IRQ handler bottom half function already calls<br>
>    intel_encoder->hotplug() function. Adding This probe function which<br>
>    will read the EDID only in case of a hotplug / unplug.<br>
> 2. During init_connector his probe will be called to read the edid<br>
> 3. Reuse the cached EDID in hdmi_detect() function.<br>
><br>
> The "< gen7" check is there because this was tested only for >=gen7<br>
> platforms. For older platforms the hotplug/reading edid path remains same.<br>
><br>
> v2: Calling set_edid instead of hdmi_probe during init.<br>
> Also, for platforms having DDI, intel_encoder for DP and HDMI is same<br>
> (taken from intel_dig_port), so for DP also, hot_plug function gets called<br>
> which is not intended here. So, check for HDMI in intel_hdmi_probe<br>
> Rely on HPD for updating edid only for platforms gen > 8 and also for VLV.<br>
><br>
> v3: Dropping the gen < 8 || !VLV  check. Now all platforms should rely on<br>
> hotplug or init for updating the edid.(Daniel)<br>
> Also, calling hdmi_probe in init instead of set_edid<br>
><br>
> Signed-off-by: Shashank Sharma <<a href="mailto:shashank.sharma@intel.com" target="_blank">shashank.sharma@intel.com</a>><br>
> Signed-off-by: Sonika Jindal <<a href="mailto:sonika.jindal@intel.com" target="_blank">sonika.jindal@intel.com</a>><br>
> ---<br>
>  drivers/gpu/drm/i915/intel_hdmi.c |   46 ++++++++++++++++++++++++++++++++-----<br>
>  1 file changed, 40 insertions(+), 6 deletions(-)<br>
><br>
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c<br>
> index 5bdb386..1eda71a 100644<br>
> --- a/drivers/gpu/drm/i915/intel_hdmi.c<br>
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c<br>
> @@ -1368,23 +1368,53 @@ intel_hdmi_set_edid(struct drm_connector *connector)<br>
>       return connected;<br>
>  }<br>
><br>
> +void intel_hdmi_probe(struct intel_encoder *intel_encoder)<br>
<br>
Please call it _hot_plug if it's for the _hot_plug path.<br>
<br>
> +{<br>
> +     struct intel_hdmi *intel_hdmi =<br>
> +                     enc_to_intel_hdmi(&intel_encoder->base);<br>
> +     struct intel_connector *intel_connector =<br>
> +                             intel_hdmi->attached_connector;<br>
> +<br>
> +     /*<br>
> +      * We are here, means there is a hotplug or a force<br>
> +      * detection. Clear the cached EDID and probe the<br>
> +      * DDC bus to check the current status of HDMI.<br>
> +      */<br>
> +     intel_hdmi_unset_edid(&intel_connector->base);<br>
> +     if (intel_hdmi_set_edid(&intel_connector->base))<br>
> +             DRM_DEBUG_DRIVER("DDC probe: got EDID\n");<br>
> +     else<br>
> +             DRM_DEBUG_DRIVER("DDC probe: no EDID\n");<br>
> +}<br>
> +<br>
>  static enum drm_connector_status<br>
>  intel_hdmi_detect(struct drm_connector *connector, bool force)<br>
>  {<br>
>       enum drm_connector_status status;<br>
> +     struct intel_connector *intel_connector =<br>
> +                             to_intel_connector(connector);<br>
><br>
>       DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",<br>
>                     connector-><a href="http://base.id" rel="noreferrer" target="_blank">base.id</a>, connector->name);<br>
> +     /*<br>
> +      * There are many userspace calls which probe EDID from<br>
> +      * detect path. In case of multiple hotplug/unplug, these<br>
> +      * can cause race conditions while probing EDID. Also its<br>
> +      * waste of CPU cycles to read the EDID again and again<br>
> +      * unless there is a real hotplug.<br>
> +      * So, rely on hotplugs and init to read edid.<br>
> +      * Check connector status based on availability of cached EDID.<br>
> +      */<br>
><br>
> -     intel_hdmi_unset_edid(connector);<br>
> -<br>
> -     if (intel_hdmi_set_edid(connector)) {<br>
> +     if (intel_connector->detect_edid) {<br>
>               struct intel_hdmi *intel_hdmi = intel_attached_hdmi(connector);<br>
> -<br>
> -             hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;<br>
>               status = connector_status_connected;<br>
> -     } else<br>
> +             hdmi_to_dig_port(intel_hdmi)->base.type = INTEL_OUTPUT_HDMI;<br>
> +             DRM_DEBUG_DRIVER("hdmi status = connected\n");<br>
> +     } else {<br>
>               status = connector_status_disconnected;<br>
> +             DRM_DEBUG_DRIVER("hdmi status = disconnected\n");<br>
> +     }<br>
><br>
>       return status;<br>
>  }<br>
> @@ -2104,11 +2134,15 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,<br>
>       intel_connector->unregister = intel_connector_unregister;<br>
><br>
>       intel_hdmi_add_properties(intel_hdmi, connector);<br>
> +     intel_encoder->hot_plug = intel_hdmi_probe;<br>
><br>
>       intel_connector_attach_encoder(intel_connector, intel_encoder);<br>
>       drm_connector_register(connector);<br>
>       intel_hdmi->attached_connector = intel_connector;<br>
><br>
> +     /* Set edid during init */<br>
> +     intel_hdmi_probe(intel_encoder);<br>
<br>
Separate patch, but we really don't want this, initial probe should be<br>
done async to avoid stalling the driver.<br>
-Daniel<br>
<br>
> +<br>
>       /* For G4X desktop chip, PEG_BAND_GAP_DATA 3:0 must first be written<br>
>        * 0xd.  Failure to do so will result in spurious interrupts being<br>
>        * generated on the port when a cable is not attached.<br>
> --<br>
> 1.7.10.4<br>
><br>
> _______________________________________________<br>
> Intel-gfx mailing list<br>
> <a href="mailto:Intel-gfx@lists.freedesktop.org" target="_blank">Intel-gfx@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx" rel="noreferrer" target="_blank">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
<br>
--<br>
Daniel Vetter<br>
Software Engineer, Intel Corporation<br>
<a href="http://blog.ffwll.ch" rel="noreferrer" target="_blank">http://blog.ffwll.ch</a><br>
_______________________________________________<br>
Intel-gfx mailing list<br>
<a href="mailto:Intel-gfx@lists.freedesktop.org" target="_blank">Intel-gfx@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/intel-gfx" rel="noreferrer" target="_blank">http://lists.freedesktop.org/mailman/listinfo/intel-gfx</a><br>
</blockquote></div>