Synaptics VMM7100 PCONs with branch firmware 7.1 deterministically
fail 8b/10b channel equalization at the 4-lane RBR link configuration
(see the preceding commit adding DP_DPCD_QUIRK_NO_LINK_RATE_RBR).

The link config computation optimizes for the minimum link rate, so
it picks exactly this failing configuration for low resolution modes.
E.g. a 1080p60 boot greeter computes to 4x162000.
The resulting link training failure makes the fallback logic reduce
the link parameters, and since the rate is already at its minimum,
the lane count is halved to 2.
The reduced intel_dp->link.max_lane_count then sticks: these PCONs
hold HPD high and never raise the long HPD that would re-sync the
link parameters via intel_dp_reset_link_params().
On the affected system the boot greeter thus permanently capped the
link at 2 lanes, limiting the subsequent 3840x2160@60 desktop mode to
6 bpc dithered output instead of the deep color modes the setup is
capable of with 4 lanes.

Skip RBR when computing the sink rates of a device with the
NO_LINK_RATE_RBR quirk, unless RBR is the only available rate.
Any mode that fits into the RBR link bandwidth also fits into HBR at
the same lane count, so no mode support is lost.
With the quirk applied the greeter trains 2x270000 and the 4k60
desktop mode 4x810000, verified on PTL (xe) with an affected PCON.

Signed-off-by: Alexander Kaplan <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 85d3aa3b9894..dec68f07161e 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -197,7 +197,8 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp 
*intel_dp)
        static const int dp_rates[] = {
                162000, 270000, 540000, 810000
        };
-       int i, max_rate;
+       int i, num_rates = 0;
+       int max_rate;
        int max_lttpr_rate;
 
        if (drm_dp_has_quirk(&intel_dp->desc, 
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
@@ -221,7 +222,17 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp 
*intel_dp)
        for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
                if (dp_rates[i] > max_rate)
                        break;
-               intel_dp->sink_rates[i] = dp_rates[i];
+
+               /*
+                * The quirked devices fail channel equalization at RBR, but
+                * train reliably at all higher rates. Skip RBR, unless it's
+                * the only available rate.
+                */
+               if (dp_rates[i] == 162000 && max_rate >= 270000 &&
+                   drm_dp_has_quirk(&intel_dp->desc, 
DP_DPCD_QUIRK_NO_LINK_RATE_RBR))
+                       continue;
+
+               intel_dp->sink_rates[num_rates++] = dp_rates[i];
        }
 
        /*
@@ -252,14 +263,14 @@ static void intel_dp_set_dpcd_sink_rates(struct intel_dp 
*intel_dp)
                }
 
                if (uhbr_rates & DP_UHBR10)
-                       intel_dp->sink_rates[i++] = 1000000;
+                       intel_dp->sink_rates[num_rates++] = 1000000;
                if (uhbr_rates & DP_UHBR13_5)
-                       intel_dp->sink_rates[i++] = 1350000;
+                       intel_dp->sink_rates[num_rates++] = 1350000;
                if (uhbr_rates & DP_UHBR20)
-                       intel_dp->sink_rates[i++] = 2000000;
+                       intel_dp->sink_rates[num_rates++] = 2000000;
        }
 
-       intel_dp->num_sink_rates = i;
+       intel_dp->num_sink_rates = num_rates;
 }
 
 static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
-- 
2.54.0


Reply via email to