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

Commit a4ef43a7 authored by Padmanabhan Komanduru's avatar Padmanabhan Komanduru Committed by Steve Cohen
Browse files

drm/msm/dp: handle AUX transactions during quick connect/disconnect



Handle AUX transactions graciously during when the DP cable is
disconnected while the DP On sequence is under process. This use-case
can happen when the connect/disconnect events are very quick or the
DP cable is a faulty one where the DP On sequence takes a long time
to finish due to continuous AUX timeout errors and DP cable is
disconnected during the process.

Change-Id: I4099ac714790be9357ff09fa4640859d35704ff4
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
parent dc13add7
Loading
Loading
Loading
Loading
+24 −1
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ struct dp_aux_private {
	bool no_send_stop;
	u32 offset;
	u32 segment;
	atomic_t aborted;

	struct drm_dp_aux drm_aux;
};
@@ -279,6 +280,20 @@ static void dp_aux_reconfig(struct dp_aux *dp_aux)
	aux->catalog->reset(aux->catalog);
}

static void dp_aux_abort_transaction(struct dp_aux *dp_aux)
{
	struct dp_aux_private *aux;

	if (!dp_aux) {
		pr_err("invalid input\n");
		return;
	}

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	atomic_set(&aux->aborted, 1);
}

static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
		struct drm_dp_aux_msg *input_msg)
{
@@ -377,6 +392,11 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,

	mutex_lock(&aux->mutex);

	if (atomic_read(&aux->aborted)) {
		ret = -ETIMEDOUT;
		goto unlock_exit;
	}

	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);

	/* Ignore address only message */
@@ -411,7 +431,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
	}

	ret = dp_aux_cmd_fifo_tx(aux, msg);
	if ((ret < 0) && aux->native) {
	if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) {
		aux->retry_cnt++;
		if (!(aux->retry_cnt % retry_count))
			aux->catalog->update_aux_cfg(aux->catalog,
@@ -467,6 +487,7 @@ static void dp_aux_init(struct dp_aux *dp_aux, struct dp_aux_cfg *aux_cfg)
	aux->catalog->setup(aux->catalog, aux_cfg);
	aux->catalog->reset(aux->catalog);
	aux->catalog->enable(aux->catalog, true);
	atomic_set(&aux->aborted, 0);
	aux->retry_cnt = 0;
}

@@ -481,6 +502,7 @@ static void dp_aux_deinit(struct dp_aux *dp_aux)

	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);

	atomic_set(&aux->aborted, 1);
	aux->catalog->enable(aux->catalog, false);
}

@@ -558,6 +580,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
	dp_aux->drm_aux_register = dp_aux_register;
	dp_aux->drm_aux_deregister = dp_aux_deregister;
	dp_aux->reconfig = dp_aux_reconfig;
	dp_aux->abort = dp_aux_abort_transaction;

	return dp_aux;
error:
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ struct dp_aux {
	void (*init)(struct dp_aux *aux, struct dp_aux_cfg *aux_cfg);
	void (*deinit)(struct dp_aux *aux);
	void (*reconfig)(struct dp_aux *aux);
	void (*abort)(struct dp_aux *aux);
};

struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
+47 −13
Original line number Diff line number Diff line
@@ -761,18 +761,18 @@ static int dp_ctrl_update_sink_vx_px(struct dp_ctrl_private *ctrl,
	return drm_dp_dpcd_write(ctrl->aux->drm_aux, 0x103, buf, 4);
}

static void dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
static int dp_ctrl_update_vx_px(struct dp_ctrl_private *ctrl)
{
	struct dp_link *link = ctrl->link;

	ctrl->catalog->update_vx_px(ctrl->catalog,
		link->phy_params.v_level, link->phy_params.p_level);

	dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
	return dp_ctrl_update_sink_vx_px(ctrl, link->phy_params.v_level,
		link->phy_params.p_level);
}

static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
static int dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
		u8 pattern)
{
	u8 buf[4];
@@ -780,7 +780,8 @@ static void dp_ctrl_train_pattern_set(struct dp_ctrl_private *ctrl,
	pr_debug("sink: pattern=%x\n", pattern);

	buf[0] = pattern;
	drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_TRAINING_PATTERN_SET, buf, 1);
	return drm_dp_dpcd_write(ctrl->aux->drm_aux,
		DP_TRAINING_PATTERN_SET, buf, 1);
}

static int dp_ctrl_read_link_status(struct dp_ctrl_private *ctrl,
@@ -817,9 +818,18 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
	wmb();

	ctrl->catalog->set_pattern(ctrl->catalog, 0x01);
	dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
	ret = dp_ctrl_train_pattern_set(ctrl, DP_TRAINING_PATTERN_1 |
		DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
	dp_ctrl_update_vx_px(ctrl);
	if (ret <= 0) {
		ret = -EINVAL;
		return ret;
	}

	ret = dp_ctrl_update_vx_px(ctrl);
	if (ret <= 0) {
		ret = -EINVAL;
		return ret;
	}

	tries = 0;
	old_v_level = ctrl->link->phy_params.v_level;
@@ -856,7 +866,11 @@ 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);
		dp_ctrl_update_vx_px(ctrl);
		ret = dp_ctrl_update_vx_px(ctrl);
		if (ret <= 0) {
			ret = -EINVAL;
			break;
		}
	}

	return ret;
@@ -910,9 +924,18 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
	else
		pattern = DP_TRAINING_PATTERN_2;

	dp_ctrl_update_vx_px(ctrl);
	ret = dp_ctrl_update_vx_px(ctrl);
	if (ret <= 0) {
		ret = -EINVAL;
		return ret;
	}
	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
	dp_ctrl_train_pattern_set(ctrl, pattern | DP_RECOVERED_CLOCK_OUT_EN);
	ret = dp_ctrl_train_pattern_set(ctrl,
		pattern | DP_RECOVERED_CLOCK_OUT_EN);
	if (ret <= 0) {
		ret = -EINVAL;
		return ret;
	}

	do  {
		drm_dp_link_train_channel_eq_delay(ctrl->panel->dpcd);
@@ -932,7 +955,11 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
		tries++;

		ctrl->link->adjust_levels(ctrl->link, link_status);
		dp_ctrl_update_vx_px(ctrl);
		ret = dp_ctrl_update_vx_px(ctrl);
		if (ret <= 0) {
			ret = -EINVAL;
			break;
		}
	} while (1);

	return ret;
@@ -954,9 +981,16 @@ static int dp_ctrl_link_train(struct dp_ctrl_private *ctrl)
		ctrl->link->link_params.bw_code);
	link_info.capabilities = ctrl->panel->link_info.capabilities;

	drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
	drm_dp_dpcd_write(ctrl->aux->drm_aux, DP_MAIN_LINK_CHANNEL_CODING_SET,
				&encoding, 1);
	ret = drm_dp_link_configure(ctrl->aux->drm_aux, &link_info);
	if (ret)
		goto end;

	ret = drm_dp_dpcd_write(ctrl->aux->drm_aux,
		DP_MAIN_LINK_CHANNEL_CODING_SET, &encoding, 1);
	if (ret <= 0) {
		ret = -EINVAL;
		goto end;
	}

	ret = dp_ctrl_link_train_1(ctrl);
	if (ret) {
+15 −4
Original line number Diff line number Diff line
@@ -455,6 +455,8 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
		/* cancel any pending request */
		dp->ctrl->abort(dp->ctrl);
		dp->aux->abort(dp->aux);

		return -EINVAL;
	}

@@ -474,8 +476,14 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
	}

	rc = dp->panel->read_sink_caps(dp->panel, dp->dp_display.connector);
	if (rc)
	if (rc) {
		if (rc == -ETIMEDOUT) {
			pr_err("Sink cap read failed, skip notification\n");
			goto end;
		} else {
			goto notify;
		}
	}

	dp->link->process_request(dp->link);

@@ -636,6 +644,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)

	/* cancel any pending request */
	dp->ctrl->abort(dp->ctrl);
	dp->aux->abort(dp->aux);

	/* wait for idle state */
	flush_workqueue(dp->wq);
@@ -715,6 +724,7 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
	} else {
		/* cancel any pending request */
		dp->ctrl->abort(dp->ctrl);
		dp->aux->abort(dp->aux);

		/* wait for idle state */
		flush_workqueue(dp->wq);
@@ -945,6 +955,8 @@ static int dp_display_enable(struct dp_display *dp_display)
		goto end;
	}

	dp->aux->init(dp->aux, dp->parser->aux_cfg);

	rc = dp->ctrl->on(dp->ctrl);

	if (dp->debug->tpg_state)
@@ -983,8 +995,6 @@ static int dp_display_post_enable(struct dp_display *dp_display)
		dp->audio->on(dp->audio);
	}

	complete_all(&dp->notification_comp);

	dp_display_update_hdcp_info(dp);

	if (dp_display_is_hdcp_enabled(dp)) {
@@ -995,6 +1005,7 @@ static int dp_display_post_enable(struct dp_display *dp_display)
	}

end:
	complete_all(&dp->notification_comp);
	mutex_unlock(&dp->session_lock);
	return 0;
}
+20 −27
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ struct dp_panel_private {
	struct dp_aux *aux;
	struct dp_link *link;
	struct dp_catalog_panel *catalog;
	bool aux_cfg_update_done;
	bool custom_edid;
	bool custom_dpcd;
	bool panel_on;
@@ -86,7 +85,11 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
			dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
		if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
			pr_err("dpcd read failed, rlen=%d\n", rlen);
			if (rlen == -ETIMEDOUT)
				rc = rlen;
			else
				rc = -EINVAL;

			goto end;
		}

@@ -202,8 +205,6 @@ static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd)
static int dp_panel_read_edid(struct dp_panel *dp_panel,
	struct drm_connector *connector)
{
	int retry_cnt = 0;
	const int max_retry = 10;
	struct dp_panel_private *panel;

	if (!dp_panel) {
@@ -218,24 +219,19 @@ static int dp_panel_read_edid(struct dp_panel *dp_panel,
		return 0;
	}

	do {
	sde_get_edid(connector, &panel->aux->drm_aux->ddc,
		(void **)&dp_panel->edid_ctrl);
	if (!dp_panel->edid_ctrl->edid) {
		pr_err("EDID read failed\n");
			retry_cnt++;
			panel->aux->reconfig(panel->aux);
			panel->aux_cfg_update_done = true;
	} else {
		u8 *buf = (u8 *)dp_panel->edid_ctrl->edid;
			u32 size = buf[0x7F] ? 256 : 128;
		u32 size = buf[0x7E] ? 256 : 128;

		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK EDID: ",
			DUMP_PREFIX_NONE, 16, 1, buf, size, false);

		return 0;
	}
	} while (retry_cnt < max_retry);

	return -EINVAL;
}
@@ -259,6 +255,10 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
		dp_panel->link_info.num_lanes) ||
		((drm_dp_link_rate_to_bw_code(dp_panel->link_info.rate)) >
		dp_panel->max_bw_code)) {
		if ((rc == -ETIMEDOUT) || (rc == -ENODEV)) {
			pr_err("DPCD read failed, return early\n");
			return rc;
		}
		pr_err("panel dpcd read failed/incorrect, set default params\n");
		dp_panel_set_default_link_params(dp_panel);
	}
@@ -269,12 +269,6 @@ static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
		return rc;
	}

	if (panel->aux_cfg_update_done) {
		pr_debug("read DPCD with updated AUX config\n");
		dp_panel_read_dpcd(dp_panel);
		panel->aux_cfg_update_done = false;
	}

	return 0;
}

@@ -766,7 +760,6 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	panel->link = in->link;

	dp_panel = &panel->dp_panel;
	panel->aux_cfg_update_done = false;
	dp_panel->max_bw_code = DP_LINK_BW_8_1;
	dp_panel->spd_enabled = true;
	memcpy(panel->spd_vendor_name, vendor_name, (sizeof(u8) * 8));