Merge tag 'drm-misc-next-fixes-2021-09-09' of git://anongit.freedesktop.org/drm/drm...
[linux-2.6-microblaze.git] / drivers / gpu / drm / msm / dp / dp_ctrl.c
index ee221d8..62e75dc 100644 (file)
@@ -81,13 +81,6 @@ struct dp_ctrl_private {
        struct completion video_comp;
 };
 
-struct dp_cr_status {
-       u8 lane_0_1;
-       u8 lane_2_3;
-};
-
-#define DP_LANE0_1_CR_DONE     0x11
-
 static int dp_aux_link_configure(struct drm_dp_aux *aux,
                                        struct dp_link_info *link)
 {
@@ -120,7 +113,7 @@ void dp_ctrl_push_idle(struct dp_ctrl *dp_ctrl)
                        IDLE_PATTERN_COMPLETION_TIMEOUT_JIFFIES))
                pr_warn("PUSH_IDLE pattern timedout\n");
 
-       pr_debug("mainlink off done\n");
+       DRM_DEBUG_DP("mainlink off done\n");
 }
 
 static void dp_ctrl_config_ctrl(struct dp_ctrl_private *ctrl)
@@ -1011,6 +1004,8 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
        u32 voltage_swing_level = link->phy_params.v_level;
        u32 pre_emphasis_level = link->phy_params.p_level;
 
+       DRM_DEBUG_DP("voltage level: %d emphasis level: %d\n", voltage_swing_level,
+                       pre_emphasis_level);
        ret = dp_catalog_ctrl_update_vx_px(ctrl->catalog,
                voltage_swing_level, pre_emphasis_level);
 
@@ -1078,7 +1073,7 @@ static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
 }
 
 static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl,
-               struct dp_cr_status *cr, int *training_step)
+                       int *training_step)
 {
        int tries, old_v_level, ret = 0;
        u8 link_status[DP_LINK_STATUS_SIZE];
@@ -1107,9 +1102,6 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl,
                if (ret)
                        return ret;
 
-               cr->lane_0_1 = link_status[0];
-               cr->lane_2_3 = link_status[1];
-
                if (drm_dp_clock_recovery_ok(link_status,
                        ctrl->link->link_params.num_lanes)) {
                        return 0;
@@ -1186,7 +1178,7 @@ static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
 }
 
 static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
-               struct dp_cr_status *cr, int *training_step)
+                       int *training_step)
 {
        int tries = 0, ret = 0;
        char pattern;
@@ -1202,10 +1194,6 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
        else
                pattern = DP_TRAINING_PATTERN_2;
 
-       ret = dp_ctrl_update_vx_px(ctrl);
-       if (ret)
-               return ret;
-
        ret = dp_catalog_ctrl_set_pattern(ctrl->catalog, pattern);
        if (ret)
                return ret;
@@ -1218,8 +1206,6 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
                ret = dp_ctrl_read_link_status(ctrl, link_status);
                if (ret)
                        return ret;
-               cr->lane_0_1 = link_status[0];
-               cr->lane_2_3 = link_status[1];
 
                if (drm_dp_channel_eq_ok(link_status,
                        ctrl->link->link_params.num_lanes)) {
@@ -1239,7 +1225,7 @@ static int dp_ctrl_link_train_2(struct dp_ctrl_private *ctrl,
 static int dp_ctrl_reinitialize_mainlink(struct dp_ctrl_private *ctrl);
 
 static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
-               struct dp_cr_status *cr, int *training_step)
+                       int *training_step)
 {
        int ret = 0;
        u8 encoding = DP_SET_ANSI_8B10B;
@@ -1255,7 +1241,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
        drm_dp_dpcd_write(ctrl->aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
                                &encoding, 1);
 
-       ret = dp_ctrl_link_train_1(ctrl, cr, training_step);
+       ret = dp_ctrl_link_train_1(ctrl, training_step);
        if (ret) {
                DRM_ERROR("link training #1 failed. ret=%d\n", ret);
                goto end;
@@ -1264,7 +1250,7 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl,
        /* print success info as this is a result of user initiated action */
        DRM_DEBUG_DP("link training #1 successful\n");
 
-       ret = dp_ctrl_link_train_2(ctrl, cr, training_step);
+       ret = dp_ctrl_link_train_2(ctrl, training_step);
        if (ret) {
                DRM_ERROR("link training #2 failed. ret=%d\n", ret);
                goto end;
@@ -1280,7 +1266,7 @@ end:
 }
 
 static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
-               struct dp_cr_status *cr, int *training_step)
+                       int *training_step)
 {
        int ret = 0;
 
@@ -1295,7 +1281,7 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl,
         * a link training pattern, we have to first do soft reset.
         */
 
-       ret = dp_ctrl_link_train(ctrl, cr, training_step);
+       ret = dp_ctrl_link_train(ctrl, training_step);
 
        return ret;
 }
@@ -1382,6 +1368,7 @@ int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
        if (reset)
                dp_catalog_ctrl_reset(ctrl->catalog);
 
+       DRM_DEBUG_DP("flip=%d\n", flip);
        dp_catalog_ctrl_phy_reset(ctrl->catalog);
        phy_init(phy);
        dp_catalog_ctrl_enable_irq(ctrl->catalog, true);
@@ -1492,14 +1479,16 @@ static int dp_ctrl_deinitialize_mainlink(struct dp_ctrl_private *ctrl)
 static int dp_ctrl_link_maintenance(struct dp_ctrl_private *ctrl)
 {
        int ret = 0;
-       struct dp_cr_status cr;
        int training_step = DP_TRAINING_NONE;
 
        dp_ctrl_push_idle(&ctrl->dp_ctrl);
 
+       ctrl->link->phy_params.p_level = 0;
+       ctrl->link->phy_params.v_level = 0;
+
        ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
 
-       ret = dp_ctrl_setup_main_link(ctrl, &cr, &training_step);
+       ret = dp_ctrl_setup_main_link(ctrl, &training_step);
        if (ret)
                goto end;
 
@@ -1526,7 +1515,7 @@ static int dp_ctrl_process_phy_test_request(struct dp_ctrl_private *ctrl)
         * running. Add the global reset just before disabling the
         * link clocks and core clocks.
         */
-       ret = dp_ctrl_off(&ctrl->dp_ctrl);
+       ret = dp_ctrl_off_link_stream(&ctrl->dp_ctrl);
        if (ret) {
                DRM_ERROR("failed to disable DP controller\n");
                return ret;
@@ -1630,6 +1619,35 @@ void dp_ctrl_handle_sink_request(struct dp_ctrl *dp_ctrl)
        }
 }
 
+static bool dp_ctrl_clock_recovery_any_ok(
+                       const u8 link_status[DP_LINK_STATUS_SIZE],
+                       int lane_count)
+{
+       int reduced_cnt;
+
+       if (lane_count <= 1)
+               return false;
+
+       /*
+        * only interested in the lane number after reduced
+        * lane_count = 4, then only interested in 2 lanes
+        * lane_count = 2, then only interested in 1 lane
+        */
+       reduced_cnt = lane_count >> 1;
+
+       return drm_dp_clock_recovery_ok(link_status, reduced_cnt);
+}
+
+static bool dp_ctrl_channel_eq_ok(struct dp_ctrl_private *ctrl)
+{
+       u8 link_status[DP_LINK_STATUS_SIZE];
+       int num_lanes = ctrl->link->link_params.num_lanes;
+
+       dp_ctrl_read_link_status(ctrl, link_status);
+
+       return drm_dp_channel_eq_ok(link_status, num_lanes);
+}
+
 int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
 {
        int rc = 0;
@@ -1637,7 +1655,7 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
        u32 rate = 0;
        int link_train_max_retries = 5;
        u32 const phy_cts_pixel_clk_khz = 148500;
-       struct dp_cr_status cr;
+       u8 link_status[DP_LINK_STATUS_SIZE];
        unsigned int training_step;
 
        if (!dp_ctrl)
@@ -1664,6 +1682,9 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
                ctrl->link->link_params.rate,
                ctrl->link->link_params.num_lanes, ctrl->dp_ctrl.pixel_rate);
 
+       ctrl->link->phy_params.p_level = 0;
+       ctrl->link->phy_params.v_level = 0;
+
        rc = dp_ctrl_enable_mainlink_clocks(ctrl);
        if (rc)
                return rc;
@@ -1677,19 +1698,21 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
                }
 
                training_step = DP_TRAINING_NONE;
-               rc = dp_ctrl_setup_main_link(ctrl, &cr, &training_step);
+               rc = dp_ctrl_setup_main_link(ctrl, &training_step);
                if (rc == 0) {
                        /* training completed successfully */
                        break;
                } else if (training_step == DP_TRAINING_1) {
                        /* link train_1 failed */
-                       if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+                       if (!dp_catalog_link_is_connected(ctrl->catalog))
                                break;
-                       }
+
+                       dp_ctrl_read_link_status(ctrl, link_status);
 
                        rc = dp_ctrl_link_rate_down_shift(ctrl);
                        if (rc < 0) { /* already in RBR = 1.6G */
-                               if (cr.lane_0_1 & DP_LANE0_1_CR_DONE) {
+                               if (dp_ctrl_clock_recovery_any_ok(link_status,
+                                       ctrl->link->link_params.num_lanes)) {
                                        /*
                                         * some lanes are ready,
                                         * reduce lane number
@@ -1705,12 +1728,18 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
                                }
                        }
                } else if (training_step == DP_TRAINING_2) {
-                       /* link train_2 failed, lower lane rate */
-                       if (!dp_catalog_link_is_connected(ctrl->catalog)) {
+                       /* link train_2 failed */
+                       if (!dp_catalog_link_is_connected(ctrl->catalog))
                                break;
-                       }
 
-                       rc = dp_ctrl_link_lane_down_shift(ctrl);
+                       dp_ctrl_read_link_status(ctrl, link_status);
+
+                       if (!drm_dp_clock_recovery_ok(link_status,
+                                       ctrl->link->link_params.num_lanes))
+                               rc = dp_ctrl_link_rate_down_shift(ctrl);
+                       else
+                               rc = dp_ctrl_link_lane_down_shift(ctrl);
+
                        if (rc < 0) {
                                /* end with failure */
                                break; /* lane == 1 already */
@@ -1721,17 +1750,19 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
        if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
                return rc;
 
-       /* stop txing train pattern */
-       dp_ctrl_clear_training_pattern(ctrl);
+       if (rc == 0) {  /* link train successfully */
+               /*
+                * do not stop train pattern here
+                * stop link training at on_stream
+                * to pass compliance test
+                */
+       } else  {
+               /*
+                * link training failed
+                * end txing train pattern here
+                */
+               dp_ctrl_clear_training_pattern(ctrl);
 
-       /*
-        * keep transmitting idle pattern until video ready
-        * to avoid main link from loss of sync
-        */
-       if (rc == 0)  /* link train successfully */
-               dp_ctrl_push_idle(dp_ctrl);
-       else  {
-               /* link training failed */
                dp_ctrl_deinitialize_mainlink(ctrl);
                rc = -ECONNRESET;
        }
@@ -1739,9 +1770,15 @@ int dp_ctrl_on_link(struct dp_ctrl *dp_ctrl)
        return rc;
 }
 
+static int dp_ctrl_link_retrain(struct dp_ctrl_private *ctrl)
+{
+       int training_step = DP_TRAINING_NONE;
+
+       return dp_ctrl_setup_main_link(ctrl, &training_step);
+}
+
 int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
 {
-       u32 rate = 0;
        int ret = 0;
        bool mainlink_ready = false;
        struct dp_ctrl_private *ctrl;
@@ -1751,10 +1788,6 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
 
        ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);
 
-       rate = ctrl->panel->link_info.rate;
-
-       ctrl->link->link_params.rate = rate;
-       ctrl->link->link_params.num_lanes = ctrl->panel->link_info.num_lanes;
        ctrl->dp_ctrl.pixel_rate = ctrl->panel->dp_mode.drm_mode.clock;
 
        DRM_DEBUG_DP("rate=%d, num_lanes=%d, pixel_rate=%d\n",
@@ -1769,6 +1802,12 @@ int dp_ctrl_on_stream(struct dp_ctrl *dp_ctrl)
                }
        }
 
+       if (!dp_ctrl_channel_eq_ok(ctrl))
+               dp_ctrl_link_retrain(ctrl);
+
+       /* stop txing train pattern to end link training */
+       dp_ctrl_clear_training_pattern(ctrl);
+
        ret = dp_ctrl_enable_stream_clocks(ctrl);
        if (ret) {
                DRM_ERROR("Failed to start pixel clocks. ret=%d\n", ret);