On Thu, Mar 05, 2026 at 01:48:11PM +0530, Arun R Murthy wrote:
> We at present have drm_dp_Read_lttpr_common_caps to read the LTTPR caps,
> but this function required DPRX caps to be passed. As per the DP2.1 spec
> section 3.6.8.6.1, section 2.12.1, section 2.12.3 (Link Policy) the
> LTTPR caps is to be read first followed by the DPRX capability.
> Hence adding another function to read the LTTPR caps without the need
> for DPRX caps.
> 
> In order to handle the issue
> https://gitlab.freedesktop.org/drm/intel/-/issues/4531
> of reading corrupted values for LTTPR caps on few pannels with DP Rev 1.2
> the workaround of reducing the block size to 1 and reading one block at a
> time is done by checking for a valid link rate.
> 
> Fixes: 657586e474bd ("drm/i915: Add a DP1.2 compatible way to read LTTPR 
> capabilities")
> Signed-off-by: Arun R Murthy <[email protected]>
> ---
>  drivers/gpu/drm/display/drm_dp_helper.c | 63 
> +++++++++++++++++++++++++++++++++
>  include/drm/display/drm_dp_helper.h     |  2 ++
>  2 files changed, 65 insertions(+)
> 
> diff --git a/drivers/gpu/drm/display/drm_dp_helper.c 
> b/drivers/gpu/drm/display/drm_dp_helper.c
> index 
> a697cc227e28964cd8322803298178e7d788e820..9fe7db73027a43b01c4d12927f1f0e61444658e5
>  100644
> --- a/drivers/gpu/drm/display/drm_dp_helper.c
> +++ b/drivers/gpu/drm/display/drm_dp_helper.c
> @@ -3050,6 +3050,69 @@ static int drm_dp_read_lttpr_regs(struct drm_dp_aux 
> *aux,
>       return 0;
>  }
>  
> +static bool drm_dp_valid_link_rate(u8 link_rate)
> +{
> +     switch (link_rate) {
> +     case 0x06:
> +     case 0x0a:
> +     case 0x14:
> +     case 0x1e:
> +             return true;
> +     default:
> +             return false;
> +     }
> +}
> +
> +/**
> + * drm_dp_read_lttpr_caps - read the LTTPR capabilities
> + * @aux: DisplayPort AUX channel
> + * @caps: buffer to return the capability info in
> + *
> + * Read capabilities common to all LTTPRs.
> + *
> + * Returns 0 on success or a negative error code on failure.
> + */
> +int drm_dp_read_lttpr_caps(struct drm_dp_aux *aux,
> +                        u8 caps[DP_LTTPR_COMMON_CAP_SIZE])
> +{
> +     /*
> +      * At least the DELL P2715Q monitor with a DPCD_REV < 0x14 returns
> +      * corrupted values when reading from the 0xF0000- range with a block
> +      * size bigger than 1.
> +      * For DP as per the spec DP2.1 section 3.6.8.6.1, section 2.12.1, 
> section
> +      * 2.12.3 (Link Policy) the LTTPR caps is to be read first followed by 
> the
> +      * DPRX capability.
> +      * So ideally we dont have DPCD_REV yet to check for the revision, 
> instead
> +      * check for the correctness of the read value and in found corrupted 
> read
> +      * block by block.
> +      */
> +     int block_size;
> +     int offset;
> +     int ret;
> +     int address = DP_LT_TUNABLE_PHY_REPEATER_FIELD_DATA_STRUCTURE_REV;
> +     int buf_size = DP_LTTPR_COMMON_CAP_SIZE;
> +
> +     ret = drm_dp_dpcd_read_data(aux, address, &caps, buf_size);
> +     if (ret < 0)
> +             return ret;
> +
> +     if (caps[0] == 0x14) {
> +             if (!drm_dp_valid_link_rate(caps[1])) {

I don't think the code can depend on what will be in caps[1] (i.e.
DP_MAX_LINK_RATE_PHY_REPEATER / 0xF0001) after the monitor returned a
corrupted value when reading this register. That is the code cannot
depend on this register value being a valid link rate encoding or
some other value.

> +                     block_size = 1;
> +                     for (offset = 0; offset < buf_size; offset += 
> block_size) {
> +                             ret = drm_dp_dpcd_read_data(aux,
> +                                                         address + offset,
> +                                                         &caps[offset],
> +                                                         block_size);
> +                             if (ret < 0)
> +                                     return ret;
> +                     }
> +             }
> +     }
> +     return 0;
> +}
> +EXPORT_SYMBOL(drm_dp_read_lttpr_caps);
> +
>  /**
>   * drm_dp_read_lttpr_common_caps - read the LTTPR common capabilities
>   * @aux: DisplayPort AUX channel
> diff --git a/include/drm/display/drm_dp_helper.h 
> b/include/drm/display/drm_dp_helper.h
> index 
> 1d0acd58f48676f60ff6a07cc6812f72cbb452e8..def145e67011c325b790c807f934b288304260c1
>  100644
> --- a/include/drm/display/drm_dp_helper.h
> +++ b/include/drm/display/drm_dp_helper.h
> @@ -755,6 +755,8 @@ bool drm_dp_read_sink_count_cap(struct drm_connector 
> *connector,
>                               const struct drm_dp_desc *desc);
>  int drm_dp_read_sink_count(struct drm_dp_aux *aux);
>  
> +int drm_dp_read_lttpr_caps(struct drm_dp_aux *aux,
> +                               u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
>  int drm_dp_read_lttpr_common_caps(struct drm_dp_aux *aux,
>                                 const u8 dpcd[DP_RECEIVER_CAP_SIZE],
>                                 u8 caps[DP_LTTPR_COMMON_CAP_SIZE]);
> 
> -- 
> 2.25.1
> 

Reply via email to