Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit bc55da98 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar Committed by Divya Sharma
Browse files

drm/msm/dp: do not toggle clocks for link maintenance



If the link maintenance request is received from sink
after video stream has been activated, re-do link
training without switching off/on the link and stream
clocks. Toggling clocks while an active stream is going
on results in V-sync timeout and may result in an unstable
display engine. As DisplayPort controller can handle
dynamic switching between video stream and link patterns
without interrupting V-sync, complete link training without
toggling clocks.

CRs-Fixed: 2309587
Change-Id: Iba8d1efb7041e9c82e08d9ba3e2aa82700e24d1c
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 9e61b769
Loading
Loading
Loading
Loading
+28 −25
Original line number Diff line number Diff line
@@ -128,10 +128,8 @@ static void dp_ctrl_push_idle(struct dp_ctrl_private *ctrl,
	int const idle_pattern_completion_timeout_ms = HZ / 10;
	u32 state = 0x0;

	if (!ctrl->power_on) {
		pr_err("CTRL off, return\n");
	if (!ctrl->power_on)
		return;
	}

	if (!ctrl->mst_mode) {
		state = ST_PUSH_IDLE;
@@ -463,8 +461,6 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
	ctrl->link->phy_params.p_level = 0;
	ctrl->link->phy_params.v_level = 0;

	ctrl->catalog->config_ctrl(ctrl->catalog);

	link_info.num_lanes = ctrl->link->link_params.lane_count;
	link_info.rate = drm_dp_bw_code_to_link_rate(
		ctrl->link->link_params.bw_code);
@@ -512,8 +508,6 @@ static int dp_ctrl_setup_main_link(struct dp_ctrl_private *ctrl)
{
	int ret = 0;

	ctrl->catalog->mainlink_ctrl(ctrl->catalog, true);

	if (ctrl->link->sink_request & DP_TEST_LINK_PHY_TEST_PATTERN)
		goto end;

@@ -587,7 +581,7 @@ static int dp_ctrl_link_setup(struct dp_ctrl_private *ctrl)
	catalog->phy_lane_cfg(catalog, ctrl->orientation,
				link_params->lane_count);

	while (--link_train_max_retries || !atomic_read(&ctrl->aborted)) {
	while (--link_train_max_retries && !atomic_read(&ctrl->aborted)) {
		pr_debug("bw_code=%d, lane_count=%d\n",
			link_params->bw_code, link_params->lane_count);

@@ -714,6 +708,11 @@ static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)
	pr_debug("Host deinitialized successfully\n");
}

static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl)
{
	ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
}

static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
{
	int ret = 0;
@@ -726,25 +725,31 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

	if (!ctrl->power_on || atomic_read(&ctrl->aborted)) {
		pr_err("CTRL off, return\n");
	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;

	if (!ctrl->power_on) {
		pr_err("ctrl off\n");
		ret = -EINVAL;
		goto end;
	}

	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;

	ctrl->catalog->reset(ctrl->catalog);
	dp_ctrl_disable_link_clock(ctrl);
	ret = dp_ctrl_link_setup(ctrl);
	if (atomic_read(&ctrl->aborted))
		goto end;

	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
	ret = dp_ctrl_setup_main_link(ctrl);
	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
	if (ret)

	if (ret) {
		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
	else
		goto end;
	}

	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;

	dp_ctrl_send_video(ctrl);
	ret = dp_ctrl_wait4video_ready(ctrl);
end:
	return ret;
}
@@ -841,11 +846,6 @@ static void dp_ctrl_send_phy_test_pattern(struct dp_ctrl_private *ctrl)
			dp_link_get_phy_test_pattern(pattern_requested));
}

static void dp_ctrl_send_video(struct dp_ctrl_private *ctrl)
{
	ctrl->catalog->state_ctrl(ctrl->catalog, ST_SEND_VIDEO);
}

static void dp_ctrl_mst_calculate_rg(struct dp_ctrl_private *ctrl,
		struct dp_panel *panel, u32 *p_x_int, u32 *p_y_frac_enum)
{
@@ -1077,6 +1077,9 @@ static void dp_ctrl_stream_off(struct dp_ctrl *dp_ctrl, struct dp_panel *panel)

	ctrl = container_of(dp_ctrl, struct dp_ctrl_private, dp_ctrl);

	if (!ctrl->power_on)
		return;

	panel->hw_cfg(panel, false);

	dp_ctrl_disable_stream_clocks(ctrl, panel);
+29 −67
Original line number Diff line number Diff line
@@ -848,37 +848,40 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	return rc;
}

static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
static void dp_display_stream_disable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	int idx;
	struct dp_panel *dp_panel;

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;

		dp_panel = dp->active_panels[idx];
	if (!dp->active_stream_cnt) {
		pr_err("invalid active_stream_cnt (%d)\n");
		return;
	}

		if (dp_panel->audio_supported)
			dp_panel->audio->off(dp_panel->audio);
	pr_debug("stream_id=%d, active_stream_cnt=%d\n",
			dp_panel->stream_id, dp->active_stream_cnt);

		dp->ctrl->stream_pre_off(dp->ctrl, dp_panel);
	dp->ctrl->stream_off(dp->ctrl, dp_panel);
	dp->active_panels[dp_panel->stream_id] = NULL;
	dp->active_stream_cnt--;
}

	dp->ctrl->link_maintenance(dp->ctrl);

	for (idx = DP_STREAM_0; idx < DP_STREAM_MAX; idx++) {
		if (!dp->active_panels[idx])
			continue;
static int dp_display_stream_enable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	int rc = 0;

		dp_panel = dp->active_panels[idx];
	rc = dp->ctrl->stream_on(dp->ctrl, dp_panel);

		dp->ctrl->stream_on(dp->ctrl, dp_panel);
	if (dp->debug->tpg_state)
		dp_panel->tpg_config(dp_panel, true);

		if (dp_panel->audio_supported)
			dp_panel->audio->on(dp_panel->audio);
	if (!rc) {
		dp->active_panels[dp_panel->stream_id] = dp_panel;
		dp->active_stream_cnt++;
	}

	pr_debug("dp active_stream_cnt:%d\n", dp->active_stream_cnt);

	return rc;
}

static void dp_display_mst_attention(struct dp_display_private *dp)
@@ -922,12 +925,12 @@ static void dp_display_attention_work(struct work_struct *work)

	if (dp->link->sink_request & DP_TEST_LINK_TRAINING) {
		dp->link->send_test_response(dp->link);
		dp_display_handle_maintenance_req(dp);
		dp->ctrl->link_maintenance(dp->ctrl);
		goto mst_attention;
	}

	if (dp->link->sink_request & DP_LINK_STATUS_UPDATED)
		dp_display_handle_maintenance_req(dp);
		dp->ctrl->link_maintenance(dp->ctrl);

	if (dp_display_is_hdcp_enabled(dp) && dp->hdcp.ops->cp_irq)
		dp->hdcp.ops->cp_irq(dp->hdcp.data);
@@ -1340,26 +1343,6 @@ static int dp_display_set_stream_info(struct dp_display *dp_display,
	return rc;
}

static int dp_display_stream_enable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	int rc = 0;

	rc = dp->ctrl->stream_on(dp->ctrl, dp_panel);

	if (dp->debug->tpg_state)
		dp_panel->tpg_config(dp_panel, true);

	if (!rc) {
		dp->active_panels[dp_panel->stream_id] = dp_panel;
		dp->active_stream_cnt++;
	}

	pr_debug("dp active_stream_cnt:%d\n", dp->active_stream_cnt);

	return rc;
}

static int dp_display_enable(struct dp_display *dp_display, void *panel)
{
	int rc = 0;
@@ -1374,13 +1357,8 @@ static int dp_display_enable(struct dp_display *dp_display, void *panel)

	mutex_lock(&dp->session_lock);

	if (atomic_read(&dp->aborted)) {
		pr_err("aborted\n");
		goto end;
	}

	if (!dp_display_is_ready(dp) || !dp->core_initialized) {
		pr_err("display not ready\n");
	if (!dp->core_initialized) {
		pr_err("host not initialized\n");
		goto end;
	}

@@ -1511,22 +1489,6 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)
	return 0;
}

static void dp_display_stream_disable(struct dp_display_private *dp,
			struct dp_panel *dp_panel)
{
	if (!dp->active_stream_cnt) {
		pr_err("invalid active_stream_cnt (%d)\n");
		return;
	}

	pr_debug("stream_id=%d, active_stream_cnt=%d\n",
			dp_panel->stream_id, dp->active_stream_cnt);

	dp->ctrl->stream_off(dp->ctrl, dp_panel);
	dp->active_panels[dp_panel->stream_id] = NULL;
	dp->active_stream_cnt--;
}

static int dp_display_disable(struct dp_display *dp_display, void *panel)
{
	struct dp_display_private *dp = NULL;