@@ -288,6 +288,49 @@ static int intel_dp_common_rates(struct intel_dp *intel_dp,
common_rates);
}
+static int intel_dp_link_rate_index(struct intel_dp *intel_dp,
+ int *common_rates, int link_rate)
+{
+ int common_len;
+ int index;
+
+ common_len = intel_dp_common_rates(intel_dp, common_rates);
+ for (index = 0; index < common_len; index++) {
+ if (link_rate == common_rates[common_len - index - 1])
+ return common_len - index - 1;
+ }
+
+ return -1;
+}
+
+void intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+ int link_rate, uint8_t lane_count)
+{
+ int common_rates[DP_MAX_SUPPORTED_RATES] = {};
+ int common_len;
+ int link_rate_index = -1;
+
+ if (!intel_dp->link_train_failed)
+ return;
+
+ common_len = intel_dp_common_rates(intel_dp, common_rates);
+ link_rate_index = intel_dp_link_rate_index(intel_dp,
+ common_rates,
+ link_rate);
+ if (link_rate_index > 0) {
+ intel_dp->fallback_link_rate_index = link_rate_index - 1;
+ intel_dp->fallback_link_rate = common_rates[intel_dp->fallback_link_rate_index];
+ intel_dp->fallback_lane_count = intel_dp_max_lane_count(intel_dp);
+ } else if (lane_count > 1) {
+ intel_dp->fallback_link_rate_index = common_len - 1;
+ intel_dp->fallback_link_rate = common_rates[intel_dp->fallback_link_rate_index];
+ intel_dp->fallback_lane_count = lane_count >> 1;
+ } else {
+ DRM_ERROR("Link Training Unsuccessful\n");
+ intel_dp->link_train_failed = false;
+ }
+}
+
static enum drm_mode_status
intel_dp_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
@@ -897,6 +897,10 @@ struct intel_dp {
uint32_t DP;
int link_rate;
uint8_t lane_count;
+ int fallback_link_rate;
+ uint8_t fallback_lane_count;
+ int fallback_link_rate_index;
+ bool link_train_failed;
uint8_t sink_count;
bool link_mst;
bool has_audio;
@@ -1396,6 +1400,8 @@ int intel_dp_set_link_status_property(struct drm_connector *connector,
void intel_dp_set_link_params(struct intel_dp *intel_dp,
int link_rate, uint8_t lane_count,
bool link_mst);
+void intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
+ int link_rate, uint8_t lane_count);
void intel_dp_start_link_train(struct intel_dp *intel_dp);
void intel_dp_stop_link_train(struct intel_dp *intel_dp);
void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
If link training fails, then we need to fallback to lower link rate first and if link training fails at RBR, then fallback to lower lane count. This function finds the next lower link rate/lane count value after link training failure. v2: Squash the patch that returns the link rate index (Jani Nikula) Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> --- drivers/gpu/drm/i915/intel_dp.c | 43 ++++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 6 ++++++ 2 files changed, 49 insertions(+)