[PATCH v1] drm/bridge: analogix_dp: Fix PE/VS value shift mismatch during link training
From: Damon Ding
Date: Mon Jun 22 2026 - 22:24:18 EST
The values returned by drm_dp_get_adjust_request_voltage() and
drm_dp_get_adjust_request_pre_emphasis() are raw unshifted 2-bit
values, but DPCD_*_SET macros expect them to be shifted into their
respective bit positions. Without right-shifting first, the combined
training_lane register value becomes corrupted whenever pre-emphasis
or voltage swing is non-zero, leading to failed link training and
black screen.
Add right shift by DP_TRAIN_VOLTAGE_SWING_SHIFT and
DP_TRAIN_PRE_EMPHASIS_SHIFT for both voltage swing and pre-emphasis
values before constructing training_lane, in both the adjust training
lane and clock recovery paths.
Reported-by: Vicente Bergas <vicencb@xxxxxxxxx>
Closes: https://lore.kernel.org/all/CAAMcf8D-d+5n=H44KeKBSqWY42m+o32W+mO-r15VqWNyYhJL7Q@xxxxxxxxxxxxxx/
Fixes: d84b087c7662 ("drm/bridge: analogix_dp: Apply DP helper APIs to get adjusted voltages and pre-emphasises")
Signed-off-by: Damon Ding <damon.ding@xxxxxxxxxxxxxx>
---
drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 7a85774aaac1..1d39a354c3d9 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -309,7 +309,9 @@ static void analogix_dp_get_adjust_training_lane(struct analogix_dp_device *dp,
lane_count = dp->link_train.lane_count;
for (lane = 0; lane < lane_count; lane++) {
voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
+ voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+ pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
training_lane = DPCD_VOLTAGE_SWING_SET(voltage_swing) |
DPCD_PRE_EMPHASIS_SET(pre_emphasis);
@@ -355,7 +357,9 @@ static int analogix_dp_process_clock_recovery(struct analogix_dp_device *dp)
for (lane = 0; lane < lane_count; lane++) {
training_lane = analogix_dp_get_lane_link_training(dp, lane);
voltage_swing = drm_dp_get_adjust_request_voltage(link_status, lane);
+ voltage_swing >>= DP_TRAIN_VOLTAGE_SWING_SHIFT;
pre_emphasis = drm_dp_get_adjust_request_pre_emphasis(link_status, lane);
+ pre_emphasis >>= DP_TRAIN_PRE_EMPHASIS_SHIFT;
if (DPCD_VOLTAGE_SWING_GET(training_lane) == voltage_swing &&
DPCD_PRE_EMPHASIS_GET(training_lane) == pre_emphasis)
--
2.34.1