Reviewed-by: Lyude Paul <ly...@redhat.com>

On Wed, 2019-09-18 at 16:26 -0400, mikita.lip...@amd.com wrote:
> From: David Francis <david.fran...@amd.com>
> 
> 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.
> 
> v2: Remember to unlock mutex on all paths
> v3: Refactor to match coding style and increase brevity
> 
> Cc: Lyude Paul <ly...@redhat.com>
> Cc: Jani Nikula <jani.nik...@linux.intel.com>
> Cc: Harry Wentland <harry.wentl...@amd.com>
> Reviewed-by: Wenjing Liu <wenjing....@amd.com>
> Signed-off-by: David Francis <david.fran...@amd.com>
> ---
>  drivers/gpu/drm/drm_dp_mst_topology.c | 127 ++++++++++++++++++++++++++
>  include/drm/drm_dp_mst_helper.h       |   2 +
>  2 files changed, 129 insertions(+)
> 
> diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c
> b/drivers/gpu/drm/drm_dp_mst_topology.c
> index ae2f986d76a2..dd2ca065cc92 100644
> --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> @@ -4147,3 +4147,130 @@ 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 || port->dpcd_rev < DP_DPCD_REV_14)
> +             return false;
> +
> +     /* Virtual DP Sink (Internal Display Panel) */
> +     if (port->port_num >= 8)
> +             return true;
> +
> +     /* DP-to-HDMI Protocol Converter */
> +     if (port->pdt == DP_PEER_DEVICE_DP_LEGACY_CONV &&
> +         !port->mcs &&
> +         port->ldps)
> +             return true;
> +
> +     /* DP-to-DP */
> +     mutex_lock(&port->mgr->lock);
> +     if (port->pdt == DP_PEER_DEVICE_MST_BRANCHING &&
> +         port->mstb &&
> +         port->mstb->num_ports == 2) {
> +             list_for_each_entry(downstream_port, &port->mstb->ports, next)
> {
> +                     if (downstream_port->pdt == DP_PEER_DEVICE_SST_SINK &&
> +                         !downstream_port->input) {
> +                             mutex_unlock(&port->mgr->lock);
> +                             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;
> +
> +     if (!port)
> +             return NULL;
> +
> +     if (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;
> +     }
> +
> +     /* 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;
> +
> +             /* Enpoint decompression with DP-to-DP peer device */
> +             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;
> +
> +     return NULL;
> +}
> +EXPORT_SYMBOL(drm_dp_mst_dsc_aux_for_port);
> 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;
>  
>  /**
-- 
Cheers,
        Lyude Paul

_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

Reply via email to