فهرست منبع

Merge "disp: msm: dp: link training enhancements"

qctecmdr 6 سال پیش
والد
کامیت
eddbcba8a5
2فایلهای تغییر یافته به همراه103 افزوده شده و 92 حذف شده
  1. 99 92
      msm/dp/dp_ctrl.c
  2. 4 0
      msm/dp/dp_link.c

+ 99 - 92
msm/dp/dp_ctrl.c

@@ -41,6 +41,8 @@
 #define MR_LINK_CUSTOM80 0x200
 #define MR_LINK_TRAINING4  0x40
 
+#define DP_MAX_LANES 4
+
 struct dp_mst_ch_slot_info {
 	u32 start_slot;
 	u32 tot_slots;
@@ -182,35 +184,40 @@ static void dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
 		pr_warn("SEND_VIDEO time out\n");
 }
 
-static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
-		u32 voltage_level, u32 pre_emphasis_level)
+static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl)
 {
-	int i;
-	u8 buf[4];
+	int i, ret;
+	u8 buf[DP_MAX_LANES];
+	u8 v_level = ctrl->link->phy_params.v_level;
+	u8 p_level = ctrl->link->phy_params.p_level;
+	u8 size = min_t(u8, sizeof(buf), ctrl->link->link_params.lane_count);
 	u32 max_level_reached = 0;
 
-	if (voltage_level == DP_LINK_VOLTAGE_MAX) {
-		pr_debug("max. voltage swing level reached %d\n",
-				voltage_level);
-		max_level_reached |= BIT(2);
+	if (v_level == DP_LINK_VOLTAGE_MAX) {
+		pr_debug("max voltage swing level reached %d\n", v_level);
+		max_level_reached |= DP_TRAIN_MAX_SWING_REACHED;
 	}
 
-	if (pre_emphasis_level == DP_LINK_PRE_EMPHASIS_MAX) {
-		pr_debug("max. pre-emphasis level reached %d\n",
-				pre_emphasis_level);
-		max_level_reached  |= BIT(5);
+	if (p_level == DP_LINK_PRE_EMPHASIS_MAX) {
+		pr_debug("max pre-emphasis level reached %d\n", p_level);
+		max_level_reached |= DP_TRAIN_MAX_PRE_EMPHASIS_REACHED;
 	}
 
-	pre_emphasis_level <<= 3;
+	p_level <<= DP_TRAIN_PRE_EMPHASIS_SHIFT;
+
+	for (i = 0; i < size; i++)
+		buf[i] = v_level | p_level | max_level_reached;
 
-	for (i = 0; i < 4; i++)
-		buf[i] = voltage_level | pre_emphasis_level | max_level_reached;
+	pr_debug("lanes: %d, swing: 0x%x, pre-emp: 0x%x\n",
+			size, v_level, p_level);
+
+	ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
+		DP_TRAINING_LANE0_SET, buf, size);
 
-	pr_debug("sink: p|v=0x%x\n", voltage_level | pre_emphasis_level);
-	return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
+	return ret <= 0 ? -EINVAL : 0;
 }
 
-static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
+static void dp_ctrl_update_hw_vx_px(struct dp_ctrl_private *ctrl)
 {
 	struct dp_link *link = ctrl->link;
 	bool high = false;
@@ -221,21 +228,22 @@ static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
 
 	ctrl->catalog->update_vx_px(ctrl->catalog,
 		link->phy_params.v_level, link->phy_params.p_level, high);
-
-	return dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
-		link->phy_params.p_level);
 }
 
-static int dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
-		u8 pattern)
+static int dp_ctrl_update_sink_pattern(struct dp_ctrl_private *ctrl, u8 pattern)
 {
-	u8 buf[4];
+	u8 buf = pattern;
+	int ret;
 
 	pr_debug("sink: pattern=%x\n", pattern);
 
-	buf[0] = pattern;
-	return drm_dp_dpcd_write(ctrl->aux->drm_aux,
-		DP_TRAINING_PATTERN_SET, buf, 1);
+	if (pattern && pattern != DP_TRAINING_PATTERN_4)
+		buf |= DP_LINK_SCRAMBLING_DISABLE;
+
+	ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux,
+		DP_TRAINING_PATTERN_SET, buf);
+
+	return ret <= 0 ? -EINVAL : 0;
 }
 
 static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
@@ -287,10 +295,11 @@ static int dp_ctrl_lane_count_down_shift(struct dp_ctrl_private *ctrl)
 	return ret;
 }
 
-static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
+static int dp_ctrl_link_training_1(struct dp_ctrl_private *ctrl)
 {
-	int tries, old_v_level, ret = 0;
+	int tries, old_v_level, ret = -EINVAL;
 	u8 link_status[DP_LINK_STATUS_SIZE];
+	u8 pattern = 0;
 	int const maximum_retries = 5;
 
 	ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
@@ -301,42 +310,42 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
 
-	ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
-	ret = dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
-		DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
-	if (ret <= 0) {
-		ret = -EINVAL;
-		goto end;
-	}
-
-	ret = dp_ctrl_update_vx_px(ctrl);
-	if (ret <= 0) {
-		ret = -EINVAL;
-		goto end;
-	}
-
 	tries = 0;
 	old_v_level = ctrl->link->phy_params.v_level;
-	while (1) {
-		if (atomic_read(&ctrl->aborted)) {
-			ret = -EINVAL;
-			break;
+	while (!atomic_read(&ctrl->aborted)) {
+		/* update hardware with current swing/pre-emp values */
+		dp_ctrl_update_hw_vx_px(ctrl);
+
+		if (!pattern) {
+			pattern = DP_TRAINING_PATTERN_1;
+
+			ctrl->catalog->set_pattern(ctrl->catalog, pattern);
+
+			/* update sink with current settings */
+			ret = dp_ctrl_update_sink_pattern(ctrl, pattern);
+			if (ret)
+				break;
 		}
 
+		ret = dp_ctrl_update_sink_vx_px(ctrl);
+		if (ret)
+			break;
+
 		drm_dp_link_train_clock_recovery_delay(ctrl->panel->dpcd);
 
 		ret = dp_ctrl_read_link_status(ctrl, link_status);
 		if (ret)
 			break;
 
-		if (drm_dp_clock_recovery_ok(link_status,
-			ctrl->link->link_params.lane_count)) {
+		if (!drm_dp_clock_recovery_ok(link_status,
+			ctrl->link->link_params.lane_count))
+			ret = -EINVAL;
+		else
 			break;
-		}
+
 
 		if (ctrl->link->phy_params.v_level == DP_LINK_VOLTAGE_MAX) {
 			pr_err_ratelimited("max v_level reached\n");
-			ret = -EAGAIN;
 			break;
 		}
 
@@ -355,13 +364,8 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 		pr_debug("clock recovery not done, adjusting vx px\n");
 
 		ctrl->link->adjust_levels(ctrl->link, link_status);
-		ret = dp_ctrl_update_vx_px(ctrl);
-		if (ret <= 0) {
-			ret = -EINVAL;
-			break;
-		}
 	}
-end:
+
 	ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
 
 	if (ret)
@@ -400,14 +404,14 @@ static int dp_ctrl_link_rate_down_shift(struct dp_ctrl_private *ctrl)
 
 static void dp_ctrl_clear_training_pattern(struct dp_ctrl_private *ctrl)
 {
-	dp_ctrl_train_pattern_set(ctrl, 0);
+	dp_ctrl_update_sink_pattern(ctrl, 0);
 	drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
 }
 
 static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 {
-	int tries = 0, ret = 0;
-	char pattern;
+	int tries = 0, ret = -EINVAL;
+	u8 dpcd_pattern, pattern = 0;
 	int const maximum_retries = 5;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
@@ -420,32 +424,30 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 	wmb();
 
 	if (drm_dp_tps3_supported(ctrl->panel->dpcd))
-		pattern = DP_TRAINING_PATTERN_3;
+		dpcd_pattern = DP_TRAINING_PATTERN_3;
 	else
-		pattern = DP_TRAINING_PATTERN_2;
+		dpcd_pattern = DP_TRAINING_PATTERN_2;
 
-	ret = dp_ctrl_update_vx_px(ctrl);
-	if (ret <= 0) {
-		ret = -EINVAL;
-		goto end;
-	}
+	while (!atomic_read(&ctrl->aborted)) {
+		/* update hardware with current swing/pre-emp values */
+		dp_ctrl_update_hw_vx_px(ctrl);
 
-	if (pattern != DP_TRAINING_PATTERN_4)
-		pattern |= DP_LINK_SCRAMBLING_DISABLE;
+		if (!pattern) {
+			pattern = dpcd_pattern;
 
-	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
-	ret = dp_ctrl_train_pattern_set(ctrl, pattern);
-	if (ret <= 0) {
-		ret = -EINVAL;
-		goto end;
-	}
+			/* program hw to send pattern */
+			ctrl->catalog->set_pattern(ctrl->catalog, pattern);
 
-	do  {
-		if (atomic_read(&ctrl->aborted)) {
-			ret = -EINVAL;
-			break;
+			/* update sink with current pattern */
+			ret = dp_ctrl_update_sink_pattern(ctrl, pattern);
+			if (ret)
+				break;
 		}
 
+		ret = dp_ctrl_update_sink_vx_px(ctrl);
+		if (ret)
+			break;
+
 		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
 
 		ret = dp_ctrl_read_link_status(ctrl, link_status);
@@ -459,8 +461,10 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 			break;
 		}
 
-		if (drm_dp_channel_eq_ok(link_status,
+		if (!drm_dp_channel_eq_ok(link_status,
 			ctrl->link->link_params.lane_count))
+			ret = -EINVAL;
+		else
 			break;
 
 		if (tries > maximum_retries) {
@@ -470,13 +474,8 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 		tries++;
 
 		ctrl->link->adjust_levels(ctrl->link, link_status);
-		ret = dp_ctrl_update_vx_px(ctrl);
-		if (ret <= 0) {
-			ret = -EINVAL;
-			break;
-		}
-	} while (1);
-end:
+	}
+
 	ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
 
 	if (ret)
@@ -489,7 +488,7 @@ end:
 static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
 {
 	int ret = 0;
-	u8 encoding = 0x1;
+	u8 const encoding = 0x1, downspread = 0x00;
 	struct drm_dp_link link_info = {0};
 
 	ctrl->link->phy_params.p_level = 0;
@@ -504,14 +503,21 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
 	if (ret)
 		goto end;
 
-	ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
-		DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
+	ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux,
+		DP_DOWNSPREAD_CTRL, downspread);
+	if (ret <= 0) {
+		ret = -EINVAL;
+		goto end;
+	}
+
+	ret = drm_dp_dpcd_writeb(ctrl->aux->drm_aux,
+		DP_MAIN_LINK_CHANNEL_CODING_SET, encoding);
 	if (ret <= 0) {
 		ret = -EINVAL;
 		goto end;
 	}
 
-	ret = dp_ctrl_link_train_1(ctrl);
+	ret = dp_ctrl_link_training_1(ctrl);
 	if (ret) {
 		pr_err("link training #1 failed\n");
 		goto end;
@@ -862,8 +868,9 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
 	u32 pattern_sent = 0x0;
 	u32 pattern_requested = ctrl->link->phy_params.phy_test_pattern_sel;
 
-	dp_ctrl_update_vx_px(ctrl);
+	dp_ctrl_update_hw_vx_px(ctrl);
 	ctrl->catalog->send_phy_pattern(ctrl->catalog, pattern_requested);
+	dp_ctrl_update_sink_vx_px(ctrl);
 	ctrl->link->send_test_response(ctrl->link);
 
 	pattern_sent = ctrl->catalog->read_phy_pattern(ctrl->catalog);

+ 4 - 0
msm/dp/dp_link.c

@@ -1426,6 +1426,10 @@ static int dp_link_adjust_levels(struct dp_link *dp_link, u8 *link_status)
 		&& (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_2))
 		dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_1;
 
+	if ((dp_link->phy_params.p_level > DP_LINK_PRE_EMPHASIS_LEVEL_2)
+		&& (dp_link->phy_params.v_level == DP_LINK_VOLTAGE_LEVEL_1))
+		dp_link->phy_params.p_level = DP_LINK_PRE_EMPHASIS_LEVEL_2;
+
 	pr_debug("Set (VxPx): %x%x\n",
 		dp_link->phy_params.v_level, dp_link->phy_params.p_level);