> Subject: [PATCH 5/6] drm/i915/dp: Disable UHBR link configs with 1/2 lanes
> 
> Disable 1 and 2 lane link configurations on UHBR tunneled links, according to
> DP Standard v2.1b "3.5.2.16.3 128b/132b DPRX Lane Count Conversion Failure
> Indication and Corrective Action". A tunnel can indicate if it's not affected 
> by
> this limitation, check for that and skip disabling the unsupported lanes for a
> well-behaving tunnel.
> 
> The Standard in the same section also describes a workaround for 2 lanes which
> requires assisstance from the sink, where the sink indicates at the end of the
> link training sequence if the link training must be retried. This mechanism 
> also
> requires quirking out some sinks - based on the sink's DPCD OUI and EDID
> identifications - which doesn't implement this link training feedback 
> indication
> properly. This patch leaves the implementation of this workaround for a 
> follow-
> up, but prepares for it already by detecting the supported number of lane
> counts at a place where both DPCD OUI and EDID is available for the quirk
> detection.
> 

LGTM,
Reviewed-by: Suraj Kandpal <[email protected]>

> Signed-off-by: Imre Deak <[email protected]>
> ---
>  .../drm/i915/display/intel_display_types.h    |  1 +
>  drivers/gpu/drm/i915/display/intel_dp.c       |  7 +++
>  drivers/gpu/drm/i915/display/intel_dp_mst.c   |  5 +++
>  .../gpu/drm/i915/display/intel_dp_tunnel.c    | 45 +++++++++++++++++++
>  .../gpu/drm/i915/display/intel_dp_tunnel.h    | 17 +++++++
>  5 files changed, 75 insertions(+)
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h
> b/drivers/gpu/drm/i915/display/intel_display_types.h
> index c048da7d6fea7..adde53dc9dce3 100644
> --- a/drivers/gpu/drm/i915/display/intel_display_types.h
> +++ b/drivers/gpu/drm/i915/display/intel_display_types.h
> @@ -1871,6 +1871,7 @@ struct intel_dp {
> 
>       struct drm_dp_tunnel *tunnel;
>       bool tunnel_suspended:1;
> +     u8 disabled_uhbr_lane_mask;
> 
>       struct {
>               struct intel_dp_mst_encoder
> *stream_encoders[I915_MAX_PIPES]; diff --git
> a/drivers/gpu/drm/i915/display/intel_dp.c
> b/drivers/gpu/drm/i915/display/intel_dp.c
> index 0d2c696b9e4b0..e0b95fbf7db0a 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -3629,6 +3629,8 @@ void intel_dp_reset_link_params(struct intel_dp
> *intel_dp)
>        * was called.
>        */
>       intel_dp_link_caps_reset(intel_dp->link.caps);
> +     intel_dp_tunnel_uhbr_lanes_wa_apply(intel_dp);
> +
>       intel_dp->link.mst_probed_lane_count = 0;
>       intel_dp->link.mst_probed_rate = 0;
>       intel_dp_link_training_reset(intel_dp->link.training);
> @@ -6281,6 +6283,8 @@ intel_dp_detect(struct drm_connector *_connector,
> 
>               intel_dp_tunnel_disconnect(intel_dp);
> 
> +             intel_dp_tunnel_uhbr_lanes_wa_reset(intel_dp);
> +
>               goto out_unset_edid;
>       }
> 
> @@ -6345,6 +6349,9 @@ intel_dp_detect(struct drm_connector *_connector,
>       if (intel_dp_is_edp(intel_dp) || connector->detect_edid)
>               status = connector_status_connected;
> 
> +     if (intel_dp_tunnel_uhbr_lanes_wa_setup(intel_dp))
> +             intel_dp_tunnel_uhbr_lanes_wa_apply(intel_dp);
> +
>  out_unset_edid:
>       if (status != connector_status_connected && !intel_dp->is_mst)
>               intel_dp_unset_edid(intel_dp);
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> index df6e54508e5d4..7cbef16ab38b1 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_mst.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_mst.c
> @@ -1453,6 +1453,11 @@ static int mst_connector_get_ddc_modes(struct
> drm_connector *_connector)
> 
>       drm_edid_free(drm_edid);
> 
> +     if (intel_dp_tunnel_uhbr_lanes_wa_setup(intel_dp)) {
> +             intel_dp_flush_connector_commits(connector);
> +             intel_dp_tunnel_uhbr_lanes_wa_apply(intel_dp);
> +     }
> +
>       return ret;
>  }
> 
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
> b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
> index 49fa4c9699b61..2199396345646 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.c
> @@ -831,6 +831,51 @@ void intel_dp_tunnel_atomic_alloc_bw(struct
> intel_atomic_state *state)
>       atomic_increase_bw(state);
>  }
> 
> +static u8 lane_count_mask(int lane_count) {
> +     return BIT(ilog2(lane_count));
> +}
> +
> +void intel_dp_tunnel_uhbr_lanes_wa_apply(struct intel_dp *intel_dp) {
> +     struct intel_connector *connector = intel_dp->attached_connector;
> +     struct intel_dp_link_caps_order order =
> +             intel_dp_link_caps_connector_compute_order(connector);
> +     struct intel_dp_link_caps *link_caps = intel_dp->link.caps;
> +     struct intel_dp_link_config link_config;
> +     struct intel_dp_link_caps_iter iter;
> +
> +     if (!intel_dp->disabled_uhbr_lane_mask)
> +             return;
> +
> +     intel_dp_link_caps_iter_start(&iter, link_caps, order,
> INTEL_DP_LINK_CAPS_FILTER_ALL);
> +     for_each_dp_link_config(&iter, &link_config) {
> +             if (drm_dp_is_uhbr_rate(link_config.rate) &&
> +                 lane_count_mask(link_config.lane_count) & intel_dp-
> >disabled_uhbr_lane_mask)
> +                     intel_dp_link_caps_disable_config(link_caps,
> &link_config);
> +     }
> +     intel_dp_link_caps_iter_end(&iter);
> +}
> +
> +bool intel_dp_tunnel_uhbr_lanes_wa_setup(struct intel_dp *intel_dp) {
> +     u8 old_mask = intel_dp->disabled_uhbr_lane_mask;
> +
> +     if (!intel_dp_tunnel_bw_alloc_is_enabled(intel_dp) ||
> +         drm_dp_tunnel_128b132b_lane0_mapping_supported(intel_dp-
> >tunnel))
> +             intel_dp->disabled_uhbr_lane_mask = 0;
> +     else
> +             /* TODO: Add support for keeping 2 lanes enabled as well. */
> +             intel_dp->disabled_uhbr_lane_mask = lane_count_mask(1) |
> +lane_count_mask(2);
> +
> +     return intel_dp->disabled_uhbr_lane_mask != old_mask; }
> +
> +void intel_dp_tunnel_uhbr_lanes_wa_reset(struct intel_dp *intel_dp) {
> +     intel_dp->disabled_uhbr_lane_mask = 0; }
> +
>  /**
>   * intel_dp_tunnel_mgr_init - Initialize the DP tunnel manager
>   * @display: display device
> diff --git a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
> b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
> index 8273e681a5128..13fc8fbb6e306 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
> +++ b/drivers/gpu/drm/i915/display/intel_dp_tunnel.h
> @@ -54,6 +54,10 @@ int intel_dp_tunnel_atomic_check_state(struct
> intel_atomic_state *state,
> 
>  void intel_dp_tunnel_atomic_alloc_bw(struct intel_atomic_state *state);
> 
> +void intel_dp_tunnel_uhbr_lanes_wa_apply(struct intel_dp *intel_dp);
> +bool intel_dp_tunnel_uhbr_lanes_wa_setup(struct intel_dp *intel_dp);
> +void intel_dp_tunnel_uhbr_lanes_wa_reset(struct intel_dp *intel_dp);
> +
>  int intel_dp_tunnel_mgr_init(struct intel_display *display);  void
> intel_dp_tunnel_mgr_cleanup(struct intel_display *display);
> 
> @@ -129,6 +133,19 @@ intel_dp_tunnel_atomic_alloc_bw(struct
> intel_atomic_state *state)
>       return 0;
>  }
> 
> +static inline void intel_dp_tunnel_uhbr_lanes_wa_apply(struct intel_dp
> +*intel_dp) { }
> +
> +static inline bool intel_dp_tunnel_uhbr_lanes_wa_setup(struct intel_dp
> +*intel_dp) {
> +     return false;
> +}
> +
> +static inline void intel_dp_tunnel_uhbr_lanes_wa_reset(struct intel_dp
> +*intel_dp) { }
> +
>  static inline int
>  intel_dp_tunnel_mgr_init(struct intel_display *display)  {
> --
> 2.49.1

Reply via email to