[PATCH v5 5/5] drm/dp_mst: Add helper for finding right aux to enable/query DSC

Jani Nikula jani.nikula at linux.intel.com
Mon Aug 26 12:47:34 UTC 2019


On Fri, 23 Aug 2019, David Francis <David.Francis at amd.com> wrote:
> Add drm_dp_mst_dsc_aux_for_port. To enable DSC, the DSC_ENABLED
> register might have to be written on the leaf port's DPCD,
> its parent's DPCD, or the MST manager's DPCD. This function
> finds the correct aux for the job.
>
> As part of this, add drm_dp_mst_is_virtual_dpcd. Virtual DPCD
> is a DP feature new in DP v1.4, which exposes certain DPCD
> registers on virtual ports.
>
> ALso add a new quirk for Synatics MST hubs that support DSC
> despite not supporting virtual DPCD.

"Also" in the commit message often means, "should be a separate
patch". I think this is true here.

BR,
Jani.


>
> Cc: Lyude Paul <lyude at redhat.com>
> 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>
> ---
>  drivers/gpu/drm/drm_dp_helper.c       |   2 +
>  drivers/gpu/drm/drm_dp_mst_topology.c | 147 ++++++++++++++++++++++++++
>  include/drm/drm_dp_helper.h           |   7 ++
>  include/drm/drm_dp_mst_helper.h       |   2 +
>  4 files changed, 158 insertions(+)
>
> diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
> index 2cc21eff4cf3..fc39323e7d52 100644
> --- a/drivers/gpu/drm/drm_dp_helper.c
> +++ b/drivers/gpu/drm/drm_dp_helper.c
> @@ -1270,6 +1270,8 @@ static const struct dpcd_quirk dpcd_quirk_list[] = {
>  	{ OUI(0x00, 0x10, 0xfa), DEVICE_ID_ANY, false, BIT(DP_DPCD_QUIRK_NO_PSR) },
>  	/* CH7511 seems to leave SINK_COUNT zeroed */
>  	{ OUI(0x00, 0x00, 0x00), DEVICE_ID('C', 'H', '7', '5', '1', '1'), false, BIT(DP_DPCD_QUIRK_NO_SINK_COUNT) },
> +	/* Synaptics DP1.4 MST hubs can support DSC without virtual DPCD */
> +	{ OUI(0x90, 0xCC, 0x24), DEVICE_ID_ANY, true, BIT(DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD) },
>  };
>  
>  #undef OUI
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
> index a39e42c7d868..559bc09b6b94 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -4150,3 +4150,150 @@ static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_aux *aux)
>  {
>  	i2c_del_adapter(&aux->ddc);
>  }
> +
> +/**
> + * drm_dp_mst_is_virtual_dpcd() - Is the given port a virtual DP Peer Device
> + * @port: The port to check
> + *
> + * A single physical MST hub object can be represented in the topology
> + * by multiple branches, with virtual ports between those branches.
> + *
> + * As of DP1.4, An MST hub with internal (virtual) ports must expose
> + * certain DPCD registers over those ports. See sections 2.6.1.1.1
> + * and 2.6.1.1.2 of Display Port specification v1.4 for details.
> + *
> + * May acquire mgr->lock
> + *
> + * Returns:
> + * true if the port is a virtual DP peer device, false otherwise
> + */
> +static bool drm_dp_mst_is_virtual_dpcd(struct drm_dp_mst_port *port)
> +{
> +	struct drm_dp_mst_port *downstream_port;
> +
> +	if (!port)
> +		return false;
> +
> +	/* Virtual DP Sink (Internal Display Panel) */
> +	if (port->port_num >= 8 && port->dpcd_rev >= DP_DPCD_REV_14)
> +		return true;
> +
> +	/* DP-to-HDMI Protocol Converter */
> +	if (port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV &&
> +			!port->mcs &&
> +			port->ldps &&
> +			port->dpcd_rev >= DP_DPCD_REV_14)
> +		return true;
> +
> +	/* DP-to-DP */
> +	mutex_lock(&port->mgr->lock);
> +	if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
> +			port->mstb &&
> +			port->dpcd_rev >= DP_DPCD_REV_14 &&
> +			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;
> +		}
> +	}
> +	mutex_unlock(&port->mgr->lock);
> +
> +	return false;
> +}
> +
> +/**
> + * drm_dp_mst_dsc_aux_for_port() - Find the correct aux for DSC
> + * @port: The port to check. A leaf of the MST tree with an attached display.
> + *
> + * Depending on the situation, DSC may be enabled via the endpoint aux,
> + * the immediately upstream aux, or the connector's physical aux.
> + *
> + * This is both the correct aux to read DSC_CAPABILITY and the
> + * correct aux to write DSC_ENABLED.
> + *
> + * This operation can be expensive (up to four aux reads), so
> + * the caller should cache the return.
> + *
> + * Returns:
> + * NULL if DSC cannot be enabled on this port, otherwise the aux device
> + */
> +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port)
> +{
> +	struct drm_dp_mst_port *immediate_upstream_port;
> +	struct drm_dp_mst_port *fec_port;
> +	struct drm_dp_desc *desc;
> +
> +	if (port && port->parent)
> +		immediate_upstream_port = port->parent->port_parent;
> +	else
> +		immediate_upstream_port = NULL;
> +
> +	fec_port = immediate_upstream_port;
> +	while (fec_port) {
> +		/*
> +		 * Each physical link (i.e. not a virtual port) between the
> +		 * output and the primary device must support FEC
> +		 */
> +		if (!drm_dp_mst_is_virtual_dpcd(fec_port) &&
> +				!fec_port->fec_capable)
> +			return NULL;
> +
> +		fec_port = fec_port->parent->port_parent;
> +	}
> +
> +	/* Enpoint decompression with DP-to-DP peer device */
> +	if (drm_dp_mst_is_virtual_dpcd(immediate_upstream_port)) {
> +		u8 upstream_dsc;
> +		u8 endpoint_dsc;
> +		u8 endpoint_fec;
> +
> +		if (drm_dp_dpcd_read(&port->aux,
> +				     DP_DSC_SUPPORT, &endpoint_dsc, 1) < 0)
> +			return NULL;
> +		if (drm_dp_dpcd_read(&port->aux,
> +				     DP_FEC_CAPABILITY, &endpoint_fec, 1) < 0)
> +			return NULL;
> +		if (drm_dp_dpcd_read(&immediate_upstream_port->aux,
> +				     DP_DSC_SUPPORT, &upstream_dsc, 1) < 0)
> +			return NULL;
> +
> +		if ((endpoint_dsc & DP_DSC_DECOMPRESSION_IS_SUPPORTED)
> +				&& (endpoint_fec & DP_FEC_CAPABLE)
> +				&& (upstream_dsc & 0x2) /* DSC passthrough */)
> +			return &port->aux;
> +
> +		/* Virtual DPCD decompression with DP-to-DP peer device */
> +		return &immediate_upstream_port->aux;
> +	}
> +
> +	/* Virtual DPCD decompression with DP-to-HDMI or Virtual DP Sink */
> +	if (drm_dp_mst_is_virtual_dpcd(port))
> +		return &port->aux;
> +
> +	/*
> +	 * Synaptics quirk
> +	 * Applies to ports for which:
> +	 * - Physical aux has Synaptics OUI
> +	 * - DPv1.4 or higher
> +	 * - Port is on primary branch device
> +	 * - Not a VGA adapter (DP_DWN_STRM_PORT_TYPE_ANALOG)
> +	 */
> +	drm_dp_read_desc(port->mgr->aux, desc, true);
> +	if (drm_dp_has_quirk(desc, DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD &&
> +			port->mgr->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14) &&
> +			port->parent == port->mgr->mst_primary) {
> +		u8 downstreamport;
> +
> +		drm_dp_dpcd_read(&port->aux, DP_DOWNSTREAMPORT_PRESENT,
> +				 &downstreamport, 1);
> +
> +		if ((downstreamport & DP_DWN_STRM_PORT_PRESENT) &&
> +				(downstreamport & DP_DWN_STRM_PORT_TYPE_MASK
> +				!= DP_DWN_STRM_PORT_TYPE_ANALOG))
> +			return port->mgr->aux;
> +	}
> +
> +	return NULL;
> +}
> +EXPORT_SYMBOL(drm_dp_mst_dsc_aux_for_port);
> diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> index 8364502f92cf..a1331b08705f 100644
> --- a/include/drm/drm_dp_helper.h
> +++ b/include/drm/drm_dp_helper.h
> @@ -1434,6 +1434,13 @@ enum drm_dp_quirk {
>  	 * The driver should ignore SINK_COUNT during detection.
>  	 */
>  	DP_DPCD_QUIRK_NO_SINK_COUNT,
> +	/**
> +	 * @DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD:
> +	 *
> +	 * The device supports MST DSC despite not supporting Virtual DPCD.
> +	 * The DSC caps can be read from the physical aux instead.
> +	 */
> +	DP_DPCD_QUIRK_DSC_WITHOUT_VIRTUAL_DPCD,
>  };
>  
>  /**
> diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
> index f113ae04fa88..4cf738545dfb 100644
> --- a/include/drm/drm_dp_mst_helper.h
> +++ b/include/drm/drm_dp_mst_helper.h
> @@ -673,6 +673,8 @@ int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state);
>  void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port);
>  void drm_dp_mst_put_port_malloc(struct drm_dp_mst_port *port);
>  
> +struct drm_dp_aux *drm_dp_mst_dsc_aux_for_port(struct drm_dp_mst_port *port);
> +
>  extern const struct drm_private_state_funcs drm_dp_mst_topology_state_funcs;
>  
>  /**

-- 
Jani Nikula, Intel Open Source Graphics Center


More information about the dri-devel mailing list