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

Commit d937eb26 authored by Ajay Singh Parmar's avatar Ajay Singh Parmar
Browse files

drm/msm/dp: add support for custom dpcd



Add debug fs support for custom dpcd so that DisplayPort
driver can use a custom dpcd instead of the dpcd read
from the sink. This is needed for debugging and testing
purposes.

CRs-Fixed: 2128730
Change-Id: I61d8b22901a7550932e7870ea06ff1026cc7a13c
Signed-off-by: default avatarAjay Singh Parmar <aparmar@codeaurora.org>
parent fae11670
Loading
Loading
Loading
Loading
+94 −0
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ struct dp_debug_private {
	u8 *edid;
	u32 edid_size;

	u8 *dpcd;
	u32 dpcd_size;

	struct dp_usbpd *usbpd;
	struct dp_link *link;
	struct dp_panel *panel;
@@ -106,6 +109,73 @@ static ssize_t dp_debug_write_edid(struct file *file,
	return rc;
}

static ssize_t dp_debug_write_dpcd(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	u8 *buf = NULL, *buf_t = NULL, *dpcd = NULL;
	const int char_to_nib = 2;
	size_t dpcd_size = 0;
	size_t size = 0, dpcd_buf_index = 0;
	ssize_t rc = count;

	pr_debug("count=%zu\n", count);

	if (!debug)
		return -ENODEV;

	if (*ppos)
		goto bail;

	size = min_t(size_t, count, SZ_32);

	buf = kzalloc(size, GFP_KERNEL);
	if (!buf) {
		rc = -ENOMEM;
		goto bail;
	}

	if (copy_from_user(buf, user_buff, size))
		goto bail;

	dpcd_size = size / char_to_nib;
	buf_t = buf;

	memset(debug->dpcd, 0, debug->dpcd_size);

	if (dpcd_size != debug->dpcd_size) {
		pr_debug("clearing debug dpcd\n");
		goto bail;
	}

	while (dpcd_size--) {
		char t[3];
		int d;

		memcpy(t, buf_t, sizeof(char) * char_to_nib);
		t[char_to_nib] = '\0';

		if (kstrtoint(t, 16, &d)) {
			pr_err("kstrtoint error\n");
			goto bail;
		}

		if (dpcd_buf_index < debug->dpcd_size)
			debug->dpcd[dpcd_buf_index++] = d;

		buf_t += char_to_nib;
	}

	print_hex_dump(KERN_DEBUG, "DEBUG DPCD: ", DUMP_PREFIX_NONE,
		8, 1, debug->dpcd, debug->dpcd_size, false);

	dpcd = debug->dpcd;
bail:
	kfree(buf);
	debug->panel->set_dpcd(debug->panel, dpcd);
	return rc;
}

static ssize_t dp_debug_write_hpd(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
@@ -503,6 +573,11 @@ static const struct file_operations edid_fops = {
	.write = dp_debug_write_edid,
};

static const struct file_operations dpcd_fops = {
	.open = simple_open,
	.write = dp_debug_write_dpcd,
};

static const struct file_operations connected_fops = {
	.open = simple_open,
	.read = dp_debug_read_connected,
@@ -585,6 +660,15 @@ static int dp_debug_init(struct dp_debug *dp_debug)
		goto error_remove_dir;
	}

	file = debugfs_create_file("dpcd", 0644, dir,
					debug, &dpcd_fops);
	if (IS_ERR_OR_NULL(file)) {
		rc = PTR_ERR(file);
		pr_err("[%s] debugfs dpcd failed, rc=%d\n",
			DEBUG_NAME, rc);
		goto error_remove_dir;
	}

	return 0;

error_remove_dir:
@@ -622,6 +706,15 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,

	debug->edid_size = SZ_256;

	debug->dpcd = devm_kzalloc(dev, SZ_16, GFP_KERNEL);
	if (!debug->dpcd) {
		rc = -ENOMEM;
		kfree(debug);
		goto error;
	}

	debug->dpcd_size = SZ_16;

	debug->dp_debug.debug_en = false;
	debug->usbpd = usbpd;
	debug->link = link;
@@ -671,5 +764,6 @@ void dp_debug_put(struct dp_debug *dp_debug)
	dp_debug_deinit(dp_debug);

	devm_kfree(debug->dev, debug->edid);
	devm_kfree(debug->dev, debug->dpcd);
	devm_kfree(debug->dev, debug);
}
+37 −6
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ struct dp_panel_private {
	struct dp_catalog_panel *catalog;
	bool aux_cfg_update_done;
	bool custom_edid;
	bool custom_dpcd;
};

static const struct dp_panel_info fail_safe = {
@@ -70,14 +71,19 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
	link_info = &dp_panel->link_info;

	if (!panel->custom_dpcd) {
		rlen = drm_dp_dpcd_read(panel->aux->drm_aux, DP_DPCD_REV,
		dpcd, (DP_RECEIVER_CAP_SIZE + 1));
			dp_panel->dpcd, (DP_RECEIVER_CAP_SIZE + 1));
		if (rlen < (DP_RECEIVER_CAP_SIZE + 1)) {
			pr_err("dpcd read failed, rlen=%d\n", rlen);
			rc = -EINVAL;
			goto end;
		}

		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ",
			DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
	}

	link_info->revision = dp_panel->dpcd[DP_DPCD_REV];

	major = (link_info->revision >> 4) & 0x0f;
@@ -159,6 +165,30 @@ static int dp_panel_set_edid(struct dp_panel *dp_panel, u8 *edid)
	return 0;
}

static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd)
{
	struct dp_panel_private *panel;
	u8 *dp_dpcd;

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

	dp_dpcd = dp_panel->dpcd;

	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);

	if (dpcd) {
		memcpy(dp_dpcd, dpcd, DP_RECEIVER_CAP_SIZE + 1);
		panel->custom_dpcd = true;
	} else {
		panel->custom_dpcd = false;
	}

	return 0;
}

static int dp_panel_read_edid(struct dp_panel *dp_panel,
	struct drm_connector *connector)
{
@@ -569,6 +599,7 @@ struct dp_panel *dp_panel_get(struct dp_panel_in *in)
	dp_panel->get_modes = dp_panel_get_modes;
	dp_panel->handle_sink_request = dp_panel_handle_sink_request;
	dp_panel->set_edid = dp_panel_set_edid;
	dp_panel->set_dpcd = dp_panel_set_dpcd;

	dp_panel_edid_register(panel);

+2 −1
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ struct dp_panel_in {

struct dp_panel {
	/* dpcd raw data */
	u8 dpcd[DP_RECEIVER_CAP_SIZE];
	u8 dpcd[DP_RECEIVER_CAP_SIZE + 1];
	u8 ds_ports[DP_MAX_DOWNSTREAM_PORTS];

	struct drm_dp_link link_info;
@@ -85,6 +85,7 @@ struct dp_panel {
		struct drm_connector *connector, struct dp_display_mode *mode);
	void (*handle_sink_request)(struct dp_panel *dp_panel);
	int (*set_edid)(struct dp_panel *dp_panel, u8 *edid);
	int (*set_dpcd)(struct dp_panel *dp_panel, u8 *dpcd);
};

/**