OpenCloudOS-Kernel/drivers/gpu/drm/i915/intel_dp_link_training.c

389 lines
11 KiB
C
Raw Normal View History

/*
* Copyright © 2008-2015 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice (including the next
* paragraph) shall be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "intel_drv.h"
static void
intel_dp_dump_link_status(const uint8_t link_status[DP_LINK_STATUS_SIZE])
{
DRM_DEBUG_KMS("ln0_1:0x%x ln2_3:0x%x align:0x%x sink:0x%x adj_req0_1:0x%x adj_req2_3:0x%x",
link_status[0], link_status[1], link_status[2],
link_status[3], link_status[4], link_status[5]);
}
static void
intel_get_adjust_train(struct intel_dp *intel_dp,
const uint8_t link_status[DP_LINK_STATUS_SIZE])
{
uint8_t v = 0;
uint8_t p = 0;
int lane;
uint8_t voltage_max;
uint8_t preemph_max;
for (lane = 0; lane < intel_dp->lane_count; lane++) {
uint8_t this_v = drm_dp_get_adjust_request_voltage(link_status, lane);
uint8_t this_p = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
if (this_v > v)
v = this_v;
if (this_p > p)
p = this_p;
}
voltage_max = intel_dp_voltage_max(intel_dp);
if (v >= voltage_max)
v = voltage_max | DP_TRAIN_MAX_SWING_REACHED;
preemph_max = intel_dp_pre_emphasis_max(intel_dp, v);
if (p >= preemph_max)
p = preemph_max | DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
for (lane = 0; lane < 4; lane++)
intel_dp->train_set[lane] = v | p;
}
static bool
intel_dp_set_link_train(struct intel_dp *intel_dp,
uint8_t dp_train_pat)
{
uint8_t buf[sizeof(intel_dp->train_set) + 1];
int ret, len;
intel_dp_program_link_training_pattern(intel_dp, dp_train_pat);
buf[0] = dp_train_pat;
if ((dp_train_pat & DP_TRAINING_PATTERN_MASK) ==
DP_TRAINING_PATTERN_DISABLE) {
/* don't write DP_TRAINING_LANEx_SET on disable */
len = 1;
} else {
/* DP_TRAINING_LANEx_SET follow DP_TRAINING_PATTERN_SET */
memcpy(buf + 1, intel_dp->train_set, intel_dp->lane_count);
len = intel_dp->lane_count + 1;
}
ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_PATTERN_SET,
buf, len);
return ret == len;
}
static bool
intel_dp_reset_link_train(struct intel_dp *intel_dp,
uint8_t dp_train_pat)
{
memset(intel_dp->train_set, 0, sizeof(intel_dp->train_set));
intel_dp_set_signal_levels(intel_dp);
return intel_dp_set_link_train(intel_dp, dp_train_pat);
}
static bool
intel_dp_update_link_train(struct intel_dp *intel_dp)
{
int ret;
intel_dp_set_signal_levels(intel_dp);
ret = drm_dp_dpcd_write(&intel_dp->aux, DP_TRAINING_LANE0_SET,
intel_dp->train_set, intel_dp->lane_count);
return ret == intel_dp->lane_count;
}
static bool intel_dp_link_max_vswing_reached(struct intel_dp *intel_dp)
{
int lane;
for (lane = 0; lane < intel_dp->lane_count; lane++)
if ((intel_dp->train_set[lane] &
DP_TRAIN_MAX_SWING_REACHED) == 0)
return false;
return true;
}
/* Enable corresponding port and start training pattern 1 */
static bool
intel_dp_link_training_clock_recovery(struct intel_dp *intel_dp)
{
uint8_t voltage;
int voltage_tries, cr_tries, max_cr_tries;
bool max_vswing_reached = false;
uint8_t link_config[2];
uint8_t link_bw, rate_select;
if (intel_dp->prepare_link_retrain)
intel_dp->prepare_link_retrain(intel_dp);
intel_dp_compute_rate(intel_dp, intel_dp->link_rate,
&link_bw, &rate_select);
if (link_bw)
DRM_DEBUG_KMS("Using LINK_BW_SET value %02x\n", link_bw);
else
DRM_DEBUG_KMS("Using LINK_RATE_SET value %02x\n", rate_select);
/* Write the link configuration data */
link_config[0] = link_bw;
link_config[1] = intel_dp->lane_count;
if (drm_dp_enhanced_frame_cap(intel_dp->dpcd))
link_config[1] |= DP_LANE_COUNT_ENHANCED_FRAME_EN;
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_BW_SET, link_config, 2);
drm/i915/dp: generate and cache sink rate array for all DP, not just eDP 1.4 There is some conflation related to sink rates, making this change more complicated than it would otherwise have to be. There are three changes here that are rather difficult to split up: 1) Use the intel_dp->sink_rates array for all DP, not just eDP 1.4. We initialize it from DPCD on eDP 1.4 like before, but generate it based on DP_MAX_LINK_RATE on others. This reduces code complexity when we need to use the sink rates; they are all always in the sink_rates array. 2) Update the sink rate array whenever we read DPCD, and use the information from there. This increases code readability when we need the sink rates. 3) Disentangle fallback rate limiting from sink rates. In the code, the max rate is a dynamic property of the *link*, not of the *sink*. Do the limiting after intersecting the source and sink rates, which are static properties of the devices. This paves the way for follow-up refactoring that I've refrained from doing here to keep this change as simple as it possibly can. v2: introduce use_rate_select and handle non-confirming eDP (Ville) v3: don't clobber cached eDP rates on short pulse (Ville) Cc: Manasi Navare <manasi.d.navare@intel.com> Cc: Ville Syrjälä <ville.syrjala@linux.intel.com> Reviewed-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/071bad76467f8ab2e73f3f61ad52d5a468004c71.1490712890.git.jani.nikula@intel.com
2017-03-28 22:59:05 +08:00
/* eDP 1.4 rate select method. */
if (!link_bw)
drm_dp_dpcd_write(&intel_dp->aux, DP_LINK_RATE_SET,
&rate_select, 1);
link_config[0] = 0;
link_config[1] = DP_SET_ANSI_8B10B;
drm_dp_dpcd_write(&intel_dp->aux, DP_DOWNSPREAD_CTRL, link_config, 2);
intel_dp->DP |= DP_PORT_EN;
/* clock recovery */
if (!intel_dp_reset_link_train(intel_dp,
DP_TRAINING_PATTERN_1 |
DP_LINK_SCRAMBLING_DISABLE)) {
DRM_ERROR("failed to enable link training\n");
return false;
}
drm/i915/dp: Limit link training clock recovery loop Limit the link training clock recovery loop to 10 attempts at LANEx_CR_DONE per DP 1.4 spec section 3.5.1.2.2 and 80 attempts for pre-DP 1.4 (4 voltage levels x 4 preemphasis levels x x 5 identical voltages tries). Some faulty USB-C MST hubs can cause us to get stuck in this loop indefinitely requesting something like: voltage swing: 0, pre-emphasis level: 2 voltage swing: 1, pre-emphasis level: 2 voltage swing: 0, pre-emphasis level: 3 over and over so max_vswing would never be reached, drm_dp_clock_recovery_ok() would never return true and voltage_tries would always get reset to 1. The driver sends those values to the hub but the hub keeps requesting new values every time. Changes in v2: - updated commit message (DK, Manasi) - defined DP_DP14_MAX_CR_TRIES (Marc) - made the loop iterate for max 10 times (Rodrigo, Marc) Changes in v3: - changed error message to use DP_DP14_MAX_CR_TRIES Changes in v4: - Updated the title to reflect the change - Updated the commit message - Added 80 attempts for pre-DP 1.4 devices Changes in v5: - Removed DP_DP14_MAX_CR_TRIES from drm v6: Updated comment to match kernel style (Rodrigo) Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Marc Herbert <marc.herbert@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Nathan Ciobanu <nathan.d.ciobanu@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180720214413.29506-1-rodrigo.vivi@intel.com
2018-07-21 05:44:12 +08:00
/*
* The DP 1.4 spec defines the max clock recovery retries value
* as 10 but for pre-DP 1.4 devices we set a very tolerant
* retry limit of 80 (4 voltage levels x 4 preemphasis levels x
* x 5 identical voltage retries). Since the previous specs didn't
* define a limit and created the possibility of an infinite loop
* we want to prevent any sync from triggering that corner case.
drm/i915/dp: Limit link training clock recovery loop Limit the link training clock recovery loop to 10 attempts at LANEx_CR_DONE per DP 1.4 spec section 3.5.1.2.2 and 80 attempts for pre-DP 1.4 (4 voltage levels x 4 preemphasis levels x x 5 identical voltages tries). Some faulty USB-C MST hubs can cause us to get stuck in this loop indefinitely requesting something like: voltage swing: 0, pre-emphasis level: 2 voltage swing: 1, pre-emphasis level: 2 voltage swing: 0, pre-emphasis level: 3 over and over so max_vswing would never be reached, drm_dp_clock_recovery_ok() would never return true and voltage_tries would always get reset to 1. The driver sends those values to the hub but the hub keeps requesting new values every time. Changes in v2: - updated commit message (DK, Manasi) - defined DP_DP14_MAX_CR_TRIES (Marc) - made the loop iterate for max 10 times (Rodrigo, Marc) Changes in v3: - changed error message to use DP_DP14_MAX_CR_TRIES Changes in v4: - Updated the title to reflect the change - Updated the commit message - Added 80 attempts for pre-DP 1.4 devices Changes in v5: - Removed DP_DP14_MAX_CR_TRIES from drm v6: Updated comment to match kernel style (Rodrigo) Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Marc Herbert <marc.herbert@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Nathan Ciobanu <nathan.d.ciobanu@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180720214413.29506-1-rodrigo.vivi@intel.com
2018-07-21 05:44:12 +08:00
*/
if (intel_dp->dpcd[DP_DPCD_REV] >= DP_DPCD_REV_14)
max_cr_tries = 10;
else
max_cr_tries = 80;
voltage_tries = 1;
drm/i915/dp: Limit link training clock recovery loop Limit the link training clock recovery loop to 10 attempts at LANEx_CR_DONE per DP 1.4 spec section 3.5.1.2.2 and 80 attempts for pre-DP 1.4 (4 voltage levels x 4 preemphasis levels x x 5 identical voltages tries). Some faulty USB-C MST hubs can cause us to get stuck in this loop indefinitely requesting something like: voltage swing: 0, pre-emphasis level: 2 voltage swing: 1, pre-emphasis level: 2 voltage swing: 0, pre-emphasis level: 3 over and over so max_vswing would never be reached, drm_dp_clock_recovery_ok() would never return true and voltage_tries would always get reset to 1. The driver sends those values to the hub but the hub keeps requesting new values every time. Changes in v2: - updated commit message (DK, Manasi) - defined DP_DP14_MAX_CR_TRIES (Marc) - made the loop iterate for max 10 times (Rodrigo, Marc) Changes in v3: - changed error message to use DP_DP14_MAX_CR_TRIES Changes in v4: - Updated the title to reflect the change - Updated the commit message - Added 80 attempts for pre-DP 1.4 devices Changes in v5: - Removed DP_DP14_MAX_CR_TRIES from drm v6: Updated comment to match kernel style (Rodrigo) Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Marc Herbert <marc.herbert@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Nathan Ciobanu <nathan.d.ciobanu@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180720214413.29506-1-rodrigo.vivi@intel.com
2018-07-21 05:44:12 +08:00
for (cr_tries = 0; cr_tries < max_cr_tries; ++cr_tries) {
uint8_t link_status[DP_LINK_STATUS_SIZE];
drm_dp_link_train_clock_recovery_delay(intel_dp->dpcd);
if (!intel_dp_get_link_status(intel_dp, link_status)) {
DRM_ERROR("failed to get link status\n");
return false;
}
if (drm_dp_clock_recovery_ok(link_status, intel_dp->lane_count)) {
DRM_DEBUG_KMS("clock recovery OK\n");
return true;
}
if (voltage_tries == 5) {
DRM_DEBUG_KMS("Same voltage tried 5 times\n");
return false;
}
if (max_vswing_reached) {
DRM_DEBUG_KMS("Max Voltage Swing reached\n");
return false;
}
voltage = intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK;
/* Update training set as requested by target */
intel_get_adjust_train(intel_dp, link_status);
if (!intel_dp_update_link_train(intel_dp)) {
DRM_ERROR("failed to update link training\n");
return false;
}
if ((intel_dp->train_set[0] & DP_TRAIN_VOLTAGE_SWING_MASK) ==
voltage)
++voltage_tries;
else
voltage_tries = 1;
if (intel_dp_link_max_vswing_reached(intel_dp))
max_vswing_reached = true;
}
drm/i915/dp: Limit link training clock recovery loop Limit the link training clock recovery loop to 10 attempts at LANEx_CR_DONE per DP 1.4 spec section 3.5.1.2.2 and 80 attempts for pre-DP 1.4 (4 voltage levels x 4 preemphasis levels x x 5 identical voltages tries). Some faulty USB-C MST hubs can cause us to get stuck in this loop indefinitely requesting something like: voltage swing: 0, pre-emphasis level: 2 voltage swing: 1, pre-emphasis level: 2 voltage swing: 0, pre-emphasis level: 3 over and over so max_vswing would never be reached, drm_dp_clock_recovery_ok() would never return true and voltage_tries would always get reset to 1. The driver sends those values to the hub but the hub keeps requesting new values every time. Changes in v2: - updated commit message (DK, Manasi) - defined DP_DP14_MAX_CR_TRIES (Marc) - made the loop iterate for max 10 times (Rodrigo, Marc) Changes in v3: - changed error message to use DP_DP14_MAX_CR_TRIES Changes in v4: - Updated the title to reflect the change - Updated the commit message - Added 80 attempts for pre-DP 1.4 devices Changes in v5: - Removed DP_DP14_MAX_CR_TRIES from drm v6: Updated comment to match kernel style (Rodrigo) Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@intel.com> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com> Cc: Marc Herbert <marc.herbert@intel.com> Cc: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Nathan Ciobanu <nathan.d.ciobanu@linux.intel.com> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180720214413.29506-1-rodrigo.vivi@intel.com
2018-07-21 05:44:12 +08:00
DRM_ERROR("Failed clock recovery %d times, giving up!\n", max_cr_tries);
return false;
}
/*
* Pick training pattern for channel equalization. Training pattern 4 for HBR3
* or for 1.4 devices that support it, training Pattern 3 for HBR2
* or 1.2 devices that support it, Training Pattern 2 otherwise.
*/
static u32 intel_dp_training_pattern(struct intel_dp *intel_dp)
{
bool source_tps3, sink_tps3, source_tps4, sink_tps4;
/*
* Intel platforms that support HBR3 also support TPS4. It is mandatory
* for all downstream devices that support HBR3. There are no known eDP
* panels that support TPS4 as of Feb 2018 as per VESA eDP_v1.4b_E1
* specification.
*/
source_tps4 = intel_dp_source_supports_hbr3(intel_dp);
sink_tps4 = drm_dp_tps4_supported(intel_dp->dpcd);
if (source_tps4 && sink_tps4) {
return DP_TRAINING_PATTERN_4;
} else if (intel_dp->link_rate == 810000) {
if (!source_tps4)
DRM_DEBUG_KMS("8.1 Gbps link rate without source HBR3/TPS4 support\n");
if (!sink_tps4)
DRM_DEBUG_KMS("8.1 Gbps link rate without sink TPS4 support\n");
}
/*
* Intel platforms that support HBR2 also support TPS3. TPS3 support is
* also mandatory for downstream devices that support HBR2. However, not
* all sinks follow the spec.
*/
source_tps3 = intel_dp_source_supports_hbr2(intel_dp);
sink_tps3 = drm_dp_tps3_supported(intel_dp->dpcd);
if (source_tps3 && sink_tps3) {
return DP_TRAINING_PATTERN_3;
} else if (intel_dp->link_rate >= 540000) {
if (!source_tps3)
DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without source HBR2/TPS3 support\n");
if (!sink_tps3)
DRM_DEBUG_KMS(">=5.4/6.48 Gbps link rate without sink TPS3 support\n");
}
return DP_TRAINING_PATTERN_2;
}
static bool
intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
{
int tries;
u32 training_pattern;
uint8_t link_status[DP_LINK_STATUS_SIZE];
bool channel_eq = false;
training_pattern = intel_dp_training_pattern(intel_dp);
/* Scrambling is disabled for TPS2/3 and enabled for TPS4 */
if (training_pattern != DP_TRAINING_PATTERN_4)
training_pattern |= DP_LINK_SCRAMBLING_DISABLE;
/* channel equalization */
if (!intel_dp_set_link_train(intel_dp,
training_pattern)) {
DRM_ERROR("failed to start channel equalization\n");
return false;
}
for (tries = 0; tries < 5; tries++) {
drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
if (!intel_dp_get_link_status(intel_dp, link_status)) {
DRM_ERROR("failed to get link status\n");
break;
}
/* Make sure clock is still ok */
if (!drm_dp_clock_recovery_ok(link_status,
intel_dp->lane_count)) {
intel_dp_dump_link_status(link_status);
DRM_DEBUG_KMS("Clock recovery check failed, cannot "
"continue channel equalization\n");
break;
}
if (drm_dp_channel_eq_ok(link_status,
intel_dp->lane_count)) {
channel_eq = true;
DRM_DEBUG_KMS("Channel EQ done. DP Training "
"successful\n");
break;
}
/* Update training set as requested by target */
intel_get_adjust_train(intel_dp, link_status);
if (!intel_dp_update_link_train(intel_dp)) {
DRM_ERROR("failed to update link training\n");
break;
}
}
/* Try 5 times, else fail and try at lower BW */
if (tries == 5) {
intel_dp_dump_link_status(link_status);
DRM_DEBUG_KMS("Channel equalization failed 5 times\n");
}
intel_dp_set_idle_link_train(intel_dp);
return channel_eq;
}
void intel_dp_stop_link_train(struct intel_dp *intel_dp)
{
intel_dp->link_trained = true;
intel_dp_set_link_train(intel_dp,
DP_TRAINING_PATTERN_DISABLE);
}
void
intel_dp_start_link_train(struct intel_dp *intel_dp)
{
drm/i915: Implement Link Rate fallback on Link training failure If link training at a link rate optimal for a particular mode fails during modeset's atomic commit phase, then we let the modeset complete and then retry. We save the link rate value at which link training failed, update the link status property to "BAD" and use a lower link rate to prune the modes. It will redo the modeset on the current mode at lower link rate or if the current mode gets pruned due to lower link constraints then, it will send a hotplug uevent for userspace to handle it. This is also required to pass DP CTS tests 4.3.1.3, 4.3.1.4, 4.3.1.6. This patch is a resend of the original commit id (233ce881dd91fb "drm/i915: Implement Link Rate fallback on Link training failure") which got reverted in this commit id (afc1ebf4562a14 Revert "drm/i915: Implement Link Rate fallback on Link training failure") due to CI failures. After investigating the CI failures it was found that these were essentially the failures which were always there but hidden because they used to be DRM_DEBUG_KMS messages for link failures so never got caught by CI. But now this patch actually throws DRM_ERROR if the link training fails at RBR and 1 lane. So it caught these link train failures. There were two failures: 1. On SKL 6700k this was because the machine in CI lab is a SKL desktop without eDP on Port A. But our VBT initialization code in the driver writes VBT defaults in a way that it always sets DP flag on Port A and this does not get cleared after parsing the VBT outputs. This has been fixed in commit id (bb1d132935c2f8 "drm/i915/vbt: split out defaults that are set when there is no VBT) and (665788572c6410b "drm/i915/vbt: don't propagate errors from intel_bios_init()) 2. On ILK-650 desktop - This was happening because of a bad monitor desktop combination. I switched the monitor in the CI lab and that helped get rid of the link failures on ILK system. v10: * Rebase on drm-tip and resend after revert v9: * Use the trimmed max values of link rate/lane count based on link train fallback (Daniel Vetter) v8: * Set link_status to BAD first and then call mode_valid (Jani Nikula) v7: Remove the redundant variable in previous patch itself v6: * Obtain link rate index from fallback_link_rate using the helper intel_dp_link_rate_index (Jani Nikula) * Include fallback within intel_dp_start_link_train (Jani Nikula) v5: * Move set link status to drm core (Daniel Vetter, Jani Nikula) v4: * Add fallback support for non DDI platforms too * Set connector->link status inside set_link_status function (Jani Nikula) v3: * Set link status property to BAd unconditionally (Jani Nikula) * Dont use two separate variables link_train_failed and link_status to indicate same thing (Jani Nikula) v2: * Squashed a few patches (Jani Nikula) Acked-by: Tony Cheng <tony.cheng@amd.com> Acked-by: Harry Wentland <Harry.wentland@amd.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/16ca48b1e74c618929245e9a085b9e3483c3a16d.1491485983.git.jani.nikula@intel.com
2017-04-06 21:44:19 +08:00
struct intel_connector *intel_connector = intel_dp->attached_connector;
if (!intel_dp_link_training_clock_recovery(intel_dp))
goto failure_handling;
if (!intel_dp_link_training_channel_equalization(intel_dp))
goto failure_handling;
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training Passed at Link Rate = %d, Lane count = %d",
intel_connector->base.base.id,
intel_connector->base.name,
drm/i915: Implement Link Rate fallback on Link training failure If link training at a link rate optimal for a particular mode fails during modeset's atomic commit phase, then we let the modeset complete and then retry. We save the link rate value at which link training failed, update the link status property to "BAD" and use a lower link rate to prune the modes. It will redo the modeset on the current mode at lower link rate or if the current mode gets pruned due to lower link constraints then, it will send a hotplug uevent for userspace to handle it. This is also required to pass DP CTS tests 4.3.1.3, 4.3.1.4, 4.3.1.6. This patch is a resend of the original commit id (233ce881dd91fb "drm/i915: Implement Link Rate fallback on Link training failure") which got reverted in this commit id (afc1ebf4562a14 Revert "drm/i915: Implement Link Rate fallback on Link training failure") due to CI failures. After investigating the CI failures it was found that these were essentially the failures which were always there but hidden because they used to be DRM_DEBUG_KMS messages for link failures so never got caught by CI. But now this patch actually throws DRM_ERROR if the link training fails at RBR and 1 lane. So it caught these link train failures. There were two failures: 1. On SKL 6700k this was because the machine in CI lab is a SKL desktop without eDP on Port A. But our VBT initialization code in the driver writes VBT defaults in a way that it always sets DP flag on Port A and this does not get cleared after parsing the VBT outputs. This has been fixed in commit id (bb1d132935c2f8 "drm/i915/vbt: split out defaults that are set when there is no VBT) and (665788572c6410b "drm/i915/vbt: don't propagate errors from intel_bios_init()) 2. On ILK-650 desktop - This was happening because of a bad monitor desktop combination. I switched the monitor in the CI lab and that helped get rid of the link failures on ILK system. v10: * Rebase on drm-tip and resend after revert v9: * Use the trimmed max values of link rate/lane count based on link train fallback (Daniel Vetter) v8: * Set link_status to BAD first and then call mode_valid (Jani Nikula) v7: Remove the redundant variable in previous patch itself v6: * Obtain link rate index from fallback_link_rate using the helper intel_dp_link_rate_index (Jani Nikula) * Include fallback within intel_dp_start_link_train (Jani Nikula) v5: * Move set link status to drm core (Daniel Vetter, Jani Nikula) v4: * Add fallback support for non DDI platforms too * Set connector->link status inside set_link_status function (Jani Nikula) v3: * Set link status property to BAd unconditionally (Jani Nikula) * Dont use two separate variables link_train_failed and link_status to indicate same thing (Jani Nikula) v2: * Squashed a few patches (Jani Nikula) Acked-by: Tony Cheng <tony.cheng@amd.com> Acked-by: Harry Wentland <Harry.wentland@amd.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/16ca48b1e74c618929245e9a085b9e3483c3a16d.1491485983.git.jani.nikula@intel.com
2017-04-06 21:44:19 +08:00
intel_dp->link_rate, intel_dp->lane_count);
return;
failure_handling:
2017-10-13 03:13:38 +08:00
/* Dont fallback and prune modes if its eDP */
if (!intel_dp_is_edp(intel_dp)) {
DRM_DEBUG_KMS("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
intel_connector->base.base.id,
intel_connector->base.name,
intel_dp->link_rate, intel_dp->lane_count);
if (!intel_dp_get_link_train_fallback_values(intel_dp,
intel_dp->link_rate,
intel_dp->lane_count))
/* Schedule a Hotplug Uevent to userspace to start modeset */
schedule_work(&intel_connector->modeset_retry_work);
} else {
DRM_ERROR("[CONNECTOR:%d:%s] Link Training failed at link rate = %d, lane count = %d",
intel_connector->base.base.id,
intel_connector->base.name,
intel_dp->link_rate, intel_dp->lane_count);
}
drm/i915: Implement Link Rate fallback on Link training failure If link training at a link rate optimal for a particular mode fails during modeset's atomic commit phase, then we let the modeset complete and then retry. We save the link rate value at which link training failed, update the link status property to "BAD" and use a lower link rate to prune the modes. It will redo the modeset on the current mode at lower link rate or if the current mode gets pruned due to lower link constraints then, it will send a hotplug uevent for userspace to handle it. This is also required to pass DP CTS tests 4.3.1.3, 4.3.1.4, 4.3.1.6. This patch is a resend of the original commit id (233ce881dd91fb "drm/i915: Implement Link Rate fallback on Link training failure") which got reverted in this commit id (afc1ebf4562a14 Revert "drm/i915: Implement Link Rate fallback on Link training failure") due to CI failures. After investigating the CI failures it was found that these were essentially the failures which were always there but hidden because they used to be DRM_DEBUG_KMS messages for link failures so never got caught by CI. But now this patch actually throws DRM_ERROR if the link training fails at RBR and 1 lane. So it caught these link train failures. There were two failures: 1. On SKL 6700k this was because the machine in CI lab is a SKL desktop without eDP on Port A. But our VBT initialization code in the driver writes VBT defaults in a way that it always sets DP flag on Port A and this does not get cleared after parsing the VBT outputs. This has been fixed in commit id (bb1d132935c2f8 "drm/i915/vbt: split out defaults that are set when there is no VBT) and (665788572c6410b "drm/i915/vbt: don't propagate errors from intel_bios_init()) 2. On ILK-650 desktop - This was happening because of a bad monitor desktop combination. I switched the monitor in the CI lab and that helped get rid of the link failures on ILK system. v10: * Rebase on drm-tip and resend after revert v9: * Use the trimmed max values of link rate/lane count based on link train fallback (Daniel Vetter) v8: * Set link_status to BAD first and then call mode_valid (Jani Nikula) v7: Remove the redundant variable in previous patch itself v6: * Obtain link rate index from fallback_link_rate using the helper intel_dp_link_rate_index (Jani Nikula) * Include fallback within intel_dp_start_link_train (Jani Nikula) v5: * Move set link status to drm core (Daniel Vetter, Jani Nikula) v4: * Add fallback support for non DDI platforms too * Set connector->link status inside set_link_status function (Jani Nikula) v3: * Set link status property to BAd unconditionally (Jani Nikula) * Dont use two separate variables link_train_failed and link_status to indicate same thing (Jani Nikula) v2: * Squashed a few patches (Jani Nikula) Acked-by: Tony Cheng <tony.cheng@amd.com> Acked-by: Harry Wentland <Harry.wentland@amd.com> Cc: Jani Nikula <jani.nikula@linux.intel.com> Cc: Daniel Vetter <daniel.vetter@intel.com> Cc: Ville Syrjala <ville.syrjala@linux.intel.com> Signed-off-by: Manasi Navare <manasi.d.navare@intel.com> Reviewed-by: Jani Nikula <jani.nikula@intel.com> Signed-off-by: Jani Nikula <jani.nikula@intel.com> Link: http://patchwork.freedesktop.org/patch/msgid/16ca48b1e74c618929245e9a085b9e3483c3a16d.1491485983.git.jani.nikula@intel.com
2017-04-06 21:44:19 +08:00
return;
}