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 <arun.r.murthy@xxxxxxxxx> --- 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