diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c index ecdf9b01340f..c9ab9d829694 100644 --- a/drivers/gpu/drm/bridge/ti-sn65dsi86.c +++ b/drivers/gpu/drm/bridge/ti-sn65dsi86.c @@ -106,6 +106,8 @@ #define SN_NUM_GPIOS 4 #define SN_GPIO_PHYSICAL_OFFSET 1 +#define SN_LINK_TRAINING_TRIES 10 + /** * struct ti_sn_bridge - Platform data for ti-sn65dsi86 driver. * @dev: Pointer to our device. @@ -673,6 +675,7 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx, { unsigned int val; int ret; + int i; /* set dp clk frequency value */ regmap_update_bits(pdata->regmap, SN_DATARATE_CONFIG_REG, @@ -689,19 +692,34 @@ static int ti_sn_link_training(struct ti_sn_bridge *pdata, int dp_rate_idx, goto exit; } - /* Semi auto link training mode */ - regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A); - ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val, - val == ML_TX_MAIN_LINK_OFF || - val == ML_TX_NORMAL_MODE, 1000, - 500 * 1000); - if (ret) { - *last_err_str = "Training complete polling failed"; - } else if (val == ML_TX_MAIN_LINK_OFF) { - *last_err_str = "Link training failed, link is off"; - ret = -EIO; + /* + * We'll try to link train several times. As part of link training + * the bridge chip will write DP_SET_POWER_D0 to DP_SET_POWER. If + * the panel isn't ready quite it might respond NAK here which means + * we need to try again. + */ + for (i = 0; i < SN_LINK_TRAINING_TRIES; i++) { + /* Semi auto link training mode */ + regmap_write(pdata->regmap, SN_ML_TX_MODE_REG, 0x0A); + ret = regmap_read_poll_timeout(pdata->regmap, SN_ML_TX_MODE_REG, val, + val == ML_TX_MAIN_LINK_OFF || + val == ML_TX_NORMAL_MODE, 1000, + 500 * 1000); + if (ret) { + *last_err_str = "Training complete polling failed"; + } else if (val == ML_TX_MAIN_LINK_OFF) { + *last_err_str = "Link training failed, link is off"; + ret = -EIO; + continue; + } + + break; } + /* If we saw quite a few retries, add a note about it */ + if (!ret && i > SN_LINK_TRAINING_TRIES / 2) + DRM_DEV_INFO(pdata->dev, "Link training needed %d retries\n", i); + exit: /* Disable the PLL if we failed */ if (ret)