return !intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy);
 }
 
-static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp,
-                                        const struct intel_crtc_state *crtc_state,
-                                        enum drm_dp_phy dp_phy,
-                                        const u8 link_status[DP_LINK_STATUS_SIZE],
-                                        int lane)
+/* 128b/132b */
+static u8 intel_dp_get_lane_adjust_tx_ffe_preset(struct intel_dp *intel_dp,
+                                                const struct intel_crtc_state *crtc_state,
+                                                enum drm_dp_phy dp_phy,
+                                                const u8 link_status[DP_LINK_STATUS_SIZE],
+                                                int lane)
+{
+       u8 tx_ffe = 0;
+
+       if (has_per_lane_signal_levels(intel_dp, dp_phy)) {
+               lane = min(lane, crtc_state->lane_count - 1);
+               tx_ffe = drm_dp_get_adjust_tx_ffe_preset(link_status, lane);
+       } else {
+               for (lane = 0; lane < crtc_state->lane_count; lane++)
+                       tx_ffe = max(tx_ffe, drm_dp_get_adjust_tx_ffe_preset(link_status, lane));
+       }
+
+       return tx_ffe;
+}
+
+/* 8b/10b */
+static u8 intel_dp_get_lane_adjust_vswing_preemph(struct intel_dp *intel_dp,
+                                                 const struct intel_crtc_state *crtc_state,
+                                                 enum drm_dp_phy dp_phy,
+                                                 const u8 link_status[DP_LINK_STATUS_SIZE],
+                                                 int lane)
 {
        u8 v = 0;
        u8 p = 0;
        return v | p;
 }
 
+static u8 intel_dp_get_lane_adjust_train(struct intel_dp *intel_dp,
+                                        const struct intel_crtc_state *crtc_state,
+                                        enum drm_dp_phy dp_phy,
+                                        const u8 link_status[DP_LINK_STATUS_SIZE],
+                                        int lane)
+{
+       if (intel_dp_is_uhbr(crtc_state))
+               return intel_dp_get_lane_adjust_tx_ffe_preset(intel_dp, crtc_state,
+                                                             dp_phy, link_status, lane);
+       else
+               return intel_dp_get_lane_adjust_vswing_preemph(intel_dp, crtc_state,
+                                                              dp_phy, link_status, lane);
+}
+
 #define TRAIN_REQ_FMT "%d/%d/%d/%d"
 #define _TRAIN_REQ_VSWING_ARGS(link_status, lane) \
        (drm_dp_get_adjust_request_voltage((link_status), (lane)) >> DP_TRAIN_VOLTAGE_SWING_SHIFT)
        _TRAIN_REQ_PREEMPH_ARGS(link_status, 1), \
        _TRAIN_REQ_PREEMPH_ARGS(link_status, 2), \
        _TRAIN_REQ_PREEMPH_ARGS(link_status, 3)
+#define _TRAIN_REQ_TX_FFE_ARGS(link_status, lane) \
+       drm_dp_get_adjust_tx_ffe_preset((link_status), (lane))
+#define TRAIN_REQ_TX_FFE_ARGS(link_status) \
+       _TRAIN_REQ_TX_FFE_ARGS(link_status, 0), \
+       _TRAIN_REQ_TX_FFE_ARGS(link_status, 1), \
+       _TRAIN_REQ_TX_FFE_ARGS(link_status, 2), \
+       _TRAIN_REQ_TX_FFE_ARGS(link_status, 3)
 
 void
 intel_dp_get_adjust_train(struct intel_dp *intel_dp,
        char phy_name[10];
        int lane;
 
-       drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, "
-                   "vswing request: " TRAIN_REQ_FMT ", "
-                   "pre-emphasis request: " TRAIN_REQ_FMT "\n",
-                   encoder->base.base.id, encoder->base.name,
-                   intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
-                   crtc_state->lane_count,
-                   TRAIN_REQ_VSWING_ARGS(link_status),
-                   TRAIN_REQ_PREEMPH_ARGS(link_status));
+       if (intel_dp_is_uhbr(crtc_state)) {
+               drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, "
+                           "TX FFE request: " TRAIN_REQ_FMT "\n",
+                           encoder->base.base.id, encoder->base.name,
+                           intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
+                           crtc_state->lane_count,
+                           TRAIN_REQ_TX_FFE_ARGS(link_status));
+       } else {
+               drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, "
+                           "vswing request: " TRAIN_REQ_FMT ", "
+                           "pre-emphasis request: " TRAIN_REQ_FMT "\n",
+                           encoder->base.base.id, encoder->base.name,
+                           intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
+                           crtc_state->lane_count,
+                           TRAIN_REQ_VSWING_ARGS(link_status),
+                           TRAIN_REQ_PREEMPH_ARGS(link_status));
+       }
 
        for (lane = 0; lane < 4; lane++)
                intel_dp->train_set[lane] =
        _TRAIN_SET_PREEMPH_ARGS((train_set)[1]), \
        _TRAIN_SET_PREEMPH_ARGS((train_set)[2]), \
        _TRAIN_SET_PREEMPH_ARGS((train_set)[3])
+#define _TRAIN_SET_TX_FFE_ARGS(train_set) \
+       ((train_set) & DP_TX_FFE_PRESET_VALUE_MASK), ""
+#define TRAIN_SET_TX_FFE_ARGS(train_set) \
+       _TRAIN_SET_TX_FFE_ARGS((train_set)[0]), \
+       _TRAIN_SET_TX_FFE_ARGS((train_set)[1]), \
+       _TRAIN_SET_TX_FFE_ARGS((train_set)[2]), \
+       _TRAIN_SET_TX_FFE_ARGS((train_set)[3])
 
 void intel_dp_set_signal_levels(struct intel_dp *intel_dp,
                                const struct intel_crtc_state *crtc_state,
        struct drm_i915_private *i915 = to_i915(encoder->base.dev);
        char phy_name[10];
 
-       drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] lanes: %d, "
-                   "vswing levels: " TRAIN_SET_FMT ", "
-                   "pre-emphasis levels: " TRAIN_SET_FMT "\n",
-                   encoder->base.base.id, encoder->base.name,
-                   intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
-                   crtc_state->lane_count,
-                   TRAIN_SET_VSWING_ARGS(intel_dp->train_set),
-                   TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set));
+       if (intel_dp_is_uhbr(crtc_state)) {
+               drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 128b/132b, lanes: %d, "
+                           "TX FFE presets: " TRAIN_SET_FMT "\n",
+                           encoder->base.base.id, encoder->base.name,
+                           intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
+                           crtc_state->lane_count,
+                           TRAIN_SET_TX_FFE_ARGS(intel_dp->train_set));
+       } else {
+               drm_dbg_kms(&i915->drm, "[ENCODER:%d:%s][%s] 8b/10b, lanes: %d, "
+                           "vswing levels: " TRAIN_SET_FMT ", "
+                           "pre-emphasis levels: " TRAIN_SET_FMT "\n",
+                           encoder->base.base.id, encoder->base.name,
+                           intel_dp_phy_name(dp_phy, phy_name, sizeof(phy_name)),
+                           crtc_state->lane_count,
+                           TRAIN_SET_VSWING_ARGS(intel_dp->train_set),
+                           TRAIN_SET_PREEMPH_ARGS(intel_dp->train_set));
+       }
 
        if (intel_dp_phy_is_downstream_of_source(intel_dp, dp_phy))
                encoder->set_signal_levels(encoder, crtc_state);
        return ret == crtc_state->lane_count;
 }
 
+/* 128b/132b */
+static bool intel_dp_lane_max_tx_ffe_reached(u8 train_set_lane)
+{
+       return (train_set_lane & DP_TX_FFE_PRESET_VALUE_MASK) ==
+               DP_TX_FFE_PRESET_VALUE_MASK;
+}
+
 /*
+ * 8b/10b
+ *
  * FIXME: The DP spec is very confusing here, also the Link CTS spec seems to
  * have self contradicting tests around this area.
  *
        int lane;
 
        for (lane = 0; lane < crtc_state->lane_count; lane++) {
-               if (!intel_dp_lane_max_vswing_reached(intel_dp->train_set[lane]))
-                       return false;
+               u8 train_set_lane = intel_dp->train_set[lane];
+
+               if (intel_dp_is_uhbr(crtc_state)) {
+                       if (!intel_dp_lane_max_tx_ffe_reached(train_set_lane))
+                               return false;
+               } else {
+                       if (!intel_dp_lane_max_vswing_reached(train_set_lane))
+                               return false;
+               }
        }
 
        return true;
                drm_dp_lttpr_link_train_clock_recovery_delay();
 }
 
-static bool intel_dp_adjust_request_changed(int lane_count,
+static bool intel_dp_adjust_request_changed(const struct intel_crtc_state *crtc_state,
                                            const u8 old_link_status[DP_LINK_STATUS_SIZE],
                                            const u8 new_link_status[DP_LINK_STATUS_SIZE])
 {
        int lane;
 
-       for (lane = 0; lane < lane_count; lane++) {
-               u8 old = drm_dp_get_adjust_request_voltage(old_link_status, lane) |
-                       drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane);
-               u8 new = drm_dp_get_adjust_request_voltage(new_link_status, lane) |
-                       drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane);
+       for (lane = 0; lane < crtc_state->lane_count; lane++) {
+               u8 old, new;
+
+               if (intel_dp_is_uhbr(crtc_state)) {
+                       old = drm_dp_get_adjust_tx_ffe_preset(old_link_status, lane);
+                       new = drm_dp_get_adjust_tx_ffe_preset(new_link_status, lane);
+               } else {
+                       old = drm_dp_get_adjust_request_voltage(old_link_status, lane) |
+                               drm_dp_get_adjust_request_pre_emphasis(old_link_status, lane);
+                       new = drm_dp_get_adjust_request_voltage(new_link_status, lane) |
+                               drm_dp_get_adjust_request_pre_emphasis(new_link_status, lane);
+               }
 
                if (old != new)
                        return true;
                        return false;
                }
 
-               if (!intel_dp_adjust_request_changed(crtc_state->lane_count,
-                                                    old_link_status, link_status))
+               if (!intel_dp_adjust_request_changed(crtc_state, old_link_status, link_status))
                        ++voltage_tries;
                else
                        voltage_tries = 1;