At least some DELL monitors (P2715Q) with DPCD_REV 1.2 return corrupted DPCD register values when reading from the 0xF0000- LTTPR range with an AUX transaction block size bigger than 1. The DP standard requires 0 to be returned - as for any other reserved/invalid addresses - but these monitors return the DPCD_REV register value repeated in each byte of the read buffer. This will in turn corrupt the values returned by the LTTPRs between the source and the monitor: LTTPRs must adjust the values they read from the downstream DPRX, for instance right-shift/init the downstream DP_PHY_REPEATER_CNT value. Since the value returned by the monitor's DPRX is non-zero the adjusted values will be corrupt. Reading the LTTPR registers one-by-one instead of reading all of them with a single AUX transfer works around the issue. According to the DP standard's 0xF0000 register description: "LTTPR-related registers at DPCD Addresses F0000h through F02FFh are valid only for DPCD r1.4 (or higher)." While it's unclear if DPCD r1.4 refers to the DPCD_REV or to the LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV register (tickets filed at the VESA site to clarify this haven't been addressed), one possibility is that it's a restriction due to non-compliant monitors described above. Disabling the non-transparent LTTPR mode for all such monitors is not a viable solution: the transparent LTTPR mode has its own issue causing link training failures and this would affect a lot of monitors in use with DPCD_REV < 1.4. Instead this patch works around the problem by reading the LTTPR common and PHY cap registers one-by-one for any monitor with a DPCD_REV < 1.4. The standard requires the DPCD capabilities to be read after the LTTPR common capabilities are read, so re-read the DPCD capabilities after the LTTPR common and PHY caps were read out. v2: - Use for instead of a while loop. (Ville) - Add to code comment the monitor model with the problem.
Unified · Split
| @@ -2400,9 +2400,36 @@ int drm_dp_dsc_sink_supported_input_bpcs(const u8 dsc_dpcd[DP_DSC_RECEIVER_CAP_S · 2399 unmodified lines | |||
| 2400 | } | 2400 | } |
| 2401 | EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); | 2401 | EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); |
| 2402 | 2402 | ||
| 2403 | static int drm_dp_read_lttpr_regs(struct drm_dp_aux *aux, | ||
| 2404 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], int address, | ||
| 2405 | u8 *buf, int buf_size) | ||
| 2406 | { | ||
| 2407 | /* | ||
| 2408 | * At least the DELL P2715Q monitor with a DPCD_REV < 0x14 returns | ||
| 2409 | * corrupted values when reading from the 0xF0000- range with a block | ||
| 2410 | * size bigger than 1. | ||
| 2411 | */ | ||
| 2412 | int block_size = dpcd[DP_DPCD_REV] < 0x14 ? 1 : buf_size; | ||
| 2413 | int offset; | ||
| 2414 | int ret; | ||
| 2415 | |||
| 2416 | for (offset = 0; offset < buf_size; offset += block_size) { | ||
| 2417 | ret = drm_dp_dpcd_read(aux, | ||
| 2418 | address + offset, | ||
| 2419 | &buf[offset], block_size); | ||
| 2420 | if (ret < 0) | ||
| 2421 | return ret; | ||
| 2422 | |||
| 2423 | WARN_ON(ret != block_size); | ||
| 2424 | } | ||
| 2425 | |||
| 2426 | return 0; | ||
| 2427 | } | ||
| 2428 | |||
| 2403 | /** | 2429 | /** |
| 2404 | * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities | 2430 | * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities |
| 2405 | * @aux: DisplayPort AUX channel | 2431 | * @aux: DisplayPort AUX channel |
| 2432 | * @dpcd: DisplayPort configuration data | ||
| 2406 | * @caps: buffer to return the capability info in | 2433 | * @caps: buffer to return the capability info in |
| 2407 | * | 2434 | * |
| 2408 | * Read capabilities common to all LTTPRs. | 2435 | * Read capabilities common to all LTTPRs. |
| @@ -2410,25 +2437,19 @@ EXPORT_SYMBOL(drm_dp_dsc_sink_supported_input_bpcs); · 1 unmodified line | |||
| 2410 | * Returns 0 on success or a negative error code on failure. | 2437 | * Returns 0 on success or a negative error code on failure. |
| 2411 | */ | 2438 | */ |
| 2412 | int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, | 2439 | int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, |
| 2440 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], | ||
| 2413 | u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) | 2441 | u8 caps[DP_LTTPR_COMMON_CAP_SIZE]) |
| 2414 | { | 2442 | { |
| 2415 | int ret; | 2443 | return drm_dp_read_lttpr_regs(aux, dpcd, |
| 2416 | 2444 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, | |
| 2417 | ret = drm_dp_dpcd_read(aux, | 2445 | caps, DP_LTTPR_COMMON_CAP_SIZE); |
| 2418 | DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV, | ||
| 2419 | caps, DP_LTTPR_COMMON_CAP_SIZE); | ||
| 2420 | if (ret < 0) | ||
| 2421 | return ret; | ||
| 2422 | |||
| 2423 | WARN_ON(ret != DP_LTTPR_COMMON_CAP_SIZE); | ||
| 2424 | |||
| 2425 | return 0; | ||
| 2426 | } | 2446 | } |
| 2427 | EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); | 2447 | EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); |
| 2428 | 2448 | ||
| 2429 | /** | 2449 | /** |
| 2430 | * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY | 2450 | * drm_dp_read_lttpr_phy_caps - read the capabilities for a given LTTPR PHY |
| 2431 | * @aux: DisplayPort AUX channel | 2451 | * @aux: DisplayPort AUX channel |
| 2452 | * @dpcd: DisplayPort configuration data | ||
| 2432 | * @dp_phy: LTTPR PHY to read the capabilities for | 2453 | * @dp_phy: LTTPR PHY to read the capabilities for |
| 2433 | * @caps: buffer to return the capability info in | 2454 | * @caps: buffer to return the capability info in |
| 2434 | * | 2455 | * |
| @@ -2437,20 +2458,13 @@ EXPORT_SYMBOL(drm_dp_read_lttpr_common_caps); · 2 unmodified lines | |||
| 2437 | * Returns 0 on success or a negative error code on failure. | 2458 | * Returns 0 on success or a negative error code on failure. |
| 2438 | */ | 2459 | */ |
| 2439 | int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, | 2460 | int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, |
| 2461 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], | ||
| 2440 | enum drm_dp_phy dp_phy, | 2462 | enum drm_dp_phy dp_phy, |
| 2441 | u8 caps[DP_LTTPR_PHY_CAP_SIZE]) | 2463 | u8 caps[DP_LTTPR_PHY_CAP_SIZE]) |
| 2442 | { | 2464 | { |
| 2443 | int ret; | 2465 | return drm_dp_read_lttpr_regs(aux, dpcd, |
| 2444 | 2466 | DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), | |
| 2445 | ret = drm_dp_dpcd_read(aux, | 2467 | caps, DP_LTTPR_PHY_CAP_SIZE); |
| 2446 | DP_TRAINING_AUX_RD_INTERVAL_PHY_REPEATER(dp_phy), | ||
| 2447 | caps, DP_LTTPR_PHY_CAP_SIZE); | ||
| 2448 | if (ret < 0) | ||
| 2449 | return ret; | ||
| 2450 | |||
| 2451 | WARN_ON(ret != DP_LTTPR_PHY_CAP_SIZE); | ||
| 2452 | |||
| 2453 | return 0; | ||
| 2454 | } | 2468 | } |
| 2455 | EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); | 2469 | EXPORT_SYMBOL(drm_dp_read_lttpr_phy_caps); |
| 2456 | 2470 | ||
| @@ -55,6 +55,7 @@ static u8 *intel_dp_lttpr_phy_caps(struct intel_dp *intel_dp, · 54 unmodified lines | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, | 57 | static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, |
| 58 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], | ||
| 58 | enum drm_dp_phy dp_phy) | 59 | enum drm_dp_phy dp_phy) |
| 59 | { | 60 | { |
| 60 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; | 61 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; |
| @@ -63,7 +64,7 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, · 2 unmodified lines | |||
| 63 | 64 | ||
| 64 | intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)); | 65 | intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)); |
| 65 | 66 | ||
| 66 | if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dp_phy, phy_caps) < 0) { | 67 | if (drm_dp_read_lttpr_phy_caps(&intel_dp->aux, dpcd, dp_phy, phy_caps) < 0) { |
| 67 | drm_dbg_kms(&dp_to_i915(intel_dp)->drm, | 68 | drm_dbg_kms(&dp_to_i915(intel_dp)->drm, |
| 68 | "[ENCODER:%d:%s][%s] failed to read the PHY caps\n", | 69 | "[ENCODER:%d:%s][%s] failed to read the PHY caps\n", |
| 69 | encoder->base.base.id, encoder->base.name, phy_name); | 70 | encoder->base.base.id, encoder->base.name, phy_name); |
| @@ -77,10 +78,12 @@ static void intel_dp_read_lttpr_phy_caps(struct intel_dp *intel_dp, · 7 unmodified lines | |||
| 77 | phy_caps); | 78 | phy_caps); |
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) | 81 | static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp, |
| 82 | const u8 dpcd[DP_RECEIVER_CAP_SIZE]) | ||
| 81 | { | 83 | { |
| 82 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; | 84 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; |
| 83 | struct drm_i915_private *i915 = to_i915(encoder->base.dev); | 85 | struct drm_i915_private *i915 = to_i915(encoder->base.dev); |
| 86 | int ret; | ||
| 84 | 87 | ||
| 85 | if (intel_dp_is_edp(intel_dp)) | 88 | if (intel_dp_is_edp(intel_dp)) |
| 86 | return false; | 89 | return false; |
| @@ -92,8 +95,9 @@ static bool intel_dp_read_lttpr_common_caps(struct intel_dp *intel_dp) · 5 unmodified lines | |||
| 92 | if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915)) | 95 | if (DISPLAY_VER(i915) < 10 || IS_GEMINILAKE(i915)) |
| 93 | return false; | 96 | return false; |
| 94 | 97 | ||
| 95 | if (drm_dp_read_lttpr_common_caps(&intel_dp->aux, | 98 | ret = drm_dp_read_lttpr_common_caps(&intel_dp->aux, dpcd, |
| 96 | intel_dp->lttpr_common_caps) < 0) | 99 | intel_dp->lttpr_common_caps); |
| 100 | if (ret < 0) | ||
| 97 | goto reset_caps; | 101 | goto reset_caps; |
| 98 | 102 | ||
| 99 | drm_dbg_kms(&dp_to_i915(intel_dp)->drm, | 103 | drm_dbg_kms(&dp_to_i915(intel_dp)->drm, |
| @@ -122,14 +126,14 @@ intel_dp_set_lttpr_transparent_mode(struct intel_dp *intel_dp, bool enable) · 22 unmodified lines | |||
| 122 | return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; | 126 | return drm_dp_dpcd_write(&intel_dp->aux, DP_PHY_REPEATER_MODE, &val, 1) == 1; |
| 123 | } | 127 | } |
| 124 | 128 | ||
| 125 | static int intel_dp_init_lttpr(struct intel_dp *intel_dp) | 129 | static int intel_dp_init_lttpr(struct intel_dp *intel_dp, const u8 dpcd[DP_RECEIVER_CAP_SIZE]) |
| 126 | { | 130 | { |
| 127 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; | 131 | struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base; |
| 128 | struct drm_i915_private *i915 = to_i915(encoder->base.dev); | 132 | struct drm_i915_private *i915 = to_i915(encoder->base.dev); |
| 129 | int lttpr_count; | 133 | int lttpr_count; |
| 130 | int i; | 134 | int i; |
| 131 | 135 | ||
| 132 | if (!intel_dp_read_lttpr_common_caps(intel_dp)) | 136 | if (!intel_dp_read_lttpr_common_caps(intel_dp, dpcd)) |
| 133 | return 0; | 137 | return 0; |
| 134 | 138 | ||
| 135 | lttpr_count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps); | 139 | lttpr_count = drm_dp_lttpr_count(intel_dp->lttpr_common_caps); |
| @@ -168,7 +172,7 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp) · 32 unmodified lines | |||
| 168 | } | 172 | } |
| 169 | 173 | ||
| 170 | for (i = 0; i < lttpr_count; i++) | 174 | for (i = 0; i < lttpr_count; i++) |
| 171 | intel_dp_read_lttpr_phy_caps(intel_dp, DP_PHY_LTTPR(i)); | 175 | intel_dp_read_lttpr_phy_caps(intel_dp, dpcd, DP_PHY_LTTPR(i)); |
| 172 | 176 | ||
| 173 | return lttpr_count; | 177 | return lttpr_count; |
| 174 | } | 178 | } |
| @@ -193,9 +197,18 @@ static int intel_dp_init_lttpr(struct intel_dp *intel_dp) · 18 unmodified lines | |||
| 193 | */ | 197 | */ |
| 194 | int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) | 198 | int intel_dp_init_lttpr_and_dprx_caps(struct intel_dp *intel_dp) |
| 195 | { | 199 | { |
| 196 | int lttpr_count = intel_dp_init_lttpr(intel_dp); | 200 | u8 dpcd[DP_RECEIVER_CAP_SIZE]; |
| 201 | int lttpr_count; | ||
| 202 | |||
| 203 | if (drm_dp_read_dpcd_caps(&intel_dp->aux, dpcd)) | ||
| 204 | return -EIO; | ||
| 197 | 205 | ||
| 198 | /* The DPTX shall read the DPRX caps after LTTPR detection. */ | 206 | lttpr_count = intel_dp_init_lttpr(intel_dp, dpcd); |
| 207 | |||
| 208 | /* | ||
| 209 | * The DPTX shall read the DPRX caps after LTTPR detection, so re-read | ||
| 210 | * it here. | ||
| 211 | */ | ||
| 199 | if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) { | 212 | if (drm_dp_read_dpcd_caps(&intel_dp->aux, intel_dp->dpcd)) { |
| 200 | intel_dp_reset_lttpr_common_caps(intel_dp); | 213 | intel_dp_reset_lttpr_common_caps(intel_dp); |
| 201 | return -EIO; | 214 | return -EIO; |
| @@ -2150,8 +2150,10 @@ bool drm_dp_read_sink_count_cap(struct drm_connector *connector, · 2149 unmodified lines | |||
| 2150 | int drm_dp_read_sink_count(struct drm_dp_aux *aux); | 2150 | int drm_dp_read_sink_count(struct drm_dp_aux *aux); |
| 2151 | 2151 | ||
| 2152 | int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, | 2152 | int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux, |
| 2153 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], | ||
| 2153 | u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); | 2154 | u8 caps[DP_LTTPR_COMMON_CAP_SIZE]); |
| 2154 | int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, | 2155 | int drm_dp_read_lttpr_phy_caps(struct drm_dp_aux *aux, |
| 2156 | const u8 dpcd[DP_RECEIVER_CAP_SIZE], | ||
| 2155 | enum drm_dp_phy dp_phy, | 2157 | enum drm_dp_phy dp_phy, |
| 2156 | u8 caps[DP_LTTPR_PHY_CAP_SIZE]); | 2158 | u8 caps[DP_LTTPR_PHY_CAP_SIZE]); |
| 2157 | int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]); | 2159 | int drm_dp_lttpr_count(const u8 cap[DP_LTTPR_COMMON_CAP_SIZE]); |