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) {