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

Commit f9165718 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "drm/msm/dp: listen to USB events to terminate simulation"

parents 4bee6db9 9299070a
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -679,10 +679,8 @@ static int dp_audio_notify(struct dp_audio_private *audio, u32 state)
	reinit_completion(&audio->hpd_comp);
	rc = ext->intf_ops.audio_notify(audio->ext_pdev,
			&ext->codec, state);
	if (rc) {
		pr_err("failed to notify audio. state=%d err=%d\n", state, rc);
	if (rc)
		goto end;
	}

	if (atomic_read(&audio->acked))
		goto end;
+70 −31
Original line number Diff line number Diff line
@@ -163,6 +163,13 @@ static ssize_t dp_debug_write_edid(struct file *file,
	kfree(buf);
	debug->panel->set_edid(debug->panel, edid);

	/*
	 * print edid status as this code is executed
	 * only while running in debug mode which is manually
	 * triggered by a tester or a script.
	 */
	pr_info("[%s]\n", edid ? "SET" : "CLEAR");

	return rc;
}

@@ -250,10 +257,18 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
	 * Reset panel's dpcd in case of any failure. Also, set the
	 * panel's dpcd only if a full dpcd is provided with offset as 0.
	 */
	if (!dpcd || (!offset && (data_len == dp_receiver_cap_size)))
	if (!dpcd || (!offset && (data_len == dp_receiver_cap_size))) {
		debug->panel->set_dpcd(debug->panel, dpcd);
	else

		/*
		 * print dpcd status as this code is executed
		 * only while running in debug mode which is manually
		 * triggered by a tester or a script.
		 */
		pr_info("[%s]\n", dpcd ? "SET" : "CLEAR");
	} else {
		debug->aux->dpcd_updated(debug->aux);
	}

	return rc;
}
@@ -1392,36 +1407,16 @@ static ssize_t dp_debug_read_hdr(struct file *file,
	return rc;
}

static ssize_t dp_debug_write_sim(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
static void dp_debug_set_sim_mode(struct dp_debug_private *debug, bool sim)
{
	struct dp_debug_private *debug = file->private_data;
	char buf[SZ_8];
	size_t len = 0;
	int sim;

	if (!debug)
		return -ENODEV;

	if (*ppos)
		return 0;

	/* Leave room for termination char */
	len = min_t(size_t, count, SZ_8 - 1);
	if (copy_from_user(buf, user_buff, len))
		goto end;

	buf[len] = '\0';

	if (kstrtoint(buf, 10, &sim) != 0)
		goto end;

	if (sim) {
		if (dp_debug_get_edid_buf(debug))
			goto end;
			return;

		if (dp_debug_get_dpcd_buf(debug))
			goto error;
		if (dp_debug_get_dpcd_buf(debug)) {
			devm_kfree(debug->dev, debug->edid);
			return;
		}

		debug->dp_debug.sim_mode = true;
		debug->aux->set_sim_mode(debug->aux, true,
@@ -1442,11 +1437,42 @@ static ssize_t dp_debug_write_sim(struct file *file,
			debug->dpcd = NULL;
		}
	}

	/*
	 * print simulation status as this code is executed
	 * only while running in debug mode which is manually
	 * triggered by a tester or a script.
	 */
	pr_info("%s\n", sim ? "[ON]" : "[OFF]");
}

static ssize_t dp_debug_write_sim(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	char buf[SZ_8];
	size_t len = 0;
	int sim;

	if (!debug)
		return -ENODEV;

	if (*ppos)
		return 0;

	/* Leave room for termination char */
	len = min_t(size_t, count, SZ_8 - 1);
	if (copy_from_user(buf, user_buff, len))
		goto end;

	buf[len] = '\0';

	if (kstrtoint(buf, 10, &sim) != 0)
		goto end;

	dp_debug_set_sim_mode(debug, sim);
end:
	return len;
error:
	devm_kfree(debug->dev, debug->edid);
	return len;
}

static ssize_t dp_debug_write_attention(struct file *file,
@@ -1898,6 +1924,18 @@ u8 *dp_debug_get_edid(struct dp_debug *dp_debug)
	return debug->edid;
}

static void dp_debug_abort(struct dp_debug *dp_debug)
{
	struct dp_debug_private *debug;

	if (!dp_debug)
		return;

	debug = container_of(dp_debug, struct dp_debug_private, dp_debug);

	dp_debug_set_sim_mode(debug, false);
}

struct dp_debug *dp_debug_get(struct dp_debug_in *in)
{
	int rc = 0;
@@ -1938,6 +1976,7 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)
	}

	dp_debug->get_edid = dp_debug_get_edid;
	dp_debug->abort = dp_debug_abort;

	INIT_LIST_HEAD(&dp_debug->dp_mst_connector_list.list);

+1 −0
Original line number Diff line number Diff line
@@ -47,6 +47,7 @@ struct dp_debug {
	struct dp_mst_connector dp_mst_connector_list;

	u8 *(*get_edid)(struct dp_debug *dp_debug);
	void (*abort)(struct dp_debug *dp_debug);
};

/**
+68 −36
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@
#include <linux/debugfs.h>
#include <linux/component.h>
#include <linux/of_irq.h>
#include <linux/extcon.h>
#include <linux/soc/qcom/fsa4480-i2c.h>

#include "sde_connector.h"
@@ -107,6 +108,8 @@ struct dp_display_private {

	u32 active_stream_cnt;
	struct dp_mst mst;

	struct notifier_block usb_nb;
};

static const struct of_device_id dp_dt_match[] = {
@@ -556,6 +559,9 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp)
	if (hpd && dp->mst.mst_active)
		goto skip_wait;

	if (!dp->mst.mst_active && (dp->power_on == hpd))
		goto skip_wait;

	if (!wait_for_completion_timeout(&dp->notification_comp,
						HZ * timeout_sec)) {
		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
@@ -846,6 +852,24 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
	return rc;
}

static void dp_display_disconnect_sync(struct dp_display_private *dp)
{
	/* cancel any pending request */
	atomic_set(&dp->aborted, 1);
	dp->ctrl->abort(dp->ctrl);
	dp->aux->abort(dp->aux);

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

	dp_display_handle_disconnect(dp);

	/* Reset abort value to allow future connections */
	atomic_set(&dp->aborted, 0);
}

static int dp_display_usbpd_disconnect_cb(struct device *dev)
{
	int rc = 0;
@@ -874,21 +898,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
	if (dp->debug->psm_enabled)
		dp->link->psm_config(dp->link, &dp->panel->link_info, true);

	/* cancel any pending request */
	atomic_set(&dp->aborted, 1);
	dp->ctrl->abort(dp->ctrl);
	dp->aux->abort(dp->aux);

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

	dp_display_handle_disconnect(dp);

	/* Reset abort value to allow future connections */
	atomic_set(&dp->aborted, 0);

	dp_display_disconnect_sync(dp);
	dp->dp_display.post_open = NULL;
end:
	return rc;
@@ -990,29 +1000,14 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
			dp->hpd->hpd_irq, dp->hpd->hpd_high,
			dp->power_on);

	if (!dp->hpd->hpd_high) {
		if (!dp->is_connected) {
			pr_debug("already disconnected\n");
			return 0;
		}

		/* cancel any pending request */
		atomic_set(&dp->aborted, 1);
		dp->ctrl->abort(dp->ctrl);
		dp->aux->abort(dp->aux);

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

		dp_display_handle_disconnect(dp);
		atomic_set(&dp->aborted, 0);
	} else if (dp->hpd->hpd_irq && dp->core_initialized) {
	if (!dp->hpd->hpd_high)
		dp_display_disconnect_sync(dp);
	else if (dp->hpd->hpd_irq && dp->core_initialized)
		queue_work(dp->wq, &dp->attention_work);
	} else {
	else if (!dp->power_on)
		queue_delayed_work(dp->wq, &dp->connect_work, 0);
	}
	else
		pr_debug("ignored\n");

	return 0;
}
@@ -1040,6 +1035,41 @@ static void dp_display_connect_work(struct work_struct *work)
		dp->link->send_test_response(dp->link);
}

static int dp_display_usb_notifier(struct notifier_block *nb,
	unsigned long event, void *ptr)
{
	struct extcon_dev *edev = ptr;
	struct dp_display_private *dp = container_of(nb,
			struct dp_display_private, usb_nb);
	if (!edev)
		goto end;

	if (!event && dp->debug->sim_mode) {
		dp_display_disconnect_sync(dp);
		dp->debug->abort(dp->debug);
	}
end:
	return NOTIFY_DONE;
}

static int dp_display_get_usb_extcon(struct dp_display_private *dp)
{
	struct extcon_dev *edev;
	int rc;

	edev = extcon_get_edev_by_phandle(&dp->pdev->dev, 0);
	if (IS_ERR(edev))
		return PTR_ERR(edev);

	dp->usb_nb.notifier_call = dp_display_usb_notifier;
	dp->usb_nb.priority = 2;
	rc = extcon_register_notifier(edev, EXTCON_USB, &dp->usb_nb);
	if (rc)
		pr_err("failed to register for usb event: %d\n", rc);

	return rc;
}

static void dp_display_deinit_sub_modules(struct dp_display_private *dp)
{
	dp_audio_put(dp->panel->audio);
@@ -1209,6 +1239,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
	dp->debug->hdcp_disabled = hdcp_disabled;
	dp_display_update_hdcp_status(dp, true);

	dp_display_get_usb_extcon(dp);

	return rc;
error_debug:
	dp_hpd_put(dp->hpd);
+1 −0
Original line number Diff line number Diff line
@@ -1004,6 +1004,7 @@ static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid)
		panel->custom_edid = true;
	} else {
		panel->custom_edid = false;
		dp_panel->edid_ctrl->edid = NULL;
	}

	pr_debug("%d\n", panel->custom_edid);