Fallback mandates on DP link training failure. This patch just covers
the DP2.0 fallback sequence.

TODO: Need to implement the DP1.4 fallback.

Signed-off-by: Arun R Murthy <[email protected]>
---
 drivers/gpu/drm/i915/display/intel_dp.c | 92 ++++++++++++++++++++++---
 1 file changed, 82 insertions(+), 10 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_dp.c 
b/drivers/gpu/drm/i915/display/intel_dp.c
index 10ec231acd98..82d354a6b0cd 100644
--- a/drivers/gpu/drm/i915/display/intel_dp.c
+++ b/drivers/gpu/drm/i915/display/intel_dp.c
@@ -104,6 +104,50 @@ static const u8 valid_dsc_bpp[] = {6, 8, 10, 12, 15};
  */
 static const u8 valid_dsc_slicecount[] = {1, 2, 4};
 
+/* DL Link Rates */
+#define UHBR20         2000000
+#define UHBR13P5       1350000
+#define UHBR10         1000000
+#define HBR3           810000
+#define HBR2           540000
+#define HBR            270000
+#define RBR            162000
+
+/* DP Lane Count */
+#define LANE_COUNT_4   4
+#define LANE_COUNT_2   2
+#define LANE_COUNT_1   1
+
+/* DP2.0 fallback values */
+struct dp_fallback {
+       u32 link_rate;
+       u8 lane_count;
+};
+
+struct dp_fallback dp2dot0_fallback[] = {
+       {UHBR20, LANE_COUNT_4},
+       {UHBR13P5, LANE_COUNT_4},
+       {UHBR20, LANE_COUNT_2},
+       {UHBR10, LANE_COUNT_4},
+       {UHBR13P5, LANE_COUNT_2},
+       {HBR3, LANE_COUNT_4},
+       {UHBR20, LANE_COUNT_1},
+       {UHBR10, LANE_COUNT_2},
+       {HBR2, LANE_COUNT_4},
+       {UHBR13P5, LANE_COUNT_1},
+       {HBR3, LANE_COUNT_2},
+       {UHBR10, LANE_COUNT_1},
+       {HBR2, LANE_COUNT_2},
+       {HBR, LANE_COUNT_4},
+       {HBR3, LANE_COUNT_1},
+       {RBR, LANE_COUNT_4},
+       {HBR2, LANE_COUNT_1},
+       {HBR, LANE_COUNT_2},
+       {RBR, LANE_COUNT_2},
+       {HBR, LANE_COUNT_1},
+       {RBR, LANE_COUNT_1},
+};
+
 /**
  * intel_dp_is_edp - is the given port attached to an eDP panel (either CPU or 
PCH)
  * @intel_dp: DP struct
@@ -299,6 +343,19 @@ static int intel_dp_common_len_rate_limit(const struct 
intel_dp *intel_dp,
                                       intel_dp->num_common_rates, max_rate);
 }
 
+static bool intel_dp_link_rate_supported(struct intel_dp *intel_dp, u32 
link_rate)
+{
+       u8 i;
+
+       for (i = 0; i < ARRAY_SIZE(intel_dp->common_rates); i++) {
+               if (intel_dp->common_rates[i] == link_rate)
+                       return true;
+               else
+                       continue;
+       }
+       return false;
+}
+
 static int intel_dp_common_rate(struct intel_dp *intel_dp, int index)
 {
        if (drm_WARN_ON(&dp_to_i915(intel_dp)->drm,
@@ -671,15 +728,6 @@ int intel_dp_get_link_train_fallback_values(struct 
intel_dp *intel_dp,
        struct drm_i915_private *i915 = dp_to_i915(intel_dp);
        int index;
 
-       /*
-        * TODO: Enable fallback on MST links once MST link compute can handle
-        * the fallback params.
-        */
-       if (intel_dp->is_mst) {
-               drm_err(&i915->drm, "Link Training Unsuccessful\n");
-               return -1;
-       }
-
        if (intel_dp_is_edp(intel_dp) && !intel_dp->use_max_params) {
                drm_dbg_kms(&i915->drm,
                            "Retrying Link training for eDP with max 
parameters\n");
@@ -687,6 +735,31 @@ int intel_dp_get_link_train_fallback_values(struct 
intel_dp *intel_dp,
                return 0;
        }
 
+       /* DP fallback values */
+       if (intel_dp->dpcd[DP_MAIN_LINK_CHANNEL_CODING] & DP_CAP_ANSI_128B132B) 
{
+               for(index = 0; index < ARRAY_SIZE(dp2dot0_fallback); index++) {
+                       if (link_rate == dp2dot0_fallback[index].link_rate &&
+                               lane_count == 
dp2dot0_fallback[index].lane_count) {
+                               for(index += 1; index < 
ARRAY_SIZE(dp2dot0_fallback); index++) {
+                                       if 
(intel_dp_link_rate_supported(intel_dp,
+                                                       
dp2dot0_fallback[index].link_rate)) {
+                                               
intel_dp_set_link_params(intel_dp,
+                                                                     
dp2dot0_fallback[index].link_rate,
+                                                                     
dp2dot0_fallback[index].lane_count);
+                                               drm_dbg_kms(&i915->drm,
+                                                           "Retrying Link 
training with link rate %d and lane count %d\n",
+                                                           
dp2dot0_fallback[index].link_rate,
+                                                           
dp2dot0_fallback[index].lane_count);
+                                               return 0;
+                                       }
+                               }
+                       }
+               }
+               /* Report failure and fail link training */
+               drm_err(&i915->drm, "Link Training Unsuccessful\n");
+               return -1;
+       }
+
        index = intel_dp_rate_index(intel_dp->common_rates,
                                    intel_dp->num_common_rates,
                                    link_rate);
@@ -716,7 +789,6 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp 
*intel_dp,
                drm_err(&i915->drm, "Link Training Unsuccessful\n");
                return -1;
        }
-
        return 0;
 }
 
-- 
2.25.1

Reply via email to