lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAF6AEGvcD1EMJOgWEpBZkeecrCuic0qBbc4=kRFNL1GiyHf+vQ@mail.gmail.com>
Date: Mon, 28 Apr 2025 13:07:47 -0700
From: Rob Clark <robdclark@...il.com>
To: Aleksandrs Vinarskis <alex.vinarskis@...il.com>
Cc: Dmitry Baryshkov <lumag@...nel.org>, linux-arm-msm@...r.kernel.org, 
	dri-devel@...ts.freedesktop.org, freedreno@...ts.freedesktop.org, 
	linux-kernel@...r.kernel.org, dmitry.baryshkov@....qualcomm.com, 
	Abhinav Kumar <quic_abhinavk@...cinc.com>, Sean Paul <sean@...rly.run>, 
	Marijn Suijten <marijn.suijten@...ainline.org>, David Airlie <airlied@...il.com>, 
	Simona Vetter <simona@...ll.ch>, laurentiu.tudor1@...l.com, abel.vesa@...aro.org, 
	johan@...nel.org, Stefan Schmidt <stefan.schmidt@...aro.org>
Subject: Re: [PATCH v3 4/4] drm/msm/dp: Introduce link training per-segment
 for LTTPRs

On Wed, Apr 16, 2025 at 7:13 PM Aleksandrs Vinarskis
<alex.vinarskis@...il.com> wrote:
>
> DisplayPort requires per-segment link training when LTTPR are switched
> to non-transparent mode, starting with LTTPR closest to the source.
> Only when each segment is trained individually, source can link train
> to sink.
>
> Implement per-segment link traning when LTTPR(s) are detected, to
> support external docking stations. On higher level, changes are:
>
> * Pass phy being trained down to all required helpers
> * Run CR, EQ link training per phy
> * Set voltage swing, pre-emphasis levels per phy
>
> This ensures successful link training both when connected directly to
> the monitor (single LTTPR onboard most X1E laptops) and via the docking
> station (at least two LTTPRs).
>
> Tested-by: Stefan Schmidt <stefan.schmidt@...aro.org>
> Signed-off-by: Aleksandrs Vinarskis <alex.vinarskis@...il.com>
> Reviewed-by: Abel Vesa <abel.vesa@...aro.org>

Tested-by: Rob Clark <robdclark@...il.com>  # yoga slim 7x

> ---
>  drivers/gpu/drm/msm/dp/dp_ctrl.c | 126 ++++++++++++++++++++++---------
>  1 file changed, 89 insertions(+), 37 deletions(-)
>
> diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> index 69a26bb5fabd..a50bfafbb4ea 100644
> --- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
> +++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
> @@ -1034,10 +1034,12 @@ static int msm_dp_ctrl_set_vx_px(struct msm_dp_ctrl_private *ctrl,
>         return 0;
>  }
>
> -static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
> +static int msm_dp_ctrl_update_phy_vx_px(struct msm_dp_ctrl_private *ctrl,
> +                                       enum drm_dp_phy dp_phy)
>  {
>         struct msm_dp_link *link = ctrl->link;
> -       int ret = 0, lane, lane_cnt;
> +       int lane, lane_cnt, reg;
> +       int ret = 0;
>         u8 buf[4];
>         u32 max_level_reached = 0;
>         u32 voltage_swing_level = link->phy_params.v_level;
> @@ -1075,8 +1077,13 @@ static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
>
>         drm_dbg_dp(ctrl->drm_dev, "sink: p|v=0x%x\n",
>                         voltage_swing_level | pre_emphasis_level);
> -       ret = drm_dp_dpcd_write(ctrl->aux, DP_TRAINING_LANE0_SET,
> -                                       buf, lane_cnt);
> +
> +       if (dp_phy == DP_PHY_DPRX)
> +               reg = DP_TRAINING_LANE0_SET;
> +       else
> +               reg = DP_TRAINING_LANE0_SET_PHY_REPEATER(dp_phy);
> +
> +       ret = drm_dp_dpcd_write(ctrl->aux, reg, buf, lane_cnt);
>         if (ret == lane_cnt)
>                 ret = 0;
>
> @@ -1084,9 +1091,10 @@ static int msm_dp_ctrl_update_vx_px(struct msm_dp_ctrl_private *ctrl)
>  }
>
>  static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
> -               u8 pattern)
> +               u8 pattern, enum drm_dp_phy dp_phy)
>  {
>         u8 buf;
> +       int reg;
>         int ret = 0;
>
>         drm_dbg_dp(ctrl->drm_dev, "sink: pattern=%x\n", pattern);
> @@ -1096,17 +1104,26 @@ static bool msm_dp_ctrl_train_pattern_set(struct msm_dp_ctrl_private *ctrl,
>         if (pattern && pattern != DP_TRAINING_PATTERN_4)
>                 buf |= DP_LINK_SCRAMBLING_DISABLE;
>
> -       ret = drm_dp_dpcd_writeb(ctrl->aux, DP_TRAINING_PATTERN_SET, buf);
> +       if (dp_phy == DP_PHY_DPRX)
> +               reg = DP_TRAINING_PATTERN_SET;
> +       else
> +               reg = DP_TRAINING_PATTERN_SET_PHY_REPEATER(dp_phy);
> +
> +       ret = drm_dp_dpcd_writeb(ctrl->aux, reg, buf);
>         return ret == 1;
>  }
>
>  static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
> -                       int *training_step)
> +                       int *training_step, enum drm_dp_phy dp_phy)
>  {
> +       int delay_us;
>         int tries, old_v_level, ret = 0;
>         u8 link_status[DP_LINK_STATUS_SIZE];
>         int const maximum_retries = 4;
>
> +       delay_us = drm_dp_read_clock_recovery_delay(ctrl->aux,
> +                                                   ctrl->panel->dpcd, dp_phy, false);
> +
>         msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
>
>         *training_step = DP_TRAINING_1;
> @@ -1115,18 +1132,19 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
>         if (ret)
>                 return ret;
>         msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
> -               DP_LINK_SCRAMBLING_DISABLE);
> +               DP_LINK_SCRAMBLING_DISABLE, dp_phy);
>
> -       ret = msm_dp_ctrl_update_vx_px(ctrl);
> +       msm_dp_link_reset_phy_params_vx_px(ctrl->link);
> +       ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
>         if (ret)
>                 return ret;
>
>         tries = 0;
>         old_v_level = ctrl->link->phy_params.v_level;
>         for (tries = 0; tries < maximum_retries; tries++) {
> -               drm_dp_link_train_clock_recovery_delay(ctrl->aux, ctrl->panel->dpcd);
> +               fsleep(delay_us);
>
> -               ret = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
> +               ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
>                 if (ret)
>                         return ret;
>
> @@ -1147,7 +1165,7 @@ static int msm_dp_ctrl_link_train_1(struct msm_dp_ctrl_private *ctrl,
>                 }
>
>                 msm_dp_link_adjust_levels(ctrl->link, link_status);
> -               ret = msm_dp_ctrl_update_vx_px(ctrl);
> +               ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
>                 if (ret)
>                         return ret;
>         }
> @@ -1199,21 +1217,31 @@ static int msm_dp_ctrl_link_lane_down_shift(struct msm_dp_ctrl_private *ctrl)
>         return 0;
>  }
>
> -static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl)
> +static void msm_dp_ctrl_clear_training_pattern(struct msm_dp_ctrl_private *ctrl,
> +                                              enum drm_dp_phy dp_phy)
>  {
> -       msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE);
> -       drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
> +       int delay_us;
> +
> +       msm_dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_DISABLE, dp_phy);
> +
> +       delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
> +                                               ctrl->panel->dpcd, dp_phy, false);
> +       fsleep(delay_us);
>  }
>
>  static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
> -                       int *training_step)
> +                       int *training_step, enum drm_dp_phy dp_phy)
>  {
> +       int delay_us;
>         int tries = 0, ret = 0;
>         u8 pattern;
>         u32 state_ctrl_bit;
>         int const maximum_retries = 5;
>         u8 link_status[DP_LINK_STATUS_SIZE];
>
> +       delay_us = drm_dp_read_channel_eq_delay(ctrl->aux,
> +                                               ctrl->panel->dpcd, dp_phy, false);
> +
>         msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
>
>         *training_step = DP_TRAINING_2;
> @@ -1233,12 +1261,12 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>         if (ret)
>                 return ret;
>
> -       msm_dp_ctrl_train_pattern_set(ctrl, pattern);
> +       msm_dp_ctrl_train_pattern_set(ctrl, pattern, dp_phy);
>
>         for (tries = 0; tries <= maximum_retries; tries++) {
> -               drm_dp_link_train_channel_eq_delay(ctrl->aux, ctrl->panel->dpcd);
> +               fsleep(delay_us);
>
> -               ret = drm_dp_dpcd_read_link_status(ctrl->aux, link_status);
> +               ret = drm_dp_dpcd_read_phy_link_status(ctrl->aux, dp_phy, link_status);
>                 if (ret)
>                         return ret;
>
> @@ -1248,7 +1276,7 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>                 }
>
>                 msm_dp_link_adjust_levels(ctrl->link, link_status);
> -               ret = msm_dp_ctrl_update_vx_px(ctrl);
> +               ret = msm_dp_ctrl_update_phy_vx_px(ctrl, dp_phy);
>                 if (ret)
>                         return ret;
>
> @@ -1257,9 +1285,32 @@ static int msm_dp_ctrl_link_train_2(struct msm_dp_ctrl_private *ctrl,
>         return -ETIMEDOUT;
>  }
>
> +static int msm_dp_ctrl_link_train_1_2(struct msm_dp_ctrl_private *ctrl,
> +                                     int *training_step, enum drm_dp_phy dp_phy)
> +{
> +       int ret;
> +
> +       ret = msm_dp_ctrl_link_train_1(ctrl, training_step, dp_phy);
> +       if (ret) {
> +               DRM_ERROR("link training #1 on phy %d failed. ret=%d\n", dp_phy, ret);
> +               return ret;
> +       }
> +       drm_dbg_dp(ctrl->drm_dev, "link training #1 on phy %d successful\n", dp_phy);
> +
> +       ret = msm_dp_ctrl_link_train_2(ctrl, training_step, dp_phy);
> +       if (ret) {
> +               DRM_ERROR("link training #2 on phy %d failed. ret=%d\n", dp_phy, ret);
> +               return ret;
> +       }
> +       drm_dbg_dp(ctrl->drm_dev, "link training #2 on phy %d successful\n", dp_phy);
> +
> +       return 0;
> +}
> +
>  static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
>                         int *training_step)
>  {
> +       int i;
>         int ret = 0;
>         const u8 *dpcd = ctrl->panel->dpcd;
>         u8 encoding[] = { 0, DP_SET_ANSI_8B10B };
> @@ -1272,8 +1323,6 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
>         link_info.rate = ctrl->link->link_params.rate;
>         link_info.capabilities = DP_LINK_CAP_ENHANCED_FRAMING;
>
> -       msm_dp_link_reset_phy_params_vx_px(ctrl->link);
> -
>         msm_dp_aux_link_configure(ctrl->aux, &link_info);
>
>         if (drm_dp_max_downspread(dpcd))
> @@ -1288,24 +1337,27 @@ static int msm_dp_ctrl_link_train(struct msm_dp_ctrl_private *ctrl,
>                                 &assr, 1);
>         }
>
> -       ret = msm_dp_ctrl_link_train_1(ctrl, training_step);
> +       for (i = ctrl->link->lttpr_count - 1; i >= 0; i--) {
> +               enum drm_dp_phy dp_phy = DP_PHY_LTTPR(i);
> +
> +               ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, dp_phy);
> +               msm_dp_ctrl_clear_training_pattern(ctrl, dp_phy);
> +
> +               if (ret)
> +                       break;
> +       }
> +
>         if (ret) {
> -               DRM_ERROR("link training #1 failed. ret=%d\n", ret);
> +               DRM_ERROR("link training of LTTPR(s) failed. ret=%d\n", ret);
>                 goto end;
>         }
>
> -       /* print success info as this is a result of user initiated action */
> -       drm_dbg_dp(ctrl->drm_dev, "link training #1 successful\n");
> -
> -       ret = msm_dp_ctrl_link_train_2(ctrl, training_step);
> +       ret = msm_dp_ctrl_link_train_1_2(ctrl, training_step, DP_PHY_DPRX);
>         if (ret) {
> -               DRM_ERROR("link training #2 failed. ret=%d\n", ret);
> +               DRM_ERROR("link training on sink failed. ret=%d\n", ret);
>                 goto end;
>         }
>
> -       /* print success info as this is a result of user initiated action */
> -       drm_dbg_dp(ctrl->drm_dev, "link training #2 successful\n");
> -
>  end:
>         msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, 0);
>
> @@ -1622,7 +1674,7 @@ static int msm_dp_ctrl_link_maintenance(struct msm_dp_ctrl_private *ctrl)
>         if (ret)
>                 goto end;
>
> -       msm_dp_ctrl_clear_training_pattern(ctrl);
> +       msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
>
>         msm_dp_catalog_ctrl_state_ctrl(ctrl->catalog, DP_STATE_CTRL_SEND_VIDEO);
>
> @@ -1646,7 +1698,7 @@ static bool msm_dp_ctrl_send_phy_test_pattern(struct msm_dp_ctrl_private *ctrl)
>                 return false;
>         }
>         msm_dp_catalog_ctrl_send_phy_pattern(ctrl->catalog, pattern_requested);
> -       msm_dp_ctrl_update_vx_px(ctrl);
> +       msm_dp_ctrl_update_phy_vx_px(ctrl, DP_PHY_DPRX);
>         msm_dp_link_send_test_response(ctrl->link);
>
>         pattern_sent = msm_dp_catalog_ctrl_read_phy_pattern(ctrl->catalog);
> @@ -1888,7 +1940,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
>                         }
>
>                         /* stop link training before start re training  */
> -                       msm_dp_ctrl_clear_training_pattern(ctrl);
> +                       msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
>                 }
>
>                 rc = msm_dp_ctrl_reinitialize_mainlink(ctrl);
> @@ -1912,7 +1964,7 @@ int msm_dp_ctrl_on_link(struct msm_dp_ctrl *msm_dp_ctrl)
>                  * link training failed
>                  * end txing train pattern here
>                  */
> -               msm_dp_ctrl_clear_training_pattern(ctrl);
> +               msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
>
>                 msm_dp_ctrl_deinitialize_mainlink(ctrl);
>                 rc = -ECONNRESET;
> @@ -1983,7 +2035,7 @@ int msm_dp_ctrl_on_stream(struct msm_dp_ctrl *msm_dp_ctrl, bool force_link_train
>                 msm_dp_ctrl_link_retrain(ctrl);
>
>         /* stop txing train pattern to end link training */
> -       msm_dp_ctrl_clear_training_pattern(ctrl);
> +       msm_dp_ctrl_clear_training_pattern(ctrl, DP_PHY_DPRX);
>
>         /*
>          * Set up transfer unit values and set controller state to send
> --
> 2.45.2
>

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ