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

Commit 7bf08e98 authored by Padmanabhan Komanduru's avatar Padmanabhan Komanduru Committed by Tatenda Chipeperekwa
Browse files

drm: msm: dp: add support for HPD notification to userspace



Add change to notify hot plug event to the userspace using the
uevent based mechanism present in DRM framework. Add change to
ensure proper teardown sequence for Display Port to come up on
subsequent plug events.

Change-Id: I856955ed11f4e0bdbc4981e7095f0db62f875276
Signed-off-by: default avatarPadmanabhan Komanduru <pkomandu@codeaurora.org>
parent 1447fbb9
Loading
Loading
Loading
Loading
+10 −64
Original line number Diff line number Diff line
@@ -66,12 +66,7 @@ struct dp_ctrl_private {
	struct completion video_comp;
	struct completion irq_comp;

	bool hpd_irq_on;
	bool power_on;
	bool sink_info_read;
	bool cont_splash;
	bool psm_enabled;
	bool initialized;
	bool orientation;

	u32 pixel_rate;
@@ -712,9 +707,6 @@ static int dp_ctrl_wait4video_ready(struct dp_ctrl_private *ctrl)
{
	int ret = 0;

	if (ctrl->cont_splash)
		return ret;

	ret = wait_for_completion_timeout(&ctrl->video_comp, HZ / 2);
	if (ret <= 0) {
		pr_err("Link Train timedout\n");
@@ -1072,11 +1064,6 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)

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

	if (ctrl->initialized) {
		pr_debug("host init done already\n");
		return 0;
	}

	ctrl->orientation = flip;
	catalog = ctrl->catalog;

@@ -1084,8 +1071,6 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip)
	catalog->phy_reset(ctrl->catalog);
	catalog->enable_irq(ctrl->catalog, true);

	ctrl->initialized = true;

	return 0;
}

@@ -1107,11 +1092,6 @@ static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)

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

	if (!ctrl->initialized) {
		pr_debug("host deinit done already\n");
		return;
	}

	ctrl->catalog->enable_irq(ctrl->catalog, false);
	ctrl->catalog->reset(ctrl->catalog);

@@ -1120,7 +1100,6 @@ static void dp_ctrl_host_deinit(struct dp_ctrl *dp_ctrl)

	dp_ctrl_disable_mainlink_clocks(ctrl);

	ctrl->initialized = false;
	pr_debug("Host deinitialized successfully\n");
}

@@ -1154,8 +1133,6 @@ static int dp_ctrl_on_irq(struct dp_ctrl_private *ctrl, bool lt_needed)

		reinit_completion(&ctrl->idle_comp);

		ctrl->power_on = true;

		if (ctrl->psm_enabled) {
			ret = ctrl->link->send_psm_request(ctrl->link, false);
			if (ret) {
@@ -1175,9 +1152,6 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)
{
	int ret = 0;

	if (ctrl->cont_splash)
		goto link_training;

	ctrl->power->clk_enable(ctrl->power, DP_CORE_PM, true);
	ctrl->catalog->hpd_config(ctrl->catalog, true);

@@ -1202,28 +1176,18 @@ static int dp_ctrl_on_hpd(struct dp_ctrl_private *ctrl)

	if (ctrl->psm_enabled)
		ret = ctrl->link->send_psm_request(ctrl->link, false);
link_training:
	ctrl->power_on = true;

	while (-EAGAIN == dp_ctrl_setup_main_link(ctrl, true))
		pr_debug("MAIN LINK TRAINING RETRY\n");

	ctrl->cont_splash = 0;

	ctrl->power_on = true;
	pr_debug("End-\n");

exit:
	return ret;
}

static int dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
static void dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)
{
	if (!ctrl->power_on) {
		pr_debug("ctrl already powered off\n");
		return 0;
	}

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

	/* Make sure DP mainlink and audio engines are disabled */
@@ -1231,28 +1195,15 @@ static int dp_ctrl_off_irq(struct dp_ctrl_private *ctrl)

	complete_all(&ctrl->irq_comp);
	pr_debug("end\n");

	return 0;
}

static int dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
static void dp_ctrl_off_hpd(struct dp_ctrl_private *ctrl)
{
	if (!ctrl->power_on) {
		pr_debug("panel already powered off\n");
		return 0;
	}

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

	ctrl->power_on = false;
	ctrl->sink_info_read = false;

	pr_debug("DP off done\n");

	return 0;
}

static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
static int dp_ctrl_on(struct dp_ctrl *dp_ctrl, bool hpd_irq)
{
	int rc = 0;
	struct dp_ctrl_private *ctrl;
@@ -1264,7 +1215,7 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)

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

	if (ctrl->hpd_irq_on)
	if (hpd_irq)
		rc = dp_ctrl_on_irq(ctrl, false);
	else
		rc = dp_ctrl_on_hpd(ctrl);
@@ -1272,24 +1223,19 @@ static int dp_ctrl_on(struct dp_ctrl *dp_ctrl)
	return rc;
}

static int dp_ctrl_off(struct dp_ctrl *dp_ctrl)
static void dp_ctrl_off(struct dp_ctrl *dp_ctrl, bool hpd_irq)
{
	int rc = 0;
	struct dp_ctrl_private *ctrl;

	if (!dp_ctrl) {
		rc = -EINVAL;
		goto end;
	}
	if (!dp_ctrl)
		return;

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

	if (ctrl->hpd_irq_on)
		rc = dp_ctrl_off_irq(ctrl);
	if (hpd_irq)
		dp_ctrl_off_irq(ctrl);
	else
		rc = dp_ctrl_off_hpd(ctrl);
end:
	return rc;
		dp_ctrl_off_hpd(ctrl);
}

static void dp_ctrl_isr(struct dp_ctrl *dp_ctrl)
+2 −2
Original line number Diff line number Diff line
@@ -25,8 +25,8 @@
struct dp_ctrl {
	int (*init)(struct dp_ctrl *dp_ctrl, bool flip);
	void (*deinit)(struct dp_ctrl *dp_ctrl);
	int (*on)(struct dp_ctrl *dp_ctrl);
	int (*off)(struct dp_ctrl *dp_ctrl);
	int (*on)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
	void (*off)(struct dp_ctrl *dp_ctrl, bool hpd_irq);
	void (*push_idle)(struct dp_ctrl *dp_ctrl);
	void (*isr)(struct dp_ctrl *dp_ctrl);
};
+82 −38
Original line number Diff line number Diff line
@@ -38,6 +38,11 @@ struct dp_display_private {
	char *name;
	int irq;

	/* state variables */
	bool core_initialized;
	bool power_on;
	bool hpd_irq_on;

	struct platform_device *pdev;
	struct dentry *root;
	struct mutex lock;
@@ -255,30 +260,63 @@ static const struct component_ops dp_display_comp_ops = {

static int dp_display_process_hpd_high(struct dp_display_private *dp)
{
	int rc;
	int rc = 0;

	rc = dp->panel->read_dpcd(dp->panel);
	if (rc)
		goto end;
		return rc;

	sde_get_edid(dp->dp_display.connector, &dp->aux->drm_aux->ddc,
		(void **)&dp->panel->edid_ctrl);

	return 0;
end:
	dp->dp_display.is_connected = true;
	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);

	return rc;
}

static int dp_display_process_hpd_low(struct dp_display_private *dp)
static void dp_display_host_init(struct dp_display_private *dp)
{
	bool flip = false;

	if (dp->core_initialized) {
		pr_debug("DP core already initialized\n");
		return;
	}

	if (dp->usbpd->orientation == ORIENTATION_CC2)
		flip = true;

	dp->power->init(dp->power, flip);
	dp->ctrl->init(dp->ctrl, flip);
	dp->aux->init(dp->aux, dp->parser->aux_cfg);
	enable_irq(dp->irq);
	dp->core_initialized = true;
}

static void dp_display_host_deinit(struct dp_display_private *dp)
{
	if (!dp->core_initialized) {
		pr_debug("DP core already off\n");
		return;
	}

	dp->aux->deinit(dp->aux);
	dp->ctrl->deinit(dp->ctrl);
	dp->power->deinit(dp->power);
	disable_irq(dp->irq);
	dp->core_initialized = false;
}

static void dp_display_process_hpd_low(struct dp_display_private *dp)
{
	dp->dp_display.is_connected = false;
	return 0;
	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);
}

static int dp_display_usbpd_configure_cb(struct device *dev)
{
	int rc = 0;
	bool flip = false;
	struct dp_display_private *dp;

	if (!dev) {
@@ -295,19 +333,9 @@ static int dp_display_usbpd_configure_cb(struct device *dev)
	}

	mutex_lock(&dp->lock);

	if (dp->usbpd->orientation == ORIENTATION_CC2)
		flip = true;

	dp->power->init(dp->power, flip);
	dp->ctrl->init(dp->ctrl, flip);
	dp->aux->init(dp->aux, dp->parser->aux_cfg);
	enable_irq(dp->irq);

	dp_display_host_init(dp);
	if (dp->usbpd->hpd_high)
		dp_display_process_hpd_high(dp);
	dp->dp_display.is_connected = true;

	mutex_unlock(&dp->lock);
end:
	return rc;
@@ -332,10 +360,23 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	}

	mutex_lock(&dp->lock);

	dp->dp_display.is_connected = false;
	disable_irq(dp->irq);
	mutex_unlock(&dp->lock);
	drm_helper_hpd_irq_event(dp->dp_display.connector->dev);

	/*
	 * If a cable/dongle is connected to the TX device but
	 * no sink device is connected, we call host
	 * initialization where orientation settings are
	 * configured. When the cable/dongle is disconnect,
	 * call host de-initialization to make sure
	 * we re-configure the orientation settings during
	 * the next connect event.
	 */
	if (!dp->power_on && dp->core_initialized)
		dp_display_host_deinit(dp);

	mutex_unlock(&dp->lock);
end:
	return rc;
}
@@ -347,31 +388,36 @@ static int dp_display_usbpd_attention_cb(struct device *dev)

	if (!dev) {
		pr_err("invalid dev\n");
		rc = -EINVAL;
		goto end;
		return -EINVAL;
	}

	dp = dev_get_drvdata(dev);
	if (!dp) {
		pr_err("no driver data found\n");
		rc = -ENODEV;
		goto end;
		return -ENODEV;
	}

	mutex_lock(&dp->lock);

	if (dp->usbpd->hpd_irq) {
		if (!dp->link->process_request(dp->link))
		dp->hpd_irq_on = true;
		rc = dp->link->process_request(dp->link);
		dp->hpd_irq_on = false;
		if (!rc)
			goto end;
	}

	if (dp->usbpd->hpd_high)
		dp_display_process_hpd_high(dp);
	else
	if (!dp->usbpd->hpd_high) {
		dp_display_process_hpd_low(dp);
		goto end;
	}

	mutex_unlock(&dp->lock);
	if (dp->usbpd->alt_mode_cfg_done) {
		dp_display_host_init(dp);
		dp_display_process_hpd_high(dp);
	}
end:
	mutex_unlock(&dp->lock);
	return rc;
}

@@ -492,7 +538,9 @@ static int dp_display_enable(struct dp_display *dp_display)
	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->lock);
	dp->ctrl->on(dp->ctrl);
	rc = dp->ctrl->on(dp->ctrl, dp->hpd_irq_on);
	if (!rc)
		dp->power_on = true;
	mutex_unlock(&dp->lock);
error:
	return rc;
@@ -517,9 +565,7 @@ static int dp_display_pre_disable(struct dp_display *dp_display)
	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->lock);

	dp->ctrl->off(dp->ctrl);

	dp->ctrl->push_idle(dp->ctrl);
	mutex_unlock(&dp->lock);
error:
	return rc;
@@ -539,11 +585,9 @@ static int dp_display_disable(struct dp_display *dp_display)
	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->lock);

	dp->aux->deinit(dp->aux);
	dp->ctrl->deinit(dp->ctrl);
	dp->power->deinit(dp->power);

	dp->ctrl->off(dp->ctrl, dp->hpd_irq_on);
	dp_display_host_deinit(dp);
	dp->power_on = false;
	mutex_unlock(&dp->lock);
error:
	return rc;
+5 −1
Original line number Diff line number Diff line
@@ -345,8 +345,12 @@ static void dp_usbpd_response_cb(struct usbpd_svid_handler *hdlr, u8 cmd,
		pd->vdo = *vdos;
		dp_usbpd_get_status(pd);

		if (pd->dp_cb && pd->dp_cb->attention)
		if (pd->dp_cb && pd->dp_cb->attention) {
			pd->dp_cb->attention(pd->dev);

			if (!pd->dp_usbpd.alt_mode_cfg_done)
				dp_usbpd_send_event(pd, DP_USBPD_EVT_CONFIGURE);
		}
		break;
	case DP_USBPD_VDM_STATUS:
		pd->vdo = *vdos;