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 <[email protected]>
Closes: 
https://lore.kernel.org/all/CAAMcf8D-d+5n=h44kekbsqwy42m+o32w+mo-r15vqwnyyhj...@mail.gmail.com/
Fixes: d84b087c7662 ("drm/bridge: analogix_dp: Apply DP helper APIs to get 
adjusted voltages and pre-emphasises")
Signed-off-by: Damon Ding <[email protected]>
---
 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

Reply via email to