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

Commit 3d0f9cb1 authored by Govinda Rajulu Chenna's avatar Govinda Rajulu Chenna
Browse files

drm/msm/dp: enhancements in dp debug module



Enhance dp debug module to validate dp mst driver
in simulation mode. Implement debugfs nodes for
reading the mst support and mst active state info,
overriding mst connector status to simulate port
connect/disconnect event without real hot plug/unplug.

CRs-Fixed: 2332059
Change-Id: Idf43651825e30c676af6bf880aabeb752c5d0cc4
Signed-off-by: default avatarGovinda Rajulu Chenna <gchenna@codeaurora.org>
parent 7f16c781
Loading
Loading
Loading
Loading
+49 −16
Original line number Diff line number Diff line
@@ -451,8 +451,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,
	struct dp_mst_connector *mst_connector;
	char buf[SZ_32];
	size_t len = 0;
	int con_id = 0;
	int con_id = 0, status;
	bool in_list = false;
	const int dp_en = BIT(3), hpd_high = BIT(7), hpd_irq = BIT(8);
	int vdo = dp_en | hpd_high | hpd_irq;

	if (!debug)
		return -ENODEV;
@@ -467,8 +469,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,

	buf[len] = '\0';

	if (kstrtoint(buf, 10, &con_id) != 0)
		goto clear;
	if (sscanf(buf, "%d %d", &con_id, &status) != 2) {
		len = 0;
		goto end;
	}

	if (!con_id)
		goto clear;
@@ -480,6 +484,7 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,
		if (mst_connector->con_id == con_id) {
			in_list = true;
			debug->mst_con_id = con_id;
			mst_connector->state = status;
			break;
		}
	}
@@ -487,6 +492,10 @@ static ssize_t dp_debug_write_mst_con_id(struct file *file,

	if (!in_list)
		pr_err("invalid connector id %u\n", con_id);
	else if (status != connector_status_unknown) {
		debug->dp_debug.mst_hpd_sim = true;
		debug->hpd->simulate_attention(debug->hpd, vdo);
	}

	goto end;
clear:
@@ -530,6 +539,21 @@ static ssize_t dp_debug_bw_code_write(struct file *file,
	return len;
}

static ssize_t dp_debug_mst_mode_read(struct file *file,
	char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	char buf[64];
	ssize_t len;

	len = scnprintf(buf, sizeof(buf),
			"mst_mode = %d, mst_state = %d\n",
			debug->parser->has_mst,
			debug->panel->mst_state);

	return simple_read_from_buffer(user_buff, count, ppos, buf, len);
}

static ssize_t dp_debug_mst_mode_write(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
@@ -631,28 +655,35 @@ static ssize_t dp_debug_mst_sideband_mode_write(struct file *file,
	struct dp_debug_private *debug = file->private_data;
	char buf[SZ_8];
	size_t len = 0;
	u32 mst_sideband_mode = 0;
	int mst_sideband_mode = 0;
	u32 mst_port_cnt = 0;

	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))
		return 0;
		return -EFAULT;

	buf[len] = '\0';

	if (kstrtoint(buf, 10, &mst_sideband_mode) != 0)
		return 0;
	if (sscanf(buf, "%d %u", &mst_sideband_mode, &mst_port_cnt) != 2) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	debug->parser->has_mst_sideband = mst_sideband_mode ? true : false;
	pr_debug("mst_enable: %d\n", mst_sideband_mode);
	if (mst_port_cnt > DP_MST_SIM_MAX_PORTS) {
		pr_err("port cnt:%d exceeding max:%d\n", mst_port_cnt,
				DP_MST_SIM_MAX_PORTS);
		return -EINVAL;
	}

	return len;
	debug->parser->has_mst_sideband = mst_sideband_mode ? true : false;
	debug->dp_debug.mst_port_cnt = mst_port_cnt;
	pr_debug("mst_sideband_mode: %d port_cnt:%d\n",
			mst_sideband_mode, mst_port_cnt);
	return count;
}

static ssize_t dp_debug_widebus_mode_write(struct file *file,
@@ -1049,9 +1080,10 @@ static ssize_t dp_debug_read_mst_conn_info(struct file *file,
			continue;
		}

		ret = snprintf(buf + len, max_size,
				"conn name:%s, conn id:%d\n", connector->name,
				connector->base.id);
		ret = scnprintf(buf + len, max_size,
				"conn name:%s, conn id:%d state:%d\n",
				connector->name, connector->base.id,
				connector->status);
		if (dp_debug_check_buffer_overflow(ret, &max_size, &len))
			break;
	}
@@ -1659,6 +1691,7 @@ static const struct file_operations dump_fops = {
static const struct file_operations mst_mode_fops = {
	.open = simple_open,
	.write = dp_debug_mst_mode_write,
	.read = dp_debug_mst_mode_read,
};

static const struct file_operations mst_sideband_mode_fops = {
+2 −0
Original line number Diff line number Diff line
@@ -45,6 +45,8 @@ struct dp_debug {
	bool force_encryption;
	char hdcp_status[SZ_128];
	struct dp_mst_connector dp_mst_connector_list;
	bool mst_hpd_sim;
	u32 mst_port_cnt;

	u8 *(*get_edid)(struct dp_debug *dp_debug);
	void (*abort)(struct dp_debug *dp_debug);
+63 −8
Original line number Diff line number Diff line
@@ -572,10 +572,17 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp)
	return 0;
}

static void dp_display_update_mst_state(struct dp_display_private *dp,
					bool state)
{
	dp->mst.mst_active = state;
	dp->panel->mst_state = state;
}

static void dp_display_process_mst_hpd_high(struct dp_display_private *dp)
{
	bool is_mst_receiver;
	struct dp_mst_hdp_info info;
	struct dp_mst_hpd_info info;

	if (dp->parser->has_mst && dp->mst.drm_registered) {
		DP_MST_DEBUG("mst_hpd_high work\n");
@@ -583,9 +590,14 @@ static void dp_display_process_mst_hpd_high(struct dp_display_private *dp)
		is_mst_receiver = dp->panel->read_mst_cap(dp->panel);

		if (is_mst_receiver && !dp->mst.mst_active) {
			dp->mst.mst_active = true;

			/* clear sink mst state */
			drm_dp_dpcd_writeb(dp->aux->drm_aux, DP_MSTM_CTRL, 0);

			dp_display_update_mst_state(dp, true);

			info.mst_protocol = dp->parser->has_mst_sideband;
			info.mst_port_cnt = dp->debug->mst_port_cnt;
			info.edid = dp->debug->get_edid(dp->debug);

			if (dp->mst.cbs.hpd)
@@ -693,7 +705,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)

static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
{
	struct dp_mst_hdp_info info = {0};
	struct dp_mst_hpd_info info = {0};

	if (dp->mst.mst_active) {
		DP_MST_DEBUG("mst_hpd_low work\n");
@@ -702,8 +714,7 @@ static void dp_display_process_mst_hpd_low(struct dp_display_private *dp)
			info.mst_protocol = dp->parser->has_mst_sideband;
			dp->mst.cbs.hpd(&dp->dp_display, false, &info);
		}

		dp->mst.mst_active = false;
		dp_display_update_mst_state(dp, false);
	}

	DP_MST_DEBUG("mst_hpd_low. mst_active:%d\n", dp->mst.mst_active);
@@ -926,8 +937,13 @@ static int dp_display_stream_enable(struct dp_display_private *dp,

static void dp_display_mst_attention(struct dp_display_private *dp)
{
	if (dp->mst.mst_active && dp->mst.cbs.hpd_irq)
		dp->mst.cbs.hpd_irq(&dp->dp_display);
	struct dp_mst_hpd_info hpd_irq = {0};

	if (dp->mst.mst_active && dp->mst.cbs.hpd_irq) {
		hpd_irq.mst_hpd_sim = dp->debug->mst_hpd_sim;
		dp->mst.cbs.hpd_irq(&dp->dp_display, &hpd_irq);
		dp->debug->mst_hpd_sim = false;
	}

	DP_MST_DEBUG("mst_attention_work. mst_active:%d\n", dp->mst.mst_active);
}
@@ -937,6 +953,9 @@ static void dp_display_attention_work(struct work_struct *work)
	struct dp_display_private *dp = container_of(work,
			struct dp_display_private, attention_work);

	if (dp->debug->mst_hpd_sim)
		goto mst_attention;

	if (dp->link->process_request(dp->link))
		goto cp_irq;

@@ -1002,7 +1021,8 @@ static int dp_display_usbpd_attention_cb(struct device *dev)

	if (!dp->hpd->hpd_high)
		dp_display_disconnect_sync(dp);
	else if (dp->hpd->hpd_irq && dp->core_initialized)
	else if ((dp->hpd->hpd_irq && dp->core_initialized) ||
			dp->debug->mst_hpd_sim)
		queue_work(dp->wq, &dp->attention_work);
	else if (!dp->power_on)
		queue_delayed_work(dp->wq, &dp->connect_work, 0);
@@ -2034,6 +2054,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,
	mst_connector->debug_en = false;
	mst_connector->conn = connector;
	mst_connector->con_id = connector->base.id;
	mst_connector->state = connector_status_unknown;
	INIT_LIST_HEAD(&mst_connector->list);

	list_add(&mst_connector->list,
@@ -2099,6 +2120,38 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display,
	return rc;
}

static int dp_display_mst_get_connector_info(struct dp_display *dp_display,
			struct drm_connector *connector,
			struct dp_mst_connector *mst_conn)
{
	struct dp_display_private *dp;
	struct dp_mst_connector *conn, *temp_conn;

	if (!connector || !mst_conn) {
		pr_err("invalid input\n");
		return -EINVAL;
	}

	dp = container_of(dp_display, struct dp_display_private, dp_display);

	mutex_lock(&dp->session_lock);
	if (!dp->mst.drm_registered) {
		pr_debug("drm mst not registered\n");
		mutex_unlock(&dp->session_lock);
		return -EPERM;
	}

	mutex_lock(&dp->debug->dp_mst_connector_list.lock);
	list_for_each_entry_safe(conn, temp_conn,
			&dp->debug->dp_mst_connector_list.list, list) {
		if (conn->con_id == connector->base.id)
			memcpy(mst_conn, conn, sizeof(*mst_conn));
	}
	mutex_unlock(&dp->debug->dp_mst_connector_list.lock);
	mutex_unlock(&dp->session_lock);
	return 0;
}

static int dp_display_mst_connector_update_edid(struct dp_display *dp_display,
			struct drm_connector *connector,
			struct edid *edid)
@@ -2221,6 +2274,8 @@ static int dp_display_probe(struct platform_device *pdev)
	g_dp_display->get_mst_caps = dp_display_get_mst_caps;
	g_dp_display->set_stream_info = dp_display_set_stream_info;
	g_dp_display->convert_to_dp_mode = dp_display_convert_to_dp_mode;
	g_dp_display->mst_get_connector_info =
					dp_display_mst_get_connector_info;

	rc = component_add(&pdev->dev, &dp_display_comp_ops);
	if (rc) {
+11 −3
Original line number Diff line number Diff line
@@ -21,15 +21,19 @@

#include "dp_panel.h"

struct dp_mst_hdp_info {
#define DP_MST_SIM_MAX_PORTS	2

struct dp_mst_hpd_info {
	bool mst_protocol;
	bool mst_hpd_sim;
	u32 mst_port_cnt;
	u8 *edid;
};

struct dp_mst_drm_cbs {
	void (*hpd)(void *display, bool hpd_status,
			struct dp_mst_hdp_info *info);
	void (*hpd_irq)(void *display);
			struct dp_mst_hpd_info *info);
	void (*hpd_irq)(void *display, struct dp_mst_hpd_info *info);
};

struct dp_mst_drm_install_info {
@@ -54,6 +58,7 @@ struct dp_mst_connector {
	struct drm_connector *conn;
	struct mutex lock;
	struct list_head list;
	enum drm_connector_status state;
};

struct dp_display {
@@ -96,6 +101,9 @@ struct dp_display {
	int (*mst_connector_update_edid)(struct dp_display *dp_display,
			struct drm_connector *connector,
			struct edid *edid);
	int (*mst_get_connector_info)(struct dp_display *dp_display,
			struct drm_connector *connector,
			struct dp_mst_connector *mst_conn);
	int (*get_mst_caps)(struct dp_display *dp_display,
			struct dp_mst_caps *mst_caps);
	int (*set_stream_info)(struct dp_display *dp_display, void *panel,
+23 −6
Original line number Diff line number Diff line
@@ -33,7 +33,6 @@
#define MAX_DP_MST_STREAMS		2
#define MAX_DP_MST_DRM_ENCODERS		2
#define MAX_DP_MST_DRM_BRIDGES		2
#define DP_MST_SIM_MAX_PORTS    2
#define HPD_STRING_SIZE			30

struct dp_drm_mst_fw_helper_ops {
@@ -89,6 +88,7 @@ struct dp_mst_sim_mode {
	struct work_struct conn_destroy_work;
	const struct drm_dp_mst_topology_cbs *cbs;
	int pbn_div;
	u32 port_cnt;
};

struct dp_mst_bridge {
@@ -175,7 +175,7 @@ static void drm_dp_mst_sim_link_probe_work(struct work_struct *work)
		break;
	}

	for (cnt = 0; cnt < DP_MST_SIM_MAX_PORTS; cnt++) {
	for (cnt = 0; cnt < sim->port_cnt; cnt++) {
		sim->sim_port[cnt].port_id = cnt;

		sim->sim_port[cnt].connector = sim->cbs->add_connector(
@@ -205,7 +205,7 @@ static void drm_dp_mst_sim_conn_destroy_work(struct work_struct *work)
	sim = container_of(work, struct dp_mst_sim_mode, conn_destroy_work);
	mst = container_of(sim, struct dp_mst_private, simulator);

	for (cnt = 0; cnt < DP_MST_SIM_MAX_PORTS; cnt++) {
	for (cnt = 0; cnt < sim->port_cnt; cnt++) {

		sim->sim_port[cnt].status = connector_status_disconnected;

@@ -268,6 +268,7 @@ static bool drm_dp_sim_mst_allocate_vcpi(struct drm_dp_mst_topology_mgr *mgr,
	sim_port->start_slot = mst->simulator.free_slot_id;
	mst->simulator.vcpi[i] = sim_port->vcpi;
	mst->simulator.free_slot_id = mst->simulator.free_slot_id + slots;
	port->vcpi.vcpi = sim_port->vcpi;

	DP_MST_DEBUG("ch:%d, start_slot:%d, slots:%d\n",
			sim_port->port_id, sim_port->start_slot,
@@ -956,6 +957,7 @@ dp_mst_connector_detect(struct drm_connector *connector, bool force,
	struct dp_display *dp_display = c_conn->display;
	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
	enum drm_connector_status status;
	struct dp_mst_connector mst_conn;

	DP_MST_DEBUG("enter:\n");

@@ -963,6 +965,13 @@ dp_mst_connector_detect(struct drm_connector *connector, bool force,
			&mst->mst_mgr,
			c_conn->mst_port);

	memset(&mst_conn, 0, sizeof(mst_conn));
	dp_display->mst_get_connector_info(dp_display, connector, &mst_conn);
	if (mst_conn.conn == connector &&
			mst_conn.state != connector_status_unknown) {
		status = mst_conn.state;
	}

	DP_MST_DEBUG("mst connector:%d detect, status:%d\n",
			connector->base.id, status);

@@ -1372,7 +1381,7 @@ static void dp_mst_hpd_event_notify(struct dp_mst_private *mst, bool hpd_status)
/* DP Driver Callback OPs */

static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
		struct dp_mst_hdp_info *info)
		struct dp_mst_hpd_info *info)
{
	int rc;
	struct dp_display *dp = dp_display;
@@ -1385,8 +1394,10 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
				hpd_status);

	if (info && !info->mst_protocol) {
		if (hpd_status)
		if (hpd_status) {
			mst->simulator.edid = (struct edid *)info->edid;
			mst->simulator.port_cnt = info->mst_port_cnt;
		}
		mst->mst_fw_cbs = &drm_dp_sim_mst_fw_helper_ops;
	} else {
		mst->mst_fw_cbs = &drm_dp_mst_fw_helper_ops;
@@ -1403,7 +1414,8 @@ static void dp_mst_display_hpd(void *dp_display, bool hpd_status,
	DP_MST_DEBUG("exit:\n");
}

static void dp_mst_display_hpd_irq(void *dp_display)
static void dp_mst_display_hpd_irq(void *dp_display,
			struct dp_mst_hpd_info *info)
{
	int rc;
	struct dp_display *dp = dp_display;
@@ -1414,6 +1426,11 @@ static void dp_mst_display_hpd_irq(void *dp_display)

	DP_MST_DEBUG("enter:\n");

	if (info->mst_hpd_sim) {
		dp_mst_hotplug(&mst->mst_mgr);
		return;
	}

	rc = drm_dp_dpcd_read(mst->caps.drm_aux, DP_SINK_COUNT_ESI,
		esi, 14);
	if (rc != 14) {
Loading