mirror of
https://github.com/torvalds/linux.git
synced 2026-09-28 03:52:02 +02:00
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
This commit is contained in:
parent
0f0950ca8e
commit
47fff2b174
|
|
@ -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];
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user