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

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

Merge "Merge remote-tracking branch 'quic/dev/msm-4.14-display' into msm-4.14"

parents c1732fc0 fbe227f0
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -351,6 +351,9 @@
		qcom,mdss-rot-danger-lut = <0x0 0x0>;
		qcom,mdss-rot-safe-lut = <0x0000ffff 0x0000ffff>;

		qcom,mdss-rot-qos-cpu-mask = <0xf>;
		qcom,mdss-rot-qos-cpu-dma-latency = <75>;

		qcom,mdss-default-ot-rd-limit = <32>;
		qcom,mdss-default-ot-wr-limit = <32>;

+0 −1
Original line number Diff line number Diff line
@@ -413,7 +413,6 @@ CONFIG_DRM=y
CONFIG_DRM_MSM_REGISTER_LOGGING=y
CONFIG_DRM_SDE_EVTLOG_DEBUG=y
CONFIG_DRM_SDE_RSC=y
CONFIG_FB_VIRTUAL=y
CONFIG_BACKLIGHT_LCD_SUPPORT=y
CONFIG_BACKLIGHT_CLASS_DEVICE=y
CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y
+341 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#define pr_fmt(fmt)	"[drm-dp] %s: " fmt, __func__

#include <linux/debugfs.h>
#include <linux/slab.h>

#include "dp_power.h"
#include "dp_catalog.h"
@@ -35,6 +36,8 @@ struct dp_debug_private {
	u8 *dpcd;
	u32 dpcd_size;

	u32 mst_con_id;

	char exe_mode[SZ_32];
	char reg_dump[SZ_32];

@@ -149,7 +152,7 @@ static ssize_t dp_debug_write_edid(struct file *file,
			goto bail;
		}

		if (edid_buf_index < debug->edid_size)
		if (debug->edid && (edid_buf_index < debug->edid_size))
			debug->edid[edid_buf_index++] = d;

		buf_t += char_to_nib;
@@ -344,6 +347,112 @@ static ssize_t dp_debug_write_edid_modes(struct file *file,
	return len;
}

static ssize_t dp_debug_write_edid_modes_mst(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	struct dp_mst_connector *mst_connector;
	char buf[SZ_32];
	char *read_buf;
	size_t len = 0;

	int hdisplay = 0, vdisplay = 0, vrefresh = 0, aspect_ratio = 0;
	int con_id = 0, offset = 0, debug_en = 0;
	bool in_list = false;

	if (!debug)
		return -ENODEV;

	if (*ppos)
		goto end;

	len = min_t(size_t, count, SZ_32 - 1);
	if (copy_from_user(buf, user_buff, len))
		goto end;

	buf[len] = '\0';
	read_buf = buf;

	mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
	while (sscanf(read_buf, "%d %d %d %d %d %d%n", &debug_en, &con_id,
			&hdisplay, &vdisplay, &vrefresh, &aspect_ratio,
			&offset) == 6) {
		list_for_each_entry(mst_connector,
				&debug->dp_debug.dp_mst_connector_list.list,
				list) {
			if (mst_connector->con_id == con_id) {
				in_list = true;
				mst_connector->debug_en = (bool) debug_en;
				mst_connector->hdisplay = hdisplay;
				mst_connector->vdisplay = vdisplay;
				mst_connector->vrefresh = vrefresh;
				mst_connector->aspect_ratio = aspect_ratio;
			}
		}

		if (!in_list)
			pr_debug("dp connector id %d is invalid\n", con_id);

		in_list = false;
		read_buf += offset;
	}
	mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);
end:
	return len;
}

static ssize_t dp_debug_write_mst_con_id(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	struct dp_mst_connector *mst_connector;
	char buf[SZ_32];
	size_t len = 0;
	int con_id = 0;
	bool in_list = false;

	if (!debug)
		return -ENODEV;

	if (*ppos)
		goto end;

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

	buf[len] = '\0';

	if (kstrtoint(buf, 10, &con_id) != 0)
		goto clear;

	if (!con_id)
		goto clear;

	/* Verify that the connector id is for a valid mst connector. */
	mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
	list_for_each_entry(mst_connector,
			&debug->dp_debug.dp_mst_connector_list.list, list) {
		if (mst_connector->con_id == con_id) {
			in_list = true;
			debug->mst_con_id = con_id;
			break;
		}
	}
	mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);

	if (!in_list)
		pr_err("invalid connector id %u\n", con_id);

	goto end;
clear:
	pr_debug("clearing mst_con_id\n");
	debug->mst_con_id = 0;
end:
	return len;
}

static ssize_t dp_debug_bw_code_write(struct file *file,
		const char __user *user_buff, size_t count, loff_t *ppos)
{
@@ -713,6 +822,183 @@ static ssize_t dp_debug_read_edid_modes(struct file *file,
	return rc;
}

static ssize_t dp_debug_read_edid_modes_mst(struct file *file,
		char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	struct dp_mst_connector *mst_connector;
	char *buf;
	u32 len = 0, ret = 0, max_size = SZ_4K;
	int rc = 0;
	struct drm_connector *connector;
	struct drm_display_mode *mode;
	bool in_list = false;

	if (!debug) {
		pr_err("invalid data\n");
		rc = -ENODEV;
		goto error;
	}

	mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
	list_for_each_entry(mst_connector,
			&debug->dp_debug.dp_mst_connector_list.list, list) {
		if (mst_connector->con_id == debug->mst_con_id) {
			connector = mst_connector->conn;
			in_list = true;
		}
	}
	mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);

	if (!in_list) {
		pr_err("connector %u not in mst list\n", debug->mst_con_id);
		rc = -EINVAL;
		goto error;
	}

	if (!connector) {
		pr_err("connector is NULL\n");
		rc = -EINVAL;
		goto error;
	}

	if (*ppos)
		goto error;

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

	mutex_lock(&connector->dev->mode_config.mutex);
	list_for_each_entry(mode, &connector->modes, head) {
		ret = snprintf(buf + len, max_size,
				"%s %d %d %d %d %d 0x%x\n",
				mode->name, mode->vrefresh,
				mode->picture_aspect_ratio, mode->htotal,
				mode->vtotal, mode->clock, mode->flags);
		if (dp_debug_check_buffer_overflow(ret, &max_size, &len))
			break;
	}
	mutex_unlock(&connector->dev->mode_config.mutex);

	if (copy_to_user(user_buff, buf, len)) {
		kfree(buf);
		rc = -EFAULT;
		goto error;
	}

	*ppos += len;
	kfree(buf);

	return len;
error:
	return rc;
}

static ssize_t dp_debug_read_mst_con_id(struct file *file,
		char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	char *buf;
	u32 len = 0, ret = 0, max_size = SZ_4K;
	int rc = 0;

	if (!debug) {
		pr_err("invalid data\n");
		rc = -ENODEV;
		goto error;
	}

	if (*ppos)
		goto error;

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

	ret = snprintf(buf, max_size, "%u\n", debug->mst_con_id);
	len += ret;

	if (copy_to_user(user_buff, buf, len)) {
		kfree(buf);
		rc = -EFAULT;
		goto error;
	}

	*ppos += len;
	kfree(buf);

	return len;
error:
	return rc;
}

static ssize_t dp_debug_read_mst_conn_info(struct file *file,
		char __user *user_buff, size_t count, loff_t *ppos)
{
	struct dp_debug_private *debug = file->private_data;
	struct dp_mst_connector *mst_connector;
	char *buf;
	u32 len = 0, ret = 0, max_size = SZ_4K;
	int rc = 0;
	struct drm_connector *connector;

	if (!debug) {
		pr_err("invalid data\n");
		rc = -ENODEV;
		goto error;
	}

	if (*ppos)
		goto error;

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

	mutex_lock(&debug->dp_debug.dp_mst_connector_list.lock);
	list_for_each_entry(mst_connector,
			&debug->dp_debug.dp_mst_connector_list.list, list) {
		/* Do not print info for head node */
		if (mst_connector->con_id == -1)
			continue;

		connector = mst_connector->conn;

		if (!connector) {
			pr_err("connector for id %d is NULL\n",
					mst_connector->con_id);
			continue;
		}

		ret = snprintf(buf + len, max_size,
				"conn name:%s, conn id:%d\n", connector->name,
				connector->base.id);
		if (dp_debug_check_buffer_overflow(ret, &max_size, &len))
			break;
	}
	mutex_unlock(&debug->dp_debug.dp_mst_connector_list.lock);

	if (copy_to_user(user_buff, buf, len)) {
		kfree(buf);
		rc = -EFAULT;
		goto error;
	}

	*ppos += len;
	kfree(buf);

	return len;
error:
	return rc;
}

static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
		size_t count, loff_t *ppos)
{
@@ -1209,6 +1495,23 @@ static const struct file_operations edid_modes_fops = {
	.write = dp_debug_write_edid_modes,
};

static const struct file_operations edid_modes_mst_fops = {
	.open = simple_open,
	.read = dp_debug_read_edid_modes_mst,
	.write = dp_debug_write_edid_modes_mst,
};

static const struct file_operations mst_conn_info_fops = {
	.open = simple_open,
	.read = dp_debug_read_mst_conn_info,
};

static const struct file_operations mst_con_id_fops = {
	.open = simple_open,
	.read = dp_debug_read_mst_con_id,
	.write = dp_debug_write_mst_con_id,
};

static const struct file_operations hpd_fops = {
	.open = simple_open,
	.write = dp_debug_write_hpd,
@@ -1328,6 +1631,33 @@ static int dp_debug_init(struct dp_debug *dp_debug)
		goto error_remove_dir;
	}

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

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

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

	file = debugfs_create_file("hpd", 0644, dir,
					debug, &hpd_fops);
	if (IS_ERR_OR_NULL(file)) {
@@ -1537,6 +1867,16 @@ struct dp_debug *dp_debug_get(struct dp_debug_in *in)

	dp_debug->get_edid = dp_debug_get_edid;

	INIT_LIST_HEAD(&dp_debug->dp_mst_connector_list.list);

	/*
	 * Do not associate the head of the list with any connector in order to
	 * maintain backwards compatibility with the SST use case.
	 */
	dp_debug->dp_mst_connector_list.con_id = -1;
	dp_debug->dp_mst_connector_list.conn = NULL;
	dp_debug->dp_mst_connector_list.debug_en = false;

	return dp_debug;
error:
	return ERR_PTR(rc);
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@
#include "dp_link.h"
#include "dp_usbpd.h"
#include "dp_aux.h"
#include "dp_display.h"

/**
 * struct dp_debug
@@ -43,6 +44,7 @@ struct dp_debug {
	u32 max_pclk_khz;
	bool force_encryption;
	char hdcp_status[SZ_128];
	struct dp_mst_connector dp_mst_connector_list;

	u8 *(*get_edid)(struct dp_debug *dp_debug);
};
+101 −1
Original line number Diff line number Diff line
@@ -231,6 +231,10 @@ static void dp_display_hdcp_cb_work(struct work_struct *work)
	u32 hdcp_auth_state;

	dp = container_of(dw, struct dp_display_private, hdcp_cb_work);

	if (!dp->power_on || atomic_read(&dp->aborted))
		return;

	status = &dp->link->hdcp_status;

	if (status->hdcp_state == HDCP_STATE_INACTIVE) {
@@ -294,8 +298,10 @@ static void dp_display_notify_hdcp_status_cb(void *ptr,

	dp->link->hdcp_status.hdcp_state = state;

	if (dp->is_connected)
	mutex_lock(&dp->session_lock);
	if (dp->power_on && !atomic_read(&dp->aborted))
		queue_delayed_work(dp->wq, &dp->hdcp_cb_work, HZ/4);
	mutex_unlock(&dp->session_lock);
}

static void dp_display_check_source_hdcp_caps(struct dp_display_private *dp)
@@ -1648,6 +1654,9 @@ static enum drm_mode_status dp_display_validate_mode(
	struct dp_panel *dp_panel;
	struct dp_debug *debug;
	enum drm_mode_status mode_status = MODE_BAD;
	bool in_list = false;
	struct dp_mst_connector *mst_connector;
	int hdis, vdis, vref, ar, _hdis, _vdis, _vref, _ar;

	if (!dp_display || !mode || !panel) {
		pr_err("invalid params\n");
@@ -1691,6 +1700,58 @@ static enum drm_mode_status dp_display_validate_mode(
		goto end;
	}

	/*
	 * If the connector exists in the mst connector list and if debug is
	 * enabled for that connector, use the mst connector settings from the
	 * list for validation. Otherwise, use non-mst default settings.
	 */
	mutex_lock(&debug->dp_mst_connector_list.lock);

	if (list_empty(&debug->dp_mst_connector_list.list)) {
		mutex_unlock(&debug->dp_mst_connector_list.lock);
		goto verify_default;
	}

	list_for_each_entry(mst_connector, &debug->dp_mst_connector_list.list,
			list) {
		if (mst_connector->con_id == dp_panel->connector->base.id) {
			in_list = true;

			if (!mst_connector->debug_en) {
				mode_status = MODE_OK;
				mutex_unlock(
				&debug->dp_mst_connector_list.lock);
				goto end;
			}

			hdis = mst_connector->hdisplay;
			vdis = mst_connector->vdisplay;
			vref = mst_connector->vrefresh;
			ar = mst_connector->aspect_ratio;

			_hdis = mode->hdisplay;
			_vdis = mode->vdisplay;
			_vref = mode->vrefresh;
			_ar = mode->picture_aspect_ratio;

			if (hdis == _hdis && vdis == _vdis && vref == _vref &&
					ar == _ar) {
				mode_status = MODE_OK;
				mutex_unlock(
				&debug->dp_mst_connector_list.lock);
				goto end;
			}

			break;
		}
	}

	mutex_unlock(&debug->dp_mst_connector_list.lock);

	if (in_list)
		goto end;

verify_default:
	if (debug->debug_en && (mode->hdisplay != debug->hdisplay ||
			mode->vdisplay != debug->vdisplay ||
			mode->vrefresh != debug->vrefresh ||
@@ -1888,6 +1949,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,
	struct dp_panel_in panel_in;
	struct dp_panel *dp_panel;
	struct dp_display_private *dp;
	struct dp_mst_connector *mst_connector;

	if (!dp_display || !connector) {
		pr_err("invalid input\n");
@@ -1896,8 +1958,11 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,

	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;
	}

@@ -1912,6 +1977,7 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,
	if (IS_ERR(dp_panel)) {
		rc = PTR_ERR(dp_panel);
		pr_err("failed to initialize panel, rc = %d\n", rc);
		mutex_unlock(&dp->session_lock);
		return rc;
	}

@@ -1920,12 +1986,28 @@ static int dp_display_mst_connector_install(struct dp_display *dp_display,
		rc = PTR_ERR(dp_panel->audio);
		pr_err("[mst] failed to initialize audio, rc = %d\n", rc);
		dp_panel->audio = NULL;
		mutex_unlock(&dp->session_lock);
		return rc;
	}

	DP_MST_DEBUG("dp mst connector installed. conn:%d\n",
			connector->base.id);

	mutex_lock(&dp->debug->dp_mst_connector_list.lock);

	mst_connector = kmalloc(sizeof(struct dp_mst_connector),
			GFP_KERNEL);
	mst_connector->debug_en = false;
	mst_connector->conn = connector;
	mst_connector->con_id = connector->base.id;
	INIT_LIST_HEAD(&mst_connector->list);

	list_add(&mst_connector->list,
			&dp->debug->dp_mst_connector_list.list);

	mutex_unlock(&dp->debug->dp_mst_connector_list.lock);
	mutex_unlock(&dp->session_lock);

	return 0;
}

@@ -1936,6 +2018,7 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display,
	struct sde_connector *sde_conn;
	struct dp_panel *dp_panel;
	struct dp_display_private *dp;
	struct dp_mst_connector *con_to_remove, *temp_con;

	if (!dp_display || !connector) {
		pr_err("invalid input\n");
@@ -1944,14 +2027,18 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display,

	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;
	}

	sde_conn = to_sde_connector(connector);
	if (!sde_conn->drv_panel) {
		pr_err("invalid panel for connector:%d\n", connector->base.id);
		mutex_unlock(&dp->session_lock);
		return -EINVAL;
	}

@@ -1962,6 +2049,19 @@ static int dp_display_mst_connector_uninstall(struct dp_display *dp_display,
	DP_MST_DEBUG("dp mst connector uninstalled. conn:%d\n",
			connector->base.id);

	mutex_lock(&dp->debug->dp_mst_connector_list.lock);

	list_for_each_entry_safe(con_to_remove, temp_con,
			&dp->debug->dp_mst_connector_list.list, list) {
		if (con_to_remove->con_id == connector->base.id) {
			list_del(&con_to_remove->list);
			kfree(con_to_remove);
		}
	}

	mutex_unlock(&dp->debug->dp_mst_connector_list.lock);
	mutex_unlock(&dp->session_lock);

	return rc;
}

Loading