0, 1620, 2160, 2430, 2700, 3240, 4320, 5400
 };
 
-static void ti_sn_bridge_set_dp_rate(struct ti_sn_bridge *pdata)
+static int ti_sn_bridge_calc_min_dp_rate_idx(struct ti_sn_bridge *pdata)
 {
        unsigned int bit_rate_khz, dp_rate_mhz;
        unsigned int i;
                if (ti_sn_bridge_dp_rate_lut[i] > dp_rate_mhz)
                        break;
 
-       regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
-                          DP_DATARATE_MASK, DP_DATARATE(i));
+       return i;
+}
+
+static int ti_sn_bridge_get_max_dp_rate_idx(struct ti_sn_bridge *pdata)
+{
+       u8 data;
+       int ret;
+
+       ret = drm_dp_dpcd_readb(&pdata->aux, DP_MAX_LINK_RATE, &data);
+       if (ret != 1) {
+               DRM_DEV_ERROR(pdata->dev,
+                             "Can't read max rate (%d); assuming 5.4 GHz\n",
+                             ret);
+               return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
+       }
+
+       /*
+        * Return an index into ti_sn_bridge_dp_rate_lut.  Just hardcode
+        * these indicies since it's not like the register spec is ever going
+        * to change and a loop would just be more complicated.  Apparently
+        * the DP sink can only return these few rates as supported even
+        * though the bridge allows some rates in between.
+        */
+       switch (data) {
+       case DP_LINK_BW_1_62:
+               return 1;
+       case DP_LINK_BW_2_7:
+               return 4;
+       case DP_LINK_BW_5_4:
+               return 7;
+       }
+
+       DRM_DEV_ERROR(pdata->dev,
+                     "Unexpected max data rate (%#x); assuming 5.4 GHz\n",
+                     (int)data);
+       return ARRAY_SIZE(ti_sn_bridge_dp_rate_lut) - 1;
 }
 
 static void ti_sn_bridge_set_video_timings(struct ti_sn_bridge *pdata)
        return data & DP_LANE_COUNT_MASK;
 }
 
-static int ti_sn_link_training(struct ti_sn_bridge *pdata)
+static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx,
+                              const char **last_err_str)
 {
        unsigned int val;
        int ret;
 
        /* set dp clk frequency value */
-       ti_sn_bridge_set_dp_rate(pdata);
+       regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG,
+                          DP_DATARATE_MASK, DP_DATARATE(dp_rate_idx));
 
        /* enable DP PLL */
        regmap_write(pdata->regmap, SN_PLL_ENABLE_REG, 1);
                                       val & DPPLL_SRC_DP_PLL_LOCK, 1000,
                                       50 * 1000);
        if (ret) {
-               DRM_ERROR("DP_PLL_LOCK polling failed (%d)\n", ret);
+               *last_err_str = "DP_PLL_LOCK polling failed";
                goto exit;
        }
 
                                       val == ML_TX_NORMAL_MODE, 1000,
                                       500 * 1000);
        if (ret) {
-               DRM_ERROR("Training complete polling failed (%d)\n", ret);
+               *last_err_str = "Training complete polling failed";
        } else if (val == ML_TX_MAIN_LINK_OFF) {
-               DRM_ERROR("Link training failed, link is off\n");
+               *last_err_str = "Link training failed, link is off";
                ret = -EIO;
        }
 
 static void ti_sn_bridge_enable(struct drm_bridge *bridge)
 {
        struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
+       const char *last_err_str = "No supported DP rate";
+       int dp_rate_idx;
+       int max_dp_rate_idx;
        unsigned int val;
-       int ret;
+       int ret = -EINVAL;
 
        /*
         * Run with the maximum number of lanes that the DP sink supports.
        regmap_update_bits(pdata->regmap, SN_SSC_CONFIG_REG, DP_NUM_LANES_MASK,
                           val);
 
-       ret = ti_sn_link_training(pdata);
-       if (ret)
+       /* Train until we run out of rates */
+       max_dp_rate_idx = ti_sn_bridge_get_max_dp_rate_idx(pdata);
+       for (dp_rate_idx = ti_sn_bridge_calc_min_dp_rate_idx(pdata);
+            dp_rate_idx <= max_dp_rate_idx;
+            dp_rate_idx++) {
+               ret = ti_sn_link_training(pdata, dp_rate_idx, &last_err_str);
+               if (!ret)
+                       break;
+       }
+       if (ret) {
+               DRM_DEV_ERROR(pdata->dev, "%s (%d)\n", last_err_str, ret);
                return;
+       }
 
        /* config video parameters */
        ti_sn_bridge_set_video_timings(pdata);