drm/i915: Improve DP downstream HPD handling
diff mbox

Message ID 1436184768-18920-1-git-send-email-ville.syrjala@linux.intel.com
State New
Headers show

Commit Message

Ville Syrjälä July 6, 2015, 12:12 p.m. UTC
From: Ville Syrjälä <ville.syrjala@linux.intel.com>

DP dongles may signal downstream HPD via short HPD pulses. If we know
the device has a HPD capable downstream port, make sure we kick off the
full hotplug processing even for short HPDs.

Additonally setting the sink to DPMS off kills the downstream HPD (at
least on my DP->VGA dongle), so skip the DPMS off for such dongles
when we turn off the port.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

Comments

Sivakumar Thulasimani July 7, 2015, 9:56 a.m. UTC | #1
On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>
> DP dongles may signal downstream HPD via short HPD pulses. If we know
> the device has a HPD capable downstream port, make sure we kick off the
> full hotplug processing even for short HPDs.
>
> Additonally setting the sink to DPMS off kills the downstream HPD (at
> least on my DP->VGA dongle), so skip the DPMS off for such dongles
> when we turn off the port.
>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>   drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
>   1 file changed, 17 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index e88cec2..f424833 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>   	}
>   }
>   
> +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
> +{
> +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
> +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
> +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
> +}
> +
>   static void intel_disable_dp(struct intel_encoder *encoder)
>   {
>   	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
>   	 * ensure that we have vdd while we switch off the panel. */
>   	intel_edp_panel_vdd_on(intel_dp);
>   	intel_edp_backlight_off(intel_dp);
> -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> +	/* Skip power down to keep downstream HPD working */
> +	if (!intel_dp_has_downstream_hpd(intel_dp))
> +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>   	intel_edp_panel_off(intel_dp);
>   
>   	/* disable the port before the pipe on g4x */
> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>   			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>   			intel_dp_check_link_status(intel_dp);
>   			drm_modeset_unlock(&dev->mode_config.connection_mutex);
> +
> +			/*
> +			 * Downstream HPD will generate a short HPD,
> +			 * so we want full hotplug processing here.
> +			 */
> +			if (intel_dp_has_downstream_hpd(intel_dp))
> +				goto put_power;
>   		}
>   	}
>   
I am looking into compliance changes for DP and this seems a relevant 
change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8, 
we are supposed to read the sink_count and do full detection if 
sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just 
check SINK_COUNT and do full detect ?
Ville Syrjälä July 7, 2015, 11:10 a.m. UTC | #2
On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani wrote:
> 
> 
> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >
> > DP dongles may signal downstream HPD via short HPD pulses. If we know
> > the device has a HPD capable downstream port, make sure we kick off the
> > full hotplug processing even for short HPDs.
> >
> > Additonally setting the sink to DPMS off kills the downstream HPD (at
> > least on my DP->VGA dongle), so skip the DPMS off for such dongles
> > when we turn off the port.
> >
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >   drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
> >   1 file changed, 17 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index e88cec2..f424833 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> >   	}
> >   }
> >   
> > +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
> > +{
> > +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
> > +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
> > +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
> > +}
> > +
> >   static void intel_disable_dp(struct intel_encoder *encoder)
> >   {
> >   	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
> >   	 * ensure that we have vdd while we switch off the panel. */
> >   	intel_edp_panel_vdd_on(intel_dp);
> >   	intel_edp_backlight_off(intel_dp);
> > -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> > +	/* Skip power down to keep downstream HPD working */
> > +	if (!intel_dp_has_downstream_hpd(intel_dp))
> > +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> >   	intel_edp_panel_off(intel_dp);
> >   
> >   	/* disable the port before the pipe on g4x */
> > @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
> >   			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> >   			intel_dp_check_link_status(intel_dp);
> >   			drm_modeset_unlock(&dev->mode_config.connection_mutex);
> > +
> > +			/*
> > +			 * Downstream HPD will generate a short HPD,
> > +			 * so we want full hotplug processing here.
> > +			 */
> > +			if (intel_dp_has_downstream_hpd(intel_dp))
> > +				goto put_power;
> >   		}
> >   	}
> >   
> I am looking into compliance changes for DP and this seems a relevant 
> change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8, 
> we are supposed to read the sink_count and do full detection if 
> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just 
> check SINK_COUNT and do full detect ?

->detect() will be called from the hotplug work and that will
check SINK_COUNT.
Sivakumar Thulasimani July 7, 2015, 11:15 a.m. UTC | #3
On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
> On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani wrote:
>>
>> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>
>>> DP dongles may signal downstream HPD via short HPD pulses. If we know
>>> the device has a HPD capable downstream port, make sure we kick off the
>>> full hotplug processing even for short HPDs.
>>>
>>> Additonally setting the sink to DPMS off kills the downstream HPD (at
>>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
>>> when we turn off the port.
>>>
>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>> ---
>>>    drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
>>>    1 file changed, 17 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>>> index e88cec2..f424833 100644
>>> --- a/drivers/gpu/drm/i915/intel_dp.c
>>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>>>    	}
>>>    }
>>>    
>>> +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
>>> +{
>>> +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
>>> +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
>>> +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
>>> +}
>>> +
>>>    static void intel_disable_dp(struct intel_encoder *encoder)
>>>    {
>>>    	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
>>>    	 * ensure that we have vdd while we switch off the panel. */
>>>    	intel_edp_panel_vdd_on(intel_dp);
>>>    	intel_edp_backlight_off(intel_dp);
>>> -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>> +	/* Skip power down to keep downstream HPD working */
>>> +	if (!intel_dp_has_downstream_hpd(intel_dp))
>>> +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>>    	intel_edp_panel_off(intel_dp);
>>>    
>>>    	/* disable the port before the pipe on g4x */
>>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>>>    			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>>>    			intel_dp_check_link_status(intel_dp);
>>>    			drm_modeset_unlock(&dev->mode_config.connection_mutex);
>>> +
>>> +			/*
>>> +			 * Downstream HPD will generate a short HPD,
>>> +			 * so we want full hotplug processing here.
>>> +			 */
>>> +			if (intel_dp_has_downstream_hpd(intel_dp))
>>> +				goto put_power;
>>>    		}
>>>    	}
>>>    
>> I am looking into compliance changes for DP and this seems a relevant
>> change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8,
>> we are supposed to read the sink_count and do full detection if
>> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just
>> check SINK_COUNT and do full detect ?
> ->detect() will be called from the hotplug work and that will
> check SINK_COUNT.
>
No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD resulting 
in detect not getting executed for
the short pulse generated. The spec requires the sink to set only the 
sink count so it is not a must for
the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for 
SINK_COUNT will pass the
compliance test.
Shuang He July 7, 2015, 11:23 a.m. UTC | #4
Tested-By: Intel Graphics QA PRTS (Patch Regression Test System Contact: shuang.he@intel.com)
Task id: 6728
-------------------------------------Summary-------------------------------------
Platform          Delta          drm-intel-nightly          Series Applied
ILK                 -1              302/302              301/302
SNB                                  312/316              312/316
IVB                                  345/345              345/345
BYT                 -1              289/289              288/289
HSW                                  382/382              382/382
-------------------------------------Detailed-------------------------------------
Platform  Test                                drm-intel-nightly          Series Applied
*ILK  igt@kms_flip@flip-vs-rmfb-interruptible      PASS(1)      DMESG_WARN(1)
(dmesg patch applied)drm:intel_pch_fifo_underrun_irq_handler[i915]]*ERROR*PCH_transcoder_A_FIFO_underrun@PCH transcoder A FIFO underrun
*BYT  igt@gem_partial_pwrite_pread@reads-uncached      PASS(1)      FAIL(1)
Note: You need to pay more attention to line start with '*'
Ville Syrjälä July 7, 2015, 11:37 a.m. UTC | #5
On Tue, Jul 07, 2015 at 04:45:11PM +0530, Sivakumar Thulasimani wrote:
> 
> 
> On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
> > On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani wrote:
> >>
> >> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
> >>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>
> >>> DP dongles may signal downstream HPD via short HPD pulses. If we know
> >>> the device has a HPD capable downstream port, make sure we kick off the
> >>> full hotplug processing even for short HPDs.
> >>>
> >>> Additonally setting the sink to DPMS off kills the downstream HPD (at
> >>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
> >>> when we turn off the port.
> >>>
> >>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>> ---
> >>>    drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
> >>>    1 file changed, 17 insertions(+), 1 deletion(-)
> >>>
> >>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> >>> index e88cec2..f424833 100644
> >>> --- a/drivers/gpu/drm/i915/intel_dp.c
> >>> +++ b/drivers/gpu/drm/i915/intel_dp.c
> >>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> >>>    	}
> >>>    }
> >>>    
> >>> +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
> >>> +{
> >>> +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
> >>> +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
> >>> +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
> >>> +}
> >>> +
> >>>    static void intel_disable_dp(struct intel_encoder *encoder)
> >>>    {
> >>>    	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> >>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
> >>>    	 * ensure that we have vdd while we switch off the panel. */
> >>>    	intel_edp_panel_vdd_on(intel_dp);
> >>>    	intel_edp_backlight_off(intel_dp);
> >>> -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> >>> +	/* Skip power down to keep downstream HPD working */
> >>> +	if (!intel_dp_has_downstream_hpd(intel_dp))
> >>> +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> >>>    	intel_edp_panel_off(intel_dp);
> >>>    
> >>>    	/* disable the port before the pipe on g4x */
> >>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
> >>>    			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> >>>    			intel_dp_check_link_status(intel_dp);
> >>>    			drm_modeset_unlock(&dev->mode_config.connection_mutex);
> >>> +
> >>> +			/*
> >>> +			 * Downstream HPD will generate a short HPD,
> >>> +			 * so we want full hotplug processing here.
> >>> +			 */
> >>> +			if (intel_dp_has_downstream_hpd(intel_dp))
> >>> +				goto put_power;
> >>>    		}
> >>>    	}
> >>>    
> >> I am looking into compliance changes for DP and this seems a relevant
> >> change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8,
> >> we are supposed to read the sink_count and do full detection if
> >> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just
> >> check SINK_COUNT and do full detect ?
> > ->detect() will be called from the hotplug work and that will
> > check SINK_COUNT.
> >
> No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD resulting 
> in detect not getting executed for
> the short pulse generated. The spec requires the sink to set only the 
> sink count so it is not a must for
> the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for 
> SINK_COUNT will pass the
> compliance test.

That seems stupid. If the downstream port isn't HPD capable then we have
no reason to check SINK_COUNT after a short HPD as the short HPD
coudln't have been caused by a downstram HPD. Obviuously we still
check SINK_COUNT after a long HPD to figure out if anything is connected
when the branch device itself gets connected to the source.
Ville Syrjälä July 7, 2015, 11:54 a.m. UTC | #6
On Tue, Jul 07, 2015 at 02:37:46PM +0300, Ville Syrjälä wrote:
> On Tue, Jul 07, 2015 at 04:45:11PM +0530, Sivakumar Thulasimani wrote:
> > 
> > 
> > On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
> > > On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani wrote:
> > >>
> > >> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
> > >>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >>>
> > >>> DP dongles may signal downstream HPD via short HPD pulses. If we know
> > >>> the device has a HPD capable downstream port, make sure we kick off the
> > >>> full hotplug processing even for short HPDs.
> > >>>
> > >>> Additonally setting the sink to DPMS off kills the downstream HPD (at
> > >>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
> > >>> when we turn off the port.
> > >>>
> > >>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > >>> ---
> > >>>    drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
> > >>>    1 file changed, 17 insertions(+), 1 deletion(-)
> > >>>
> > >>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > >>> index e88cec2..f424833 100644
> > >>> --- a/drivers/gpu/drm/i915/intel_dp.c
> > >>> +++ b/drivers/gpu/drm/i915/intel_dp.c
> > >>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
> > >>>    	}
> > >>>    }
> > >>>    
> > >>> +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
> > >>> +{
> > >>> +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
> > >>> +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
> > >>> +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
> > >>> +}
> > >>> +
> > >>>    static void intel_disable_dp(struct intel_encoder *encoder)
> > >>>    {
> > >>>    	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > >>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
> > >>>    	 * ensure that we have vdd while we switch off the panel. */
> > >>>    	intel_edp_panel_vdd_on(intel_dp);
> > >>>    	intel_edp_backlight_off(intel_dp);
> > >>> -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> > >>> +	/* Skip power down to keep downstream HPD working */
> > >>> +	if (!intel_dp_has_downstream_hpd(intel_dp))
> > >>> +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> > >>>    	intel_edp_panel_off(intel_dp);
> > >>>    
> > >>>    	/* disable the port before the pipe on g4x */
> > >>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
> > >>>    			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> > >>>    			intel_dp_check_link_status(intel_dp);
> > >>>    			drm_modeset_unlock(&dev->mode_config.connection_mutex);
> > >>> +
> > >>> +			/*
> > >>> +			 * Downstream HPD will generate a short HPD,
> > >>> +			 * so we want full hotplug processing here.
> > >>> +			 */
> > >>> +			if (intel_dp_has_downstream_hpd(intel_dp))
> > >>> +				goto put_power;
> > >>>    		}
> > >>>    	}
> > >>>    
> > >> I am looking into compliance changes for DP and this seems a relevant
> > >> change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8,
> > >> we are supposed to read the sink_count and do full detection if
> > >> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just
> > >> check SINK_COUNT and do full detect ?
> > > ->detect() will be called from the hotplug work and that will
> > > check SINK_COUNT.
> > >
> > No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD resulting 
> > in detect not getting executed for
> > the short pulse generated. The spec requires the sink to set only the 
> > sink count so it is not a must for
> > the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for 
> > SINK_COUNT will pass the
> > compliance test.
> 
> That seems stupid. If the downstream port isn't HPD capable then we have
> no reason to check SINK_COUNT after a short HPD as the short HPD
> coudln't have been caused by a downstram HPD. Obviuously we still
> check SINK_COUNT after a long HPD to figure out if anything is connected
> when the branch device itself gets connected to the source.

Actually that's not correct. We don't check SINK_COUNT unless the downstream
port is HPD capable.

The spec says:
"If the DFP does not provide for means for plug/unplug detection, the
adaptor must set the SINK_COUNT field bits, as if those Sink devices were
all permanently plugged."

So according to the there can't be any changes in SINK_COUNT if the
downstream port is not HPD capable.
Sivakumar Thulasimani July 7, 2015, 12:20 p.m. UTC | #7
On 7/7/2015 5:24 PM, Ville Syrjälä wrote:
> On Tue, Jul 07, 2015 at 02:37:46PM +0300, Ville Syrjälä wrote:
>> On Tue, Jul 07, 2015 at 04:45:11PM +0530, Sivakumar Thulasimani wrote:
>>>
>>> On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
>>>> On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani wrote:
>>>>> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>
>>>>>> DP dongles may signal downstream HPD via short HPD pulses. If we know
>>>>>> the device has a HPD capable downstream port, make sure we kick off the
>>>>>> full hotplug processing even for short HPDs.
>>>>>>
>>>>>> Additonally setting the sink to DPMS off kills the downstream HPD (at
>>>>>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
>>>>>> when we turn off the port.
>>>>>>
>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>> ---
>>>>>>     drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
>>>>>>     1 file changed, 17 insertions(+), 1 deletion(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
>>>>>> index e88cec2..f424833 100644
>>>>>> --- a/drivers/gpu/drm/i915/intel_dp.c
>>>>>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>>>>>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
>>>>>>     	}
>>>>>>     }
>>>>>>     
>>>>>> +static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
>>>>>> +{
>>>>>> +	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
>>>>>> +		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
>>>>>> +		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
>>>>>> +}
>>>>>> +
>>>>>>     static void intel_disable_dp(struct intel_encoder *encoder)
>>>>>>     {
>>>>>>     	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>>>>>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct intel_encoder *encoder)
>>>>>>     	 * ensure that we have vdd while we switch off the panel. */
>>>>>>     	intel_edp_panel_vdd_on(intel_dp);
>>>>>>     	intel_edp_backlight_off(intel_dp);
>>>>>> -	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>>>>> +	/* Skip power down to keep downstream HPD working */
>>>>>> +	if (!intel_dp_has_downstream_hpd(intel_dp))
>>>>>> +		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>>>>>     	intel_edp_panel_off(intel_dp);
>>>>>>     
>>>>>>     	/* disable the port before the pipe on g4x */
>>>>>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
>>>>>>     			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>>>>>>     			intel_dp_check_link_status(intel_dp);
>>>>>>     			drm_modeset_unlock(&dev->mode_config.connection_mutex);
>>>>>> +
>>>>>> +			/*
>>>>>> +			 * Downstream HPD will generate a short HPD,
>>>>>> +			 * so we want full hotplug processing here.
>>>>>> +			 */
>>>>>> +			if (intel_dp_has_downstream_hpd(intel_dp))
>>>>>> +				goto put_power;
>>>>>>     		}
>>>>>>     	}
>>>>>>     
>>>>> I am looking into compliance changes for DP and this seems a relevant
>>>>> change for compliance as well. but as per Link CTS 1.2 section 4.2.2.8,
>>>>> we are supposed to read the sink_count and do full detection if
>>>>> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can we just
>>>>> check SINK_COUNT and do full detect ?
>>>> ->detect() will be called from the hotplug work and that will
>>>> check SINK_COUNT.
>>>>
>>> No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD resulting
>>> in detect not getting executed for
>>> the short pulse generated. The spec requires the sink to set only the
>>> sink count so it is not a must for
>>> the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for
>>> SINK_COUNT will pass the
>>> compliance test.
>> That seems stupid. If the downstream port isn't HPD capable then we have
>> no reason to check SINK_COUNT after a short HPD as the short HPD
>> coudln't have been caused by a downstram HPD. Obviuously we still
>> check SINK_COUNT after a long HPD to figure out if anything is connected
>> when the branch device itself gets connected to the source.
> Actually that's not correct. We don't check SINK_COUNT unless the downstream
> port is HPD capable.
>
> The spec says:
> "If the DFP does not provide for means for plug/unplug detection, the
> adaptor must set the SINK_COUNT field bits, as if those Sink devices were
> all permanently plugged."
>
> So according to the there can't be any changes in SINK_COUNT if the
> downstream port is not HPD capable.
>
>
>
yes, agree on the no changes for SINK_COUNT if HPD is 0. i'll check with 
DP Compliance test
tomorrow and confirm the exact reason for its failure may be my 
understanding of it was incorrect.
Sivakumar Thulasimani July 8, 2015, 12:20 p.m. UTC | #8
On 7/7/2015 5:50 PM, Sivakumar Thulasimani wrote:
>
>
> On 7/7/2015 5:24 PM, Ville Syrjälä wrote:
>> On Tue, Jul 07, 2015 at 02:37:46PM +0300, Ville Syrjälä wrote:
>>> On Tue, Jul 07, 2015 at 04:45:11PM +0530, Sivakumar Thulasimani wrote:
>>>>
>>>> On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
>>>>> On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani 
>>>>> wrote:
>>>>>> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
>>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>>
>>>>>>> DP dongles may signal downstream HPD via short HPD pulses. If we 
>>>>>>> know
>>>>>>> the device has a HPD capable downstream port, make sure we kick 
>>>>>>> off the
>>>>>>> full hotplug processing even for short HPDs.
>>>>>>>
>>>>>>> Additonally setting the sink to DPMS off kills the downstream 
>>>>>>> HPD (at
>>>>>>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
>>>>>>> when we turn off the port.
>>>>>>>
>>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
>>>>>>> ---
>>>>>>>     drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
>>>>>>>     1 file changed, 17 insertions(+), 1 deletion(-)
>>>>>>>
>>>>>>> diff --git a/drivers/gpu/drm/i915/intel_dp.c 
>>>>>>> b/drivers/gpu/drm/i915/intel_dp.c
>>>>>>> index e88cec2..f424833 100644
>>>>>>> --- a/drivers/gpu/drm/i915/intel_dp.c
>>>>>>> +++ b/drivers/gpu/drm/i915/intel_dp.c
>>>>>>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct 
>>>>>>> intel_encoder *encoder,
>>>>>>>         }
>>>>>>>     }
>>>>>>>     +static bool intel_dp_has_downstream_hpd(struct intel_dp 
>>>>>>> *intel_dp)
>>>>>>> +{
>>>>>>> +    return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & 
>>>>>>> DP_DWN_STRM_PORT_PRESENT &&
>>>>>>> +        intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
>>>>>>> +        intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
>>>>>>> +}
>>>>>>> +
>>>>>>>     static void intel_disable_dp(struct intel_encoder *encoder)
>>>>>>>     {
>>>>>>>         struct intel_dp *intel_dp = 
>>>>>>> enc_to_intel_dp(&encoder->base);
>>>>>>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct 
>>>>>>> intel_encoder *encoder)
>>>>>>>          * ensure that we have vdd while we switch off the 
>>>>>>> panel. */
>>>>>>>         intel_edp_panel_vdd_on(intel_dp);
>>>>>>>         intel_edp_backlight_off(intel_dp);
>>>>>>> -    intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>>>>>> +    /* Skip power down to keep downstream HPD working */
>>>>>>> +    if (!intel_dp_has_downstream_hpd(intel_dp))
>>>>>>> +        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
>>>>>>>         intel_edp_panel_off(intel_dp);
>>>>>>>             /* disable the port before the pipe on g4x */
>>>>>>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct 
>>>>>>> intel_digital_port *intel_dig_port, bool long_hpd)
>>>>>>> drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
>>>>>>>                 intel_dp_check_link_status(intel_dp);
>>>>>>> drm_modeset_unlock(&dev->mode_config.connection_mutex);
>>>>>>> +
>>>>>>> +            /*
>>>>>>> +             * Downstream HPD will generate a short HPD,
>>>>>>> +             * so we want full hotplug processing here.
>>>>>>> +             */
>>>>>>> +            if (intel_dp_has_downstream_hpd(intel_dp))
>>>>>>> +                goto put_power;
>>>>>>>             }
>>>>>>>         }
>>>>>> I am looking into compliance changes for DP and this seems a 
>>>>>> relevant
>>>>>> change for compliance as well. but as per Link CTS 1.2 section 
>>>>>> 4.2.2.8,
>>>>>> we are supposed to read the sink_count and do full detection if
>>>>>> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can 
>>>>>> we just
>>>>>> check SINK_COUNT and do full detect ?
>>>>> ->detect() will be called from the hotplug work and that will
>>>>> check SINK_COUNT.
>>>>>
>>>> No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD 
>>>> resulting
>>>> in detect not getting executed for
>>>> the short pulse generated. The spec requires the sink to set only the
>>>> sink count so it is not a must for
>>>> the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for
>>>> SINK_COUNT will pass the
>>>> compliance test.
>>> That seems stupid. If the downstream port isn't HPD capable then we 
>>> have
>>> no reason to check SINK_COUNT after a short HPD as the short HPD
>>> coudln't have been caused by a downstram HPD. Obviuously we still
>>> check SINK_COUNT after a long HPD to figure out if anything is 
>>> connected
>>> when the branch device itself gets connected to the source.
>> Actually that's not correct. We don't check SINK_COUNT unless the 
>> downstream
>> port is HPD capable.
>>
>> The spec says:
>> "If the DFP does not provide for means for plug/unplug detection, the
>> adaptor must set the SINK_COUNT field bits, as if those Sink devices 
>> were
>> all permanently plugged."
>>
>> So according to the there can't be any changes in SINK_COUNT if the
>> downstream port is not HPD capable.
>>
>>
>>
> yes, agree on the no changes for SINK_COUNT if HPD is 0. i'll check 
> with DP Compliance test
> tomorrow and confirm the exact reason for its failure may be my 
> understanding of it was incorrect.
>
confirmed that the compliance sink is not setting HPD bit during detect. 
so this looks to be a bug in
the sink tool. i'll file a bug with their team instead.

coming back to this patch, i will get back once i understand the complex 
scenario of all short pulse
is treated as long pulse post this change, for example: we will do full 
detection even if the sink requested
retraining of link.
Ville Syrjälä July 8, 2015, 12:27 p.m. UTC | #9
On Wed, Jul 08, 2015 at 05:50:05PM +0530, Sivakumar Thulasimani wrote:
> 
> 
> On 7/7/2015 5:50 PM, Sivakumar Thulasimani wrote:
> >
> >
> > On 7/7/2015 5:24 PM, Ville Syrjälä wrote:
> >> On Tue, Jul 07, 2015 at 02:37:46PM +0300, Ville Syrjälä wrote:
> >>> On Tue, Jul 07, 2015 at 04:45:11PM +0530, Sivakumar Thulasimani wrote:
> >>>>
> >>>> On 7/7/2015 4:40 PM, Ville Syrjälä wrote:
> >>>>> On Tue, Jul 07, 2015 at 03:26:36PM +0530, Sivakumar Thulasimani 
> >>>>> wrote:
> >>>>>> On 7/6/2015 5:42 PM, ville.syrjala@linux.intel.com wrote:
> >>>>>>> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>>>>
> >>>>>>> DP dongles may signal downstream HPD via short HPD pulses. If we 
> >>>>>>> know
> >>>>>>> the device has a HPD capable downstream port, make sure we kick 
> >>>>>>> off the
> >>>>>>> full hotplug processing even for short HPDs.
> >>>>>>>
> >>>>>>> Additonally setting the sink to DPMS off kills the downstream 
> >>>>>>> HPD (at
> >>>>>>> least on my DP->VGA dongle), so skip the DPMS off for such dongles
> >>>>>>> when we turn off the port.
> >>>>>>>
> >>>>>>> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> >>>>>>> ---
> >>>>>>>     drivers/gpu/drm/i915/intel_dp.c | 18 +++++++++++++++++-
> >>>>>>>     1 file changed, 17 insertions(+), 1 deletion(-)
> >>>>>>>
> >>>>>>> diff --git a/drivers/gpu/drm/i915/intel_dp.c 
> >>>>>>> b/drivers/gpu/drm/i915/intel_dp.c
> >>>>>>> index e88cec2..f424833 100644
> >>>>>>> --- a/drivers/gpu/drm/i915/intel_dp.c
> >>>>>>> +++ b/drivers/gpu/drm/i915/intel_dp.c
> >>>>>>> @@ -2324,6 +2324,13 @@ static void intel_dp_get_config(struct 
> >>>>>>> intel_encoder *encoder,
> >>>>>>>         }
> >>>>>>>     }
> >>>>>>>     +static bool intel_dp_has_downstream_hpd(struct intel_dp 
> >>>>>>> *intel_dp)
> >>>>>>> +{
> >>>>>>> +    return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & 
> >>>>>>> DP_DWN_STRM_PORT_PRESENT &&
> >>>>>>> +        intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
> >>>>>>> +        intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
> >>>>>>> +}
> >>>>>>> +
> >>>>>>>     static void intel_disable_dp(struct intel_encoder *encoder)
> >>>>>>>     {
> >>>>>>>         struct intel_dp *intel_dp = 
> >>>>>>> enc_to_intel_dp(&encoder->base);
> >>>>>>> @@ -2340,7 +2347,9 @@ static void intel_disable_dp(struct 
> >>>>>>> intel_encoder *encoder)
> >>>>>>>          * ensure that we have vdd while we switch off the 
> >>>>>>> panel. */
> >>>>>>>         intel_edp_panel_vdd_on(intel_dp);
> >>>>>>>         intel_edp_backlight_off(intel_dp);
> >>>>>>> -    intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> >>>>>>> +    /* Skip power down to keep downstream HPD working */
> >>>>>>> +    if (!intel_dp_has_downstream_hpd(intel_dp))
> >>>>>>> +        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
> >>>>>>>         intel_edp_panel_off(intel_dp);
> >>>>>>>             /* disable the port before the pipe on g4x */
> >>>>>>> @@ -4944,6 +4953,13 @@ intel_dp_hpd_pulse(struct 
> >>>>>>> intel_digital_port *intel_dig_port, bool long_hpd)
> >>>>>>> drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
> >>>>>>>                 intel_dp_check_link_status(intel_dp);
> >>>>>>> drm_modeset_unlock(&dev->mode_config.connection_mutex);
> >>>>>>> +
> >>>>>>> +            /*
> >>>>>>> +             * Downstream HPD will generate a short HPD,
> >>>>>>> +             * so we want full hotplug processing here.
> >>>>>>> +             */
> >>>>>>> +            if (intel_dp_has_downstream_hpd(intel_dp))
> >>>>>>> +                goto put_power;
> >>>>>>>             }
> >>>>>>>         }
> >>>>>> I am looking into compliance changes for DP and this seems a 
> >>>>>> relevant
> >>>>>> change for compliance as well. but as per Link CTS 1.2 section 
> >>>>>> 4.2.2.8,
> >>>>>> we are supposed to read the sink_count and do full detection if
> >>>>>> sink_count is >1.  So instead of checking for DP_DS_PORT_HPD can 
> >>>>>> we just
> >>>>>> check SINK_COUNT and do full detect ?
> >>>>> ->detect() will be called from the hotplug work and that will
> >>>>> check SINK_COUNT.
> >>>>>
> >>>> No, the Compliance Sink tool, will not set the DP_DS_PORT_HPD 
> >>>> resulting
> >>>> in detect not getting executed for
> >>>> the short pulse generated. The spec requires the sink to set only the
> >>>> sink count so it is not a must for
> >>>> the sink to update the DP_DOWNSTREAM_PORT_0. so only a check for
> >>>> SINK_COUNT will pass the
> >>>> compliance test.
> >>> That seems stupid. If the downstream port isn't HPD capable then we 
> >>> have
> >>> no reason to check SINK_COUNT after a short HPD as the short HPD
> >>> coudln't have been caused by a downstram HPD. Obviuously we still
> >>> check SINK_COUNT after a long HPD to figure out if anything is 
> >>> connected
> >>> when the branch device itself gets connected to the source.
> >> Actually that's not correct. We don't check SINK_COUNT unless the 
> >> downstream
> >> port is HPD capable.
> >>
> >> The spec says:
> >> "If the DFP does not provide for means for plug/unplug detection, the
> >> adaptor must set the SINK_COUNT field bits, as if those Sink devices 
> >> were
> >> all permanently plugged."
> >>
> >> So according to the there can't be any changes in SINK_COUNT if the
> >> downstream port is not HPD capable.
> >>
> >>
> >>
> > yes, agree on the no changes for SINK_COUNT if HPD is 0. i'll check 
> > with DP Compliance test
> > tomorrow and confirm the exact reason for its failure may be my 
> > understanding of it was incorrect.
> >
> confirmed that the compliance sink is not setting HPD bit during detect. 
> so this looks to be a bug in
> the sink tool. i'll file a bug with their team instead.
> 
> coming back to this patch, i will get back once i understand the complex 
> scenario of all short pulse
> is treated as long pulse post this change, for example: we will do full 
> detection even if the sink requested
> retraining of link.

I suppose we should read the reason for the short HPD from some DPCD
register, assuming one exists. I've not trawled the spec for such a
thing so can't say for sure.

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index e88cec2..f424833 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -2324,6 +2324,13 @@  static void intel_dp_get_config(struct intel_encoder *encoder,
 	}
 }
 
+static bool intel_dp_has_downstream_hpd(struct intel_dp *intel_dp)
+{
+	return intel_dp->dpcd[DP_DOWNSTREAMPORT_PRESENT] & DP_DWN_STRM_PORT_PRESENT &&
+		intel_dp->dpcd[DP_DPCD_REV] >= 0x11 &&
+		intel_dp->downstream_ports[0] & DP_DS_PORT_HPD;
+}
+
 static void intel_disable_dp(struct intel_encoder *encoder)
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
@@ -2340,7 +2347,9 @@  static void intel_disable_dp(struct intel_encoder *encoder)
 	 * ensure that we have vdd while we switch off the panel. */
 	intel_edp_panel_vdd_on(intel_dp);
 	intel_edp_backlight_off(intel_dp);
-	intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
+	/* Skip power down to keep downstream HPD working */
+	if (!intel_dp_has_downstream_hpd(intel_dp))
+		intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
 	intel_edp_panel_off(intel_dp);
 
 	/* disable the port before the pipe on g4x */
@@ -4944,6 +4953,13 @@  intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 			drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
 			intel_dp_check_link_status(intel_dp);
 			drm_modeset_unlock(&dev->mode_config.connection_mutex);
+
+			/*
+			 * Downstream HPD will generate a short HPD,
+			 * so we want full hotplug processing here.
+			 */
+			if (intel_dp_has_downstream_hpd(intel_dp))
+				goto put_power;
 		}
 	}