diff options
| author | Imre Deak <imre.deak@intel.com> | 2026-07-14 18:26:59 +0300 |
|---|---|---|
| committer | Imre Deak <imre.deak@intel.com> | 2026-07-20 15:47:16 +0300 |
| commit | 47fff2b1749e9ba5dfab7528960555cc865360b5 (patch) | |
| tree | c5b66f4411886639c59f57a08592bc9274e8065b /drivers/gpu | |
| parent | 0f0950ca8eb20053022ce956cc3cd112279dd7bb (diff) | |
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.
Reviewed-by: Suraj Kandpal <suraj.kandpal@intel.com>
Signed-off-by: Imre Deak <imre.deak@intel.com>
Link: https://patch.msgid.link/20260714152700.555527-6-imre.deak@intel.com
Diffstat (limited to 'drivers/gpu')
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_display_types.h | 1 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp.c | 7 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_mst.c | 5 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_tunnel.c | 45 | ||||
| -rw-r--r-- | drivers/gpu/drm/i915/display/intel_dp_tunnel.h | 17 |
5 files changed, 75 insertions, 0 deletions
diff --git a/drivers/gpu/drm/i915/display/intel_display_types.h b/drivers/gpu/drm/i915/display/intel_display_types.h index 17336ad6d5e9..b7cc361fd955 100644 --- a/drivers/gpu/drm/i915/display/intel_display_types.h +++ b/drivers/gpu/drm/i915/display/intel_display_types.h @@ -1878,6 +1878,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 61b18e056c2a..6bcaba434788 100644 --- a/drivers/gpu/drm/i915/display/intel_dp.c +++ b/drivers/gpu/drm/i915/display/intel_dp.c @@ -3590,6 +3590,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); @@ -6242,6 +6244,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; } @@ -6306,6 +6310,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 b5af01159949..3be1643f8d03 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 49fa4c9699b6..219939634564 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 8273e681a512..13fc8fbb6e30 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) { |
