Skip to content

Commit

Permalink
drm/i915: Switch to LTTPR non-transparent mode link training
Browse files Browse the repository at this point in the history
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ä <[email protected]>
Reviewed-by: Ville Syrjälä <[email protected]>
Signed-off-by: Imre Deak <[email protected]>
Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
  • Loading branch information
ideak committed Oct 12, 2020
1 parent 7b2a4ab commit b30edfd
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 73 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/display/intel_display_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -1303,6 +1303,7 @@ struct intel_dp {
u8 edp_dpcd[EDP_DISPLAY_CTL_CAP_SIZE];
u8 dsc_dpcd[DP_DSC_RECEIVER_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;
/* source rates */
int num_source_rates;
Expand Down
28 changes: 14 additions & 14 deletions drivers/gpu/drm/i915/display/intel_dp.c
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ static void intel_dp_set_sink_rates(struct intel_dp *intel_dp)
162000, 270000, 540000, 810000
};
int i, max_rate;
int max_lttpr_rate;

if (drm_dp_has_quirk(&intel_dp->desc, 0,
DP_DPCD_QUIRK_CAN_DO_MAX_LINK_RATE_3_24_GBPS)) {
Expand All @@ -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_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++) {
if (dp_rates[i] > max_rate)
Expand Down Expand Up @@ -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 sink_max = drm_dp_max_lane_count(intel_dp->dpcd);
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);
}
Expand Down Expand Up @@ -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);
}

/*
* 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,
const struct intel_crtc_state *crtc_state)
{
Expand Down Expand Up @@ -5592,13 +5589,15 @@ static void intel_dp_process_phy_request(struct intel_dp *intel_dp,
&intel_dp->compliance.test_data.phytest;
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");
return;
}

/* 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);

Expand Down Expand Up @@ -5756,7 +5755,8 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
if (intel_psr_enabled(intel_dp))
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;

/*
Expand Down
2 changes: 0 additions & 2 deletions drivers/gpu/drm/i915/display/intel_dp.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ void intel_dp_compute_rate(struct intel_dp *intel_dp, int port_clock,
u8 *link_bw, u8 *rate_select);
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_get_link_status(struct intel_dp *intel_dp, u8 *link_status);

bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp);
int intel_dp_link_required(int pixel_clock, int bpp);
Expand Down
Loading

0 comments on commit b30edfd

Please sign in to comment.