[PATCH v2 11/14] drm/amd/display: Validate DSC caps on MST endpoints

Lyude Paul lyude at redhat.com
Tue Aug 20 20:34:49 UTC 2019


Hi, I was looking through patchwork and just noticed this series. I've been
working on trying to rework a lot of the drm MST helpers (currently on hold
for a short bit while I fix some other unrelated issues at work...), and one
of the things we're currently missing with our helpers are helpers for
handling checking the PBN of downstream sinks (which could be added to
drm_dp_mst_atomic_check()). As well, it looks like you could also add a DRM
helper for checking for DSC/FEC support on mstbs. Thoughts?

On Tue, 2019-08-20 at 15:12 -0400, David Francis wrote:
> The first step in MST DSC is checking MST endpoints
> to see how DSC can be enabled
> 
> Case 1: DP-to-DP peer device
> if the branch immediately upstream has
>  - PDT = DP_PEER_DEVICE_DP_MST_BRANCHING (2)
>  - DPCD rev. >= DP 1.4
>  - Exactly one input and one output
>  - The output has PDT = DP_PEER_DEVICE_SST_SINK (3)
> 
> In this case, DSC could be possible either on the endpoint
> or the peer device. Prefer the endpoint, which is possible if
>  - The endpoint has DP_DSC_DECOMPRESSION_IS_SUPPORTED bit set
>  - The endpoint has DP_FEC_CAPABLE bit set
>  - The peer device has DSC_PASSTHROUGH_CAPABILITY bit set (from DP v2.0)
> 
> Otherwise, use the peer device
> 
> Case 2: DP-to-HDMI peer device
> If the output port has
>  - PDT = DP_PEER_DEVICE_DP_LEGACY_CONV (4)
>  - DPCD rev. >= DP 1.4
>  - LDPS = true
>  - MCS = false
> 
> In this case, DSC can only be attempted on the peer device
> (the output port)
> 
> Case 3: Virtual DP Sink (Internal Display Panel)
> If the output port has
>  - DPCD rev. >= DP 1.4
>  - port_num >= 8
> 
> In this case, DSC can only be attempted on the peer device
> (the output port)
> 
> Case 4: Synaptix Workaround
> If the output has
>  - link DPCD rev. >= DP 1.4
>  - link branch_dev_id = 0x90CC24 (Synaptix)
>  - There is exactly one branch device between the link and output
> 
> In this case, DSC can be attempted, but only using the *link*
> aux device's caps. This is a quirk.
> 
> Test for these cases as modes are enumerated for an MST endpoint.
> We cannot do this during link attach because the dc_sink object
> will not have been created yet
> 
> If no DSC is attempted, zero the DSC caps
> 
> Cc: Wenjing Liu <Wenjing.Liu at amd.com>
> Cc: Nikola Cornij <Nikola.Cornij at amd.com>
> Signed-off-by: David Francis <David.Francis at amd.com>
> ---
>  .../display/amdgpu_dm/amdgpu_dm_mst_types.c   | 123 +++++++++++++++++-
>  .../display/amdgpu_dm/amdgpu_dm_mst_types.h   |   3 +
>  2 files changed, 125 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> index 16218a202b59..58571844f6d5 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
> @@ -25,6 +25,7 @@
>  
>  #include <linux/version.h>
>  #include <drm/drm_atomic_helper.h>
> +#include <drm/drm_dp_mst_helper.h>
>  #include "dm_services.h"
>  #include "amdgpu.h"
>  #include "amdgpu_dm.h"
> @@ -189,6 +190,120 @@ static const struct drm_connector_funcs
> dm_dp_mst_connector_funcs = {
>  	.early_unregister = amdgpu_dm_mst_connector_early_unregister,
>  };
>  
> +bool is_virtual_dpcd(struct drm_dp_mst_port *port)
> +{
> +	struct drm_dp_mst_port *downstream_port;
> +
> +	if (!port)
> +		return false;
> +
> +	if (port->port_num >= 8 &&
> +		port->dpcd_rev >= DP_DPCD_REV_14) {
> +		/* Virtual DP Sink (Internal Display Panel) */
> +		return true;
> +	} else if (port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV &&
> +			!port->mcs &&
> +			port->ldps &&
> +			port->dpcd_rev >= DP_DPCD_REV_14) {
> +		/* DP-to-HDMI Protocol Converter */
> +		return true;
> +	} else if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
> +			port->mstb &&
> +			port->dpcd_rev >= DP_DPCD_REV_14) {
> +		/* DP-to-DP */
> +		if (port->mstb->num_ports == 2) {
> +			list_for_each_entry(downstream_port, &port->mstb-
> >ports, next) {
> +				if (!downstream_port->input &&
> +						downstream_port->pdt ==
> DP_PEER_DEVICE_SST_SINK)
> +					return true;
> +			}
> +		}
> +	}
> +	return false;
> +}
> +
> +bool synaptix_workaround(struct amdgpu_dm_connector *aconnector)
> +{
> +	struct drm_dp_mst_port *port = aconnector->port;
> +	struct dc_link *link = aconnector->dc_sink->link;
> +	u8 down_stream_port_data;
> +
> +	if (port->mgr->mst_primary == port->parent &&
> +			link->dpcd_caps.branch_dev_id == 0x90CC24 &&
> +			link->dpcd_caps.dpcd_rev.raw >= DP_DPCD_REV_14) {
> +		drm_dp_mst_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT,
> &down_stream_port_data, 1);
> +		if ((down_stream_port_data & 7) != 3)
> +			return true;
> +	}
> +	return false;
> +}
> +
> +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
> +static bool validate_dsc_caps_on_connector(struct amdgpu_dm_connector
> *aconnector)
> +{
> +	u8 upstream_dsc_caps[16] = { 0 };
> +	u8 endpoint_dsc_caps[16] = { 0 };
> +	u8 endpoint_fec_caps = 0;
> +	struct dc_sink *dc_sink = aconnector->dc_sink;
> +	struct drm_dp_mst_port *output_port = aconnector->port;
> +	struct drm_dp_mst_port *immediate_upstream_port;
> +	struct drm_dp_mst_port *fec_port;
> +
> +	if (aconnector->port && aconnector->port->parent)
> +		immediate_upstream_port = aconnector->port->parent-
> >port_parent;
> +	else
> +		immediate_upstream_port = NULL;
> +
> +	fec_port = immediate_upstream_port;
> +	while (fec_port) {
> +		if (!fec_port->fec_capable)
> +			return false;
> +
> +		fec_port = fec_port->parent->port_parent;
> +	}
> +
> +	if (immediate_upstream_port)
> +		drm_dp_mst_dpcd_read(&immediate_upstream_port->aux,
> DP_DSC_SUPPORT, upstream_dsc_caps, 16);
> +	drm_dp_mst_dpcd_read(&output_port->aux, DP_DSC_SUPPORT,
> endpoint_dsc_caps, 16);
> +	drm_dp_mst_dpcd_read(&output_port->aux, DP_FEC_CAPABILITY,
> &endpoint_fec_caps, 1);
> +
> +	if (is_virtual_dpcd(immediate_upstream_port)
> +			&& (upstream_dsc_caps[0] & 0x2) /* DSC passthrough
> capability */
> +			&& (endpoint_fec_caps & DP_FEC_CAPABLE)
> +			&& (endpoint_dsc_caps[0] &
> DP_DSC_DECOMPRESSION_IS_SUPPORTED)) {
> +		/* Enpoint decompression with DP-to-DP peer device */
> +		if (!dc_dsc_parse_dsc_dpcd(endpoint_dsc_caps, NULL, &dc_sink-
> >sink_dsc_caps.dsc_dec_caps))
> +			return false;
> +
> +		dc_sink->sink_dsc_caps.is_virtual_dpcd_dsc = false;
> +	} else if (is_virtual_dpcd(immediate_upstream_port)) {
> +		/* Virtual DPCD decompression with DP-to-DP peer device */
> +		if (!dc_dsc_parse_dsc_dpcd(upstream_dsc_caps, NULL, &dc_sink-
> >sink_dsc_caps.dsc_dec_caps))
> +			return false;
> +
> +		dc_sink->sink_dsc_caps.is_virtual_dpcd_dsc = true;
> +	} else if (is_virtual_dpcd(output_port)) {
> +		/* Virtual DPCD decompression with DP-to-HDMI or Virtual DP
> Sink */
> +		if (!dc_dsc_parse_dsc_dpcd(endpoint_dsc_caps, NULL, &dc_sink-
> >sink_dsc_caps.dsc_dec_caps))
> +			return false;
> +
> +		dc_sink->sink_dsc_caps.is_virtual_dpcd_dsc = true;
> +	} else if (synaptix_workaround(aconnector)) {
> +		/* Synaptix workaround */
> +		aconnector = dc_sink->link->priv;
> +		drm_dp_dpcd_read(&aconnector->dm_dp_aux.aux, DP_DSC_SUPPORT,
> upstream_dsc_caps, 16);
> +		if (!dc_dsc_parse_dsc_dpcd(upstream_dsc_caps, NULL, &dc_sink-
> >sink_dsc_caps.dsc_dec_caps))
> +			return false;
> +
> +		dc_sink->sink_dsc_caps.is_virtual_dpcd_dsc = true;
> +	} else {
> +		return false;
> +	}
> +
> +	return true;
> +}
> +#endif
> +
>  static int dm_dp_mst_get_modes(struct drm_connector *connector)
>  {
>  	struct amdgpu_dm_connector *aconnector =
> to_amdgpu_dm_connector(connector);
> @@ -231,10 +346,16 @@ static int dm_dp_mst_get_modes(struct drm_connector
> *connector)
>  		/* dc_link_add_remote_sink returns a new reference */
>  		aconnector->dc_sink = dc_sink;
>  
> -		if (aconnector->dc_sink)
> +		if (aconnector->dc_sink) {
>  			amdgpu_dm_update_freesync_caps(
>  					connector, aconnector->edid);
>  
> +#ifdef CONFIG_DRM_AMD_DC_DSC_SUPPORT
> +			if (!validate_dsc_caps_on_connector(aconnector))
> +				memset(&aconnector->dc_sink->sink_dsc_caps,
> +				       0, sizeof(aconnector->dc_sink-
> >sink_dsc_caps));
> +#endif
> +		}
>  	}
>  
>  	drm_connector_update_edid_property(
> diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
> b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
> index 2da851b40042..8de3d8c30f8d 100644
> --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
> +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.h
> @@ -32,4 +32,7 @@ struct amdgpu_dm_connector;
>  void amdgpu_dm_initialize_dp_connector(struct amdgpu_display_manager *dm,
>  				       struct amdgpu_dm_connector
> *aconnector);
>  
> +bool is_virtual_dpcd(struct drm_dp_mst_port *port);
> +bool synaptix_workaround(struct amdgpu_dm_connector *aconnector);
> +
>  #endif
-- 
Cheers,
	Lyude Paul



More information about the amd-gfx mailing list