> 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
