summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/bridge/ti-sn65dsi86.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/ti-sn65dsi86.c')
-rw-r--r--drivers/gpu/drm/bridge/ti-sn65dsi86.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/drivers/gpu/drm/bridge/ti-sn65dsi86.c b/drivers/gpu/drm/bridge/ti-sn65dsi86.c
index ecdf9b01340f..6ca1debd0f88 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)
@@ -816,8 +834,7 @@ static void ti_sn_bridge_post_disable(struct drm_bridge *bridge)
{
struct ti_sn_bridge *pdata = bridge_to_ti_sn_bridge(bridge);
- if (pdata->refclk)
- clk_disable_unprepare(pdata->refclk);
+ clk_disable_unprepare(pdata->refclk);
pm_runtime_put_sync(pdata->dev);
}