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

Commit 423611f7 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar Committed by Gerrit - the friendly Code Review server
Browse files

drm/msm/dp: fix boot-up cable notification delays



During boot-up, based on experiments, add proper delays
before sending events to user-space. User-space modules
listening for events may not be ready when the events are
sent at boot-up. Avoid missing these events by adding
necessary delays.

CRs-Fixed: 2170496
Change-Id: Iae3aa008b03df058c0c9f57f2febe042984bf921
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent 7a9eac93
Loading
Loading
Loading
Loading
+34 −22
Original line number Diff line number Diff line
@@ -89,11 +89,12 @@ struct dp_display_private {

	struct workqueue_struct *wq;
	struct delayed_work hdcp_cb_work;
	struct work_struct connect_work;
	struct delayed_work connect_work;
	struct work_struct attention_work;
	struct mutex hdcp_mutex;
	struct mutex session_lock;
	int hdcp_status;
	unsigned long audio_status;
};

static const struct of_device_id dp_dt_match[] = {
@@ -101,6 +102,11 @@ static const struct of_device_id dp_dt_match[] = {
	{}
};

static bool dp_display_framework_ready(struct dp_display_private *dp)
{
	return dp->dp_display.post_open ? false : true;
}

static inline bool dp_display_is_hdcp_enabled(struct dp_display_private *dp)
{
	return dp->hdcp.feature_enabled &&
@@ -449,31 +455,30 @@ static void dp_display_post_open(struct dp_display *dp_display)
	}

	/* if cable is already connected, send notification */
	if (dp_display->is_connected)
		dp_display_send_hpd_event(dp);
	if (dp->usbpd->hpd_high)
		queue_delayed_work(dp->wq, &dp->connect_work, HZ * 10);
	else
		dp_display->post_open = NULL;

}

static int dp_display_send_hpd_notification(struct dp_display_private *dp,
		bool hpd)
{
	u32 timeout_sec;

	dp->dp_display.is_connected = hpd;

	/* in case, framework is not yet up, don't notify hpd */
	if (dp->dp_display.post_open)
		return 0;
	if  (dp_display_framework_ready(dp))
		timeout_sec = 5;
	else
		timeout_sec = 10;

	reinit_completion(&dp->notification_comp);
	dp_display_send_hpd_event(dp);

	if (!wait_for_completion_timeout(&dp->notification_comp, HZ * 5)) {
	if (!wait_for_completion_timeout(&dp->notification_comp,
						HZ * timeout_sec)) {
		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
		/* cancel any pending request */
		dp->ctrl->abort(dp->ctrl);
		dp->aux->abort(dp->aux);

		return -EINVAL;
	}

@@ -568,6 +573,8 @@ static int dp_display_process_hpd_low(struct dp_display_private *dp)
	if (dp->audio_supported)
		dp->audio->off(dp->audio);

	dp->audio_status = -ENODEV;

	rc = dp_display_send_hpd_notification(dp, false);

	dp->aux->deinit(dp->aux);
@@ -597,8 +604,9 @@ static int dp_display_usbpd_configure_cb(struct device *dev)

	dp_display_host_init(dp);

	if (dp->usbpd->hpd_high)
		queue_work(dp->wq, &dp->connect_work);
	/* check for hpd high and framework ready */
	if  (dp->usbpd->hpd_high && dp_display_framework_ready(dp))
		queue_delayed_work(dp->wq, &dp->connect_work, 0);
end:
	return rc;
}
@@ -662,6 +670,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	dp->aux->abort(dp->aux);

	/* wait for idle state */
	cancel_delayed_work(&dp->connect_work);
	flush_workqueue(dp->wq);

	dp_display_handle_disconnect(dp);
@@ -673,13 +682,13 @@ static void dp_display_handle_maintenance_req(struct dp_display_private *dp)
{
	mutex_lock(&dp->audio->ops_lock);

	if (dp->audio_supported)
	if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
		dp->audio->off(dp->audio);

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

	if (dp->audio_supported)
		dp->audio->on(dp->audio);
	if (dp->audio_supported && !IS_ERR_VALUE(dp->audio_status))
		dp->audio_status = dp->audio->on(dp->audio);

	mutex_unlock(&dp->audio->ops_lock);
}
@@ -702,7 +711,7 @@ static void dp_display_attention_work(struct work_struct *work)
			return;
		}

		queue_work(dp->wq, &dp->connect_work);
		queue_delayed_work(dp->wq, &dp->connect_work, 0);
		return;
	}

@@ -752,13 +761,14 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
		dp->link->process_request(dp->link);
		queue_work(dp->wq, &dp->attention_work);
	} else if (dp->usbpd->hpd_high) {
		queue_work(dp->wq, &dp->connect_work);
		queue_delayed_work(dp->wq, &dp->connect_work, 0);
	} else {
		/* cancel any pending request */
		dp->ctrl->abort(dp->ctrl);
		dp->aux->abort(dp->aux);

		/* wait for idle state */
		cancel_delayed_work(&dp->connect_work);
		flush_workqueue(dp->wq);

		dp_display_handle_disconnect(dp);
@@ -769,7 +779,8 @@ static int dp_display_usbpd_attention_cb(struct device *dev)

static void dp_display_connect_work(struct work_struct *work)
{
	struct dp_display_private *dp = container_of(work,
	struct delayed_work *dw = to_delayed_work(work);
	struct dp_display_private *dp = container_of(dw,
			struct dp_display_private, connect_work);

	if (dp->dp_display.is_connected) {
@@ -1065,7 +1076,7 @@ static int dp_display_post_enable(struct dp_display *dp_display)
	if (dp->audio_supported) {
		dp->audio->bw_code = dp->link->link_params.bw_code;
		dp->audio->lane_count = dp->link->link_params.lane_count;
		dp->audio->on(dp->audio);
		dp->audio_status = dp->audio->on(dp->audio);
	}

	dp_display_update_hdcp_info(dp);
@@ -1288,7 +1299,7 @@ static int dp_display_create_workqueue(struct dp_display_private *dp)
	}

	INIT_DELAYED_WORK(&dp->hdcp_cb_work, dp_display_hdcp_cb_work);
	INIT_WORK(&dp->connect_work, dp_display_connect_work);
	INIT_DELAYED_WORK(&dp->connect_work, dp_display_connect_work);
	INIT_WORK(&dp->attention_work, dp_display_attention_work);

	return 0;
@@ -1315,6 +1326,7 @@ static int dp_display_probe(struct platform_device *pdev)

	dp->pdev = pdev;
	dp->name = "drm_dp";
	dp->audio_status = -ENODEV;

	rc = dp_display_create_workqueue(dp);
	if (rc) {
+37 −8
Original line number Diff line number Diff line
/* Copyright (c) 2016-2017, The Linux Foundation. All rights reserved.
/* Copyright (c) 2016-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -44,6 +44,20 @@ static const unsigned int msm_ext_disp_supported_cable[] = {
	EXTCON_NONE,
};

static int msm_ext_disp_find_index(struct extcon_dev *edev,
		enum msm_ext_disp_type id)
{
	int i;

	/* Find the the index of extcon cable in edev->supported_cable */
	for (i = 0; i < edev->max_supported; i++) {
		if (edev->supported_cable[i] == id)
			return i;
	}

	return -EINVAL;
}

static int msm_ext_disp_extcon_register(struct msm_ext_disp *ext_disp)
{
	int ret = 0;
@@ -145,7 +159,8 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
		enum msm_ext_disp_cable_state new_state)
{
	int ret = 0;
	int state;
	int state, index;
	enum msm_ext_disp_cable_state current_state;

	if (!ext_disp->ops) {
		pr_err("codec not registered, skip notification\n");
@@ -154,13 +169,27 @@ static int msm_ext_disp_process_audio(struct msm_ext_disp *ext_disp,
	}

	state = ext_disp->audio_sdev.state;

	index = msm_ext_disp_find_index(&ext_disp->audio_sdev, type);
	if (index < 0 || index >= ext_disp->audio_sdev.max_supported) {
		pr_err("invalid index\n");
		ret = -EINVAL;
		goto end;
	}

	if (state & BIT(index))
		current_state = EXT_DISPLAY_CABLE_CONNECT;
	else
		current_state = EXT_DISPLAY_CABLE_DISCONNECT;

	if (current_state == new_state) {
		ret = -EEXIST;
		pr_debug("same state\n");
	} else {
		ret = extcon_set_state_sync(&ext_disp->audio_sdev,
			ext_disp->current_disp, !!new_state);

	pr_debug("Audio state %s %d\n",
			ext_disp->audio_sdev.state == state ?
			"is same" : "switched to",
			ext_disp->audio_sdev.state);
		pr_debug("state changed to %d\n", new_state);
	}
end:
	return ret;
}