Commit b30edfd8 authored by Imre Deak's avatar Imre Deak

drm/i915: Switch to LTTPR non-transparent mode link training

The DP Standard's recommendation is to use the LTTPR non-transparent
mode link training if LTTPRs are detected, so let's do this.

Besides power-saving, the advantages of this are that the maximum number
of LTTPRs can only be used in non-transparent mode (the limit is 5-8 in
transparent mode), and it provides a way to narrow down the reason for a
link training failure to a given link segment. Non-transparent mode is
probably also the mode that was tested the most by the industry.

The changes in this patchset:
- Pass the DP PHY that is currently link trained to all LT helpers, so
  that these can access the correct LTTPR/DPRX DPCD registers.
- During LT take into account the LTTPR common lane rate/count and the
  per LTTPR-PHY vswing/pre-emph limits.
- Switch to LTTPR non-transparent LT mode and train each link segment
  according to the sequence in DP Standard v2.0 (complete CR/EQ for
  each segment before continuing with the next segment).

v2:
- Switch to non-transparent mode during connector detection, which is
  required before reading the per-PHY LTTPR capabilities.
- Move the DP_PHY_LTTPR() macro to drm_dp_helper.h (Ville)
- Use the new drm_dp_dpcd_read_phy_link_status() instead of adding the
  same logic to intel_dp_get_link_status(). (Ville)
- Make intel_dp_lttpr_phy_caps() return a pointer to the whole array
  instead of a pointer to its first element. (Ville)
- Add the intel_dp_phy_is_downstream_of_source() helper. (Ville)
- Add a code comment about the disable->enable quirk of
  non-transparent mode.
- Add the intel_dp_training_pattern_set_reg() helper.
- Fix checkpatch/sparse warns.

Cc: Ville Syrjälä <ville.syrjala@linux.intel.com>
Reviewed-by: default avatarVille Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: default avatarImre Deak <imre.deak@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20201007170917.1764556-7-imre.deak@intel.com
parent 7b2a4ab8
...@@ -1303,6 +1303,7 @@ struct intel_dp { ...@@ -1303,6 +1303,7 @@ struct intel_dp {
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE]; u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE]; u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_SIZE];
u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE]; u8 lttpr_common_caps[DP_LTTPR_COMMON_CAP_SIZE];
u8 lttpr_phy_caps[DP_MAX_LTTPR_COUNT][DP_LTTPR_PHY_CAP_SIZE];
u8 fec_capable; u8 fec_capable;
/* source rates */ /* source rates */
int num_source_rates; int num_source_rates;
......
...@@ -160,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) ...@@ -160,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
162000, 270000, 540000, 810000 162000, 270000, 540000, 810000
}; };
int i, max_rate; int i, max_rate;
int max_lttpr_rate;
if (drm_dp_has_quirk(&intel_dp->desc, 0, if (drm_dp_has_quirk(&intel_dp->desc, 0,
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) { DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
...@@ -173,6 +174,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp) ...@@ -173,6 +174,9 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
} }
max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]); max_rate = drm_dp_bw_code_to_link_rate(intel_dp->dpcd[DP_MAX_LINK_RATE]);
max_lttpr_rate = drm_dp_lttpr_max_link_rate(intel_dp->lttpr_common_caps);
if (max_lttpr_rate)
max_rate = min(max_rate, max_lttpr_rate);
for (i = 0; i < ARRAY_SIZE(dp_rates); i++) { for (i = 0; i < ARRAY_SIZE(dp_rates); i++) {
if (dp_rates[i] > max_rate) if (dp_rates[i] > max_rate)
...@@ -218,6 +222,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp) ...@@ -218,6 +222,10 @@ static int intel_dp_max_common_lane_count(struct intel_dp *intel_dp)
int source_max = dig_port->max_lanes; int source_max = dig_port->max_lanes;
int sink_max = drm_dp_max_lane_count(intel_dp->dpcd); int sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
int fia_max = intel_tc_port_fia_max_lane_count(dig_port); int fia_max = intel_tc_port_fia_max_lane_count(dig_port);
int lttpr_max = drm_dp_lttpr_max_lane_count(intel_dp->lttpr_common_caps);
if (lttpr_max)
sink_max = min(sink_max, lttpr_max);
return min3(source_max, sink_max, fia_max); return min3(source_max, sink_max, fia_max);
} }
...@@ -4179,17 +4187,6 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state, ...@@ -4179,17 +4187,6 @@ static void chv_dp_post_pll_disable(struct intel_atomic_state *state,
chv_phy_post_pll_disable(encoder, old_crtc_state); chv_phy_post_pll_disable(encoder, old_crtc_state);
} }
/*
* Fetch AUX CH registers 0x202 - 0x207 which contain
* link status information
*/
bool
intel_dp_get_link_status(struct intel_dp *intel_dp, u8 link_status[DP_LINK_STATUS_SIZE])
{
return drm_dp_dpcd_read(&intel_dp->aux, DP_LANE0_1_STATUS, link_status,
DP_LINK_STATUS_SIZE) == DP_LINK_STATUS_SIZE;
}
static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp, static u8 intel_dp_voltage_max_2(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state) const struct intel_crtc_state *crtc_state)
{ {
...@@ -5592,13 +5589,15 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp, ...@@ -5592,13 +5589,15 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
&intel_dp->compliance.test_data.phytest; &intel_dp->compliance.test_data.phytest;
u8 link_status[DP_LINK_STATUS_SIZE]; u8 link_status[DP_LINK_STATUS_SIZE];
if (!intel_dp_get_link_status(intel_dp, link_status)) { if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
link_status) < 0) {
DRM_DEBUG_KMS("failed to get link status\n"); DRM_DEBUG_KMS("failed to get link status\n");
return; return;
} }
/* retrieve vswing & pre-emphasis setting */ /* retrieve vswing & pre-emphasis setting */
intel_dp_get_adjust_train(intel_dp, crtc_state, link_status); intel_dp_get_adjust_train(intel_dp, crtc_state, DP_PHY_DPRX,
link_status);
intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state); intel_dp_autotest_phy_ddi_disable(intel_dp, crtc_state);
...@@ -5756,7 +5755,8 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp) ...@@ -5756,7 +5755,8 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
if (intel_psr_enabled(intel_dp)) if (intel_psr_enabled(intel_dp))
return false; return false;
if (!intel_dp_get_link_status(intel_dp, link_status)) if (drm_dp_dpcd_read_phy_link_status(&intel_dp->aux, DP_PHY_DPRX,
link_status) < 0)
return false; return false;
/* /*
......
...@@ -102,8 +102,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock, ...@@ -102,8 +102,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select); u8 *link_bw, u8 *rate_select);
bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp); bool intel_dp_source_supports_hbr2(struct intel_dp *intel_dp);
bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp); bool intel_dp_source_supports_hbr3(struct intel_dp *intel_dp);
bool
intel_dp_get_link_status(struct intel_dp *intel_dp, u8 *link_status);
bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp); bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp); int intel_dp_link_required(int pixel_clock, int bpp);
......
...@@ -15,6 +15,7 @@ int intel_dp_lttpr_init(struct intel_dp *intel_dp); ...@@ -15,6 +15,7 @@ int intel_dp_lttpr_init(struct intel_dp *intel_dp);
void intel_dp_get_adjust_train(struct intel_dp *intel_dp, void intel_dp_get_adjust_train(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state, const struct intel_crtc_state *crtc_state,
enum drm_dp_phy dp_phy,
const u8 link_status[DP_LINK_STATUS_SIZE]); const u8 link_status[DP_LINK_STATUS_SIZE]);
void intel_dp_start_link_train(struct intel_dp *intel_dp, void intel_dp_start_link_train(struct intel_dp *intel_dp,
const struct intel_crtc_state *crtc_state); const struct intel_crtc_state *crtc_state);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment