drm/msm/dp: add support for simulation

Add debugfs node to enable/disable simulation mode.
Avoid AUX communication in simulation mode and override
it with debugfs data. This can be used for a quick
DP validation by triggering hot plug using debugfs nodes.

Change-Id: Id6a5112a4565feb15decf36b346c8cfd9783fd6f
Signed-off-by: Ajay Singh Parmar <aparmar@codeaurora.org>
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.c b/drivers/gpu/drm/msm/dp/dp_aux.c
index 79f2ec9..0a3fb24 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.c
+++ b/drivers/gpu/drm/msm/dp/dp_aux.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -29,22 +29,25 @@ struct dp_aux_private {
 	struct dp_aux dp_aux;
 	struct dp_catalog_aux *catalog;
 	struct dp_aux_cfg *cfg;
-
 	struct mutex mutex;
 	struct completion comp;
+	struct drm_dp_aux drm_aux;
 
-	u32 aux_error_num;
-	u32 retry_cnt;
 	bool cmd_busy;
 	bool native;
 	bool read;
 	bool no_send_addr;
 	bool no_send_stop;
+
 	u32 offset;
 	u32 segment;
+	u32 aux_error_num;
+	u32 retry_cnt;
+
 	atomic_t aborted;
 
-	struct drm_dp_aux drm_aux;
+	u8 *dpcd;
+	u8 *edid;
 };
 
 static char *dp_aux_get_error(u32 aux_error)
@@ -320,6 +323,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
  *
  * @aux: DP AUX private structure
  * @input_msg: input message from DRM upstream APIs
+ * @send_seg: send the seg to sink
  *
  * return: void
  *
@@ -327,7 +331,7 @@ static void dp_aux_update_offset_and_segment(struct dp_aux_private *aux,
  * sinks that do not handle the i2c middle-of-transaction flag correctly.
  */
 static void dp_aux_transfer_helper(struct dp_aux_private *aux,
-		struct drm_dp_aux_msg *input_msg)
+		struct drm_dp_aux_msg *input_msg, bool send_seg)
 {
 	struct drm_dp_aux_msg helper_msg;
 	u32 const message_size = 0x10;
@@ -346,7 +350,7 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux,
 	 * duplicate AUX transactions related to this while reading the
 	 * first 16 bytes of each block.
 	 */
-	if (!(aux->offset % edid_block_length))
+	if (!(aux->offset % edid_block_length) || !send_seg)
 		goto end;
 
 	aux->read = false;
@@ -388,26 +392,16 @@ static void dp_aux_transfer_helper(struct dp_aux_private *aux,
 		aux->segment = 0x0; /* reset segment at end of block */
 }
 
-/*
- * This function does the real job to process an AUX transaction.
- * It will call aux_reset() function to reset the AUX channel,
- * if the waiting is timeout.
- */
-static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
-		struct drm_dp_aux_msg *msg)
+static int dp_aux_transfer_ready(struct dp_aux_private *aux,
+		struct drm_dp_aux_msg *msg, bool send_seg)
 {
-	ssize_t ret;
+	int ret = 0;
 	int const aux_cmd_native_max = 16;
 	int const aux_cmd_i2c_max = 128;
-	int const retry_count = 5;
-	struct dp_aux_private *aux = container_of(drm_aux,
-		struct dp_aux_private, drm_aux);
-
-	mutex_lock(&aux->mutex);
 
 	if (atomic_read(&aux->aborted)) {
 		ret = -ETIMEDOUT;
-		goto unlock_exit;
+		goto error;
 	}
 
 	aux->native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
@@ -416,8 +410,7 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
 	if ((msg->size == 0) || (msg->buffer == NULL)) {
 		msg->reply = aux->native ?
 			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
-		ret = msg->size;
-		goto unlock_exit;
+		goto error;
 	}
 
 	/* msg sanity check */
@@ -426,14 +419,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
 		pr_err("%s: invalid msg: size(%zu), request(%x)\n",
 			__func__, msg->size, msg->request);
 		ret = -EINVAL;
-		goto unlock_exit;
+		goto error;
 	}
 
 	dp_aux_update_offset_and_segment(aux, msg);
-	dp_aux_transfer_helper(aux, msg);
+
+	dp_aux_transfer_helper(aux, msg, send_seg);
 
 	aux->read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
-	aux->cmd_busy = true;
 
 	if (aux->read) {
 		aux->no_send_addr = true;
@@ -443,6 +436,98 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
 		aux->no_send_stop = true;
 	}
 
+	aux->cmd_busy = true;
+error:
+	return ret;
+}
+
+static ssize_t dp_aux_transfer_debug(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u8 buf[SZ_64];
+	u32 timeout;
+	ssize_t ret;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
+
+	ret = dp_aux_transfer_ready(aux, msg, false);
+	if (ret)
+		goto end;
+
+	aux->aux_error_num = DP_AUX_ERR_NONE;
+
+	if (aux->native) {
+		if (aux->read && ((msg->address + msg->size) < SZ_1K)) {
+			aux->dp_aux.reg = msg->address;
+
+			reinit_completion(&aux->comp);
+			timeout = wait_for_completion_timeout(&aux->comp, HZ);
+			if (!timeout)
+				pr_err("aux timeout for 0x%x\n", msg->address);
+
+			aux->dp_aux.reg = 0xFFFF;
+
+			memcpy(msg->buffer, aux->dpcd + msg->address,
+				msg->size);
+			aux->aux_error_num = DP_AUX_ERR_NONE;
+		} else {
+			memset(msg->buffer, 0, msg->size);
+		}
+	} else {
+		if (aux->read && msg->address == 0x50) {
+			memcpy(msg->buffer,
+				aux->edid + aux->offset - 16,
+				msg->size);
+		}
+	}
+
+	if (aux->aux_error_num == DP_AUX_ERR_NONE) {
+		snprintf(buf, SZ_64, "[drm-dp] dbg: %5s %5s %5xh(%2zu): ",
+			aux->native ? "NATIVE" : "I2C",
+			aux->read ? "READ" : "WRITE",
+			msg->address, msg->size);
+
+		print_hex_dump(KERN_DEBUG, buf,
+			DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false);
+
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+	} else {
+		/* Reply defer to retry */
+		msg->reply = aux->native ?
+			DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+	}
+
+	ret = msg->size;
+end:
+	return ret;
+}
+
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call aux_reset() function to reset the AUX channel,
+ * if the waiting is timeout.
+ */
+static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
+		struct drm_dp_aux_msg *msg)
+{
+	u8 buf[SZ_64];
+	ssize_t ret;
+	int const retry_count = 5;
+	struct dp_aux_private *aux = container_of(drm_aux,
+		struct dp_aux_private, drm_aux);
+
+	mutex_lock(&aux->mutex);
+
+	ret = dp_aux_transfer_ready(aux, msg, true);
+	if (ret)
+		goto unlock_exit;
+
+	if (!aux->cmd_busy) {
+		ret = msg->size;
+		goto unlock_exit;
+	}
+
 	ret = dp_aux_cmd_fifo_tx(aux, msg);
 	if ((ret < 0) && aux->native && !atomic_read(&aux->aborted)) {
 		aux->retry_cnt++;
@@ -459,6 +544,14 @@ static ssize_t dp_aux_transfer(struct drm_dp_aux *drm_aux,
 		if (aux->read)
 			dp_aux_cmd_fifo_rx(aux, msg);
 
+		snprintf(buf, SZ_64, "[drm-dp] %5s %5s %5xh(%2zu): ",
+			aux->native ? "NATIVE" : "I2C",
+			aux->read ? "READ" : "WRITE",
+			msg->address, msg->size);
+
+		print_hex_dump(KERN_DEBUG, buf,
+			DUMP_PREFIX_NONE, 8, 1, msg->buffer, msg->size, false);
+
 		msg->reply = aux->native ?
 			DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
 	} else {
@@ -558,6 +651,41 @@ static void dp_aux_deregister(struct dp_aux *dp_aux)
 	drm_dp_aux_unregister(&aux->drm_aux);
 }
 
+static void dp_aux_dpcd_updated(struct dp_aux *dp_aux)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	complete(&aux->comp);
+}
+
+static void dp_aux_set_sim_mode(struct dp_aux *dp_aux, bool en,
+		u8 *edid, u8 *dpcd)
+{
+	struct dp_aux_private *aux;
+
+	if (!dp_aux) {
+		pr_err("invalid input\n");
+		return;
+	}
+
+	aux = container_of(dp_aux, struct dp_aux_private, dp_aux);
+
+	aux->edid = edid;
+	aux->dpcd = dpcd;
+
+	if (en)
+		aux->drm_aux.transfer = dp_aux_transfer_debug;
+	else
+		aux->drm_aux.transfer = dp_aux_transfer;
+}
+
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
 		struct dp_aux_cfg *aux_cfg)
 {
@@ -586,6 +714,7 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
 	aux->cfg = aux_cfg;
 	dp_aux = &aux->dp_aux;
 	aux->retry_cnt = 0;
+	aux->dp_aux.reg = 0xFFFF;
 
 	dp_aux->isr     = dp_aux_isr;
 	dp_aux->init    = dp_aux_init;
@@ -594,6 +723,8 @@ struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
 	dp_aux->drm_aux_deregister = dp_aux_deregister;
 	dp_aux->reconfig = dp_aux_reconfig;
 	dp_aux->abort = dp_aux_abort_transaction;
+	dp_aux->dpcd_updated = dp_aux_dpcd_updated;
+	dp_aux->set_sim_mode = dp_aux_set_sim_mode;
 
 	return dp_aux;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_aux.h b/drivers/gpu/drm/msm/dp/dp_aux.h
index e8cb1cc..bf52d57 100644
--- a/drivers/gpu/drm/msm/dp/dp_aux.h
+++ b/drivers/gpu/drm/msm/dp/dp_aux.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -18,6 +18,19 @@
 #include "dp_catalog.h"
 #include "drm_dp_helper.h"
 
+#define DP_STATE_NOTIFICATION_SENT          BIT(0)
+#define DP_STATE_TRAIN_1_STARTED            BIT(1)
+#define DP_STATE_TRAIN_1_SUCCEEDED          BIT(2)
+#define DP_STATE_TRAIN_1_FAILED             BIT(3)
+#define DP_STATE_TRAIN_2_STARTED            BIT(4)
+#define DP_STATE_TRAIN_2_SUCCEEDED          BIT(5)
+#define DP_STATE_TRAIN_2_FAILED             BIT(6)
+#define DP_STATE_CTRL_POWERED_ON            BIT(7)
+#define DP_STATE_CTRL_POWERED_OFF           BIT(8)
+#define DP_STATE_LINK_MAINTENANCE_STARTED   BIT(9)
+#define DP_STATE_LINK_MAINTENANCE_COMPLETED BIT(10)
+#define DP_STATE_LINK_MAINTENANCE_FAILED    BIT(11)
+
 enum dp_aux_error {
 	DP_AUX_ERR_NONE	= 0,
 	DP_AUX_ERR_ADDR	= -1,
@@ -29,6 +42,9 @@ enum dp_aux_error {
 };
 
 struct dp_aux {
+	u32 reg;
+	u32 state;
+
 	struct drm_dp_aux *drm_aux;
 	int (*drm_aux_register)(struct dp_aux *aux);
 	void (*drm_aux_deregister)(struct dp_aux *aux);
@@ -37,6 +53,8 @@ struct dp_aux {
 	void (*deinit)(struct dp_aux *aux);
 	void (*reconfig)(struct dp_aux *aux);
 	void (*abort)(struct dp_aux *aux);
+	void (*dpcd_updated)(struct dp_aux *aux);
+	void (*set_sim_mode)(struct dp_aux *aux, bool en, u8 *edid, u8 *dpcd);
 };
 
 struct dp_aux *dp_aux_get(struct device *dev, struct dp_catalog_aux *catalog,
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.c b/drivers/gpu/drm/msm/dp/dp_ctrl.c
index d9fc7df..bcd8a2a 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.c
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.c
@@ -820,6 +820,10 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 	u8 link_status[DP_LINK_STATUS_SIZE];
 	int const maximum_retries = 5;
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_1_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -829,13 +833,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 		DP_LINK_SCRAMBLING_DISABLE); /* train_1 */
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	tries = 0;
@@ -879,6 +883,13 @@ static int dp_ctrl_link_train_1(struct dp_ctrl_private *ctrl)
 			break;
 		}
 	}
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_1_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_1_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_1_SUCCEEDED;
 
 	return ret;
 }
@@ -922,6 +933,10 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 	int const maximum_retries = 5;
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_FAILED;
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_SUCCEEDED;
+	ctrl->aux->state |= DP_STATE_TRAIN_2_STARTED;
+
 	dp_ctrl_state_ctrl(ctrl, 0);
 	/* Make sure to clear the current pattern before starting a new one */
 	wmb();
@@ -934,14 +949,14 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 	ret = dp_ctrl_update_vx_px(ctrl);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 	ctrl->catalog->set_pattern(ctrl->catalog, pattern);
 	ret = dp_ctrl_train_pattern_set(ctrl,
 		pattern | DP_RECOVERED_CLOCK_OUT_EN);
 	if (ret <= 0) {
 		ret = -EINVAL;
-		return ret;
+		goto end;
 	}
 
 	do  {
@@ -968,7 +983,13 @@ static int dp_ctrl_link_training_2(struct dp_ctrl_private *ctrl)
 			break;
 		}
 	} while (!atomic_read(&ctrl->aborted));
+end:
+	ctrl->aux->state &= ~DP_STATE_TRAIN_2_STARTED;
 
+	if (ret)
+		ctrl->aux->state |= DP_STATE_TRAIN_2_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_TRAIN_2_SUCCEEDED;
 	return ret;
 }
 
@@ -1109,8 +1130,7 @@ static int dp_ctrl_disable_mainlink_clocks(struct dp_ctrl_private *ctrl)
 	return ctrl->power->clk_enable(ctrl->power, DP_CTRL_PM, false);
 }
 
-static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl,
-	bool flip, bool multi_func)
+static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl, bool flip, bool reset)
 {
 	struct dp_ctrl_private *ctrl;
 	struct dp_catalog_ctrl *catalog;
@@ -1125,7 +1145,7 @@ static int dp_ctrl_host_init(struct dp_ctrl *dp_ctrl,
 	ctrl->orientation = flip;
 	catalog = ctrl->catalog;
 
-	if (!multi_func) {
+	if (reset) {
 		catalog->usb_reset(ctrl->catalog, flip);
 		catalog->phy_reset(ctrl->catalog);
 	}
@@ -1192,6 +1212,10 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
 		return -EINVAL;
 	}
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_COMPLETED;
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_FAILED;
+	ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_STARTED;
+
 	ctrl->dp_ctrl.push_idle(&ctrl->dp_ctrl);
 	ctrl->dp_ctrl.reset(&ctrl->dp_ctrl);
 
@@ -1231,6 +1255,13 @@ static int dp_ctrl_link_maintenance(struct dp_ctrl *dp_ctrl)
 		ret = dp_ctrl_setup_main_link(ctrl, true);
 	} while (ret == -EAGAIN);
 
+	ctrl->aux->state &= ~DP_STATE_LINK_MAINTENANCE_STARTED;
+
+	if (ret)
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_FAILED;
+	else
+		ctrl->aux->state |= DP_STATE_LINK_MAINTENANCE_COMPLETED;
+
 	return ret;
 }
 
diff --git a/drivers/gpu/drm/msm/dp/dp_ctrl.h b/drivers/gpu/drm/msm/dp/dp_ctrl.h
index 229c779..31d8f07 100644
--- a/drivers/gpu/drm/msm/dp/dp_ctrl.h
+++ b/drivers/gpu/drm/msm/dp/dp_ctrl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -23,7 +23,7 @@
 #include "dp_catalog.h"
 
 struct dp_ctrl {
-	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool multi_func);
+	int (*init)(struct dp_ctrl *dp_ctrl, bool flip, bool reset);
 	void (*deinit)(struct dp_ctrl *dp_ctrl);
 	int (*on)(struct dp_ctrl *dp_ctrl);
 	void (*off)(struct dp_ctrl *dp_ctrl);
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.c b/drivers/gpu/drm/msm/dp/dp_debug.c
index 054b3c8..a63b2c5 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.c
+++ b/drivers/gpu/drm/msm/dp/dp_debug.c
@@ -36,15 +36,52 @@ struct dp_debug_private {
 	u8 *dpcd;
 	u32 dpcd_size;
 
+	int vdo;
+
 	struct dp_usbpd *usbpd;
 	struct dp_link *link;
 	struct dp_panel *panel;
+	struct dp_aux *aux;
 	struct drm_connector **connector;
 	struct device *dev;
-
+	struct work_struct sim_work;
 	struct dp_debug dp_debug;
 };
 
+static int dp_debug_get_edid_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->edid) {
+		debug->edid = devm_kzalloc(debug->dev, SZ_256, GFP_KERNEL);
+		if (!debug->edid) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->edid_size = SZ_256;
+	}
+end:
+	return rc;
+}
+
+static int dp_debug_get_dpcd_buf(struct dp_debug_private *debug)
+{
+	int rc = 0;
+
+	if (!debug->dpcd) {
+		debug->dpcd = devm_kzalloc(debug->dev, SZ_1K, GFP_KERNEL);
+		if (!debug->dpcd) {
+			rc = -ENOMEM;
+			goto end;
+		}
+
+		debug->dpcd_size = SZ_1K;
+	}
+end:
+	return rc;
+}
+
 static ssize_t dp_debug_write_edid(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -75,7 +112,8 @@ static ssize_t dp_debug_write_edid(struct file *file,
 	edid_size = size / char_to_nib;
 	buf_t = buf;
 
-	memset(debug->edid, 0, debug->edid_size);
+	if (dp_debug_get_edid_buf(debug))
+		goto bail;
 
 	if (edid_size != debug->edid_size) {
 		pr_debug("clearing debug edid\n");
@@ -100,13 +138,13 @@ static ssize_t dp_debug_write_edid(struct file *file,
 		buf_t += char_to_nib;
 	}
 
-	print_hex_dump(KERN_DEBUG, "DEBUG EDID: ", DUMP_PREFIX_NONE,
-		16, 1, debug->edid, debug->edid_size, false);
-
 	edid = debug->edid;
 bail:
 	kfree(buf);
-	debug->panel->set_edid(debug->panel, edid);
+
+	if (!debug->dp_debug.sim_mode)
+		debug->panel->set_edid(debug->panel, edid);
+
 	return rc;
 }
 
@@ -119,8 +157,8 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 	size_t dpcd_size = 0;
 	size_t size = 0, dpcd_buf_index = 0;
 	ssize_t rc = count;
-
-	pr_debug("count=%zu\n", count);
+	char offset_ch[5];
+	u32 offset;
 
 	if (!debug)
 		return -ENODEV;
@@ -128,7 +166,7 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 	if (*ppos)
 		goto bail;
 
-	size = min_t(size_t, count, SZ_32);
+	size = min_t(size_t, count, SZ_2K);
 
 	buf = kzalloc(size, GFP_KERNEL);
 	if (!buf) {
@@ -139,16 +177,30 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 	if (copy_from_user(buf, user_buff, size))
 		goto bail;
 
-	dpcd_size = size / char_to_nib;
-	buf_t = buf;
+	memcpy(offset_ch, buf, 4);
+	offset_ch[4] = '\0';
 
-	memset(debug->dpcd, 0, debug->dpcd_size);
-
-	if (dpcd_size != debug->dpcd_size) {
-		pr_debug("clearing debug dpcd\n");
+	if (kstrtoint(offset_ch, 16, &offset)) {
+		pr_err("offset kstrtoint error\n");
 		goto bail;
 	}
 
+	if (dp_debug_get_dpcd_buf(debug))
+		goto bail;
+
+	if (offset == 0xFFFF) {
+		pr_err("clearing dpcd\n");
+		memset(debug->dpcd, 0, debug->dpcd_size);
+		goto bail;
+	}
+
+	size -= 4;
+
+	dpcd_size = size / char_to_nib;
+	buf_t = buf + 4;
+
+	dpcd_buf_index = offset;
+
 	while (dpcd_size--) {
 		char t[3];
 		int d;
@@ -167,16 +219,39 @@ static ssize_t dp_debug_write_dpcd(struct file *file,
 		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);
+	if (debug->dp_debug.sim_mode)
+		debug->aux->dpcd_updated(debug->aux);
+	else
+		debug->panel->set_dpcd(debug->panel, dpcd);
+
 	return rc;
 }
 
+static ssize_t dp_debug_read_dpcd(struct file *file,
+		char __user *user_buff, size_t count, loff_t *ppos)
+{
+	struct dp_debug_private *debug = file->private_data;
+	char buf[SZ_8];
+	u32 len = 0;
+
+	if (!debug)
+		return -ENODEV;
+
+	if (*ppos)
+		return 0;
+
+	len += snprintf(buf, SZ_8, "0x%x\n", debug->aux->reg);
+
+	if (copy_to_user(user_buff, buf, len))
+		return -EFAULT;
+
+	*ppos += len;
+	return len;
+}
+
 static ssize_t dp_debug_write_hpd(struct file *file,
 		const char __user *user_buff, size_t count, loff_t *ppos)
 {
@@ -421,7 +496,6 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
 	struct dp_debug_private *debug = file->private_data;
 	char *buf;
 	u32 len = 0, rc = 0;
-	u64 lclk = 0;
 	u32 max_size = SZ_4K;
 
 	if (!debug)
@@ -434,124 +508,60 @@ static ssize_t dp_debug_read_info(struct file *file, char __user *user_buff,
 	if (!buf)
 		return -ENOMEM;
 
-	rc = snprintf(buf + len, max_size, "\tname = %s\n", DEBUG_NAME);
+	rc = snprintf(buf + len, max_size, "\tstate=0x%x\n", debug->aux->state);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel\n\t\tmax_pclk_khz = %d\n",
-		debug->panel->max_pclk_khz);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdrm_dp_link\n\t\trate = %u\n",
+	rc = snprintf(buf + len, max_size, "\tlink_rate=%u\n",
 		debug->panel->link_info.rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tnum_lanes = %u\n",
+	rc = snprintf(buf + len, max_size, "\tnum_lanes=%u\n",
 		debug->panel->link_info.num_lanes);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tcapabilities = %lu\n",
-		debug->panel->link_info.capabilities);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\tdp_panel_info:\n\t\tactive = %dx%d\n",
+	rc = snprintf(buf + len, max_size, "\tresolution=%dx%d@%dHz\n",
 		debug->panel->pinfo.h_active,
-		debug->panel->pinfo.v_active);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tback_porch = %dx%d\n",
-		debug->panel->pinfo.h_back_porch,
-		debug->panel->pinfo.v_back_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tfront_porch = %dx%d\n",
-		debug->panel->pinfo.h_front_porch,
-		debug->panel->pinfo.v_front_porch);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tsync_width = %dx%d\n",
-		debug->panel->pinfo.h_sync_width,
-		debug->panel->pinfo.v_sync_width);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\tactive_low = %dx%d\n",
-		debug->panel->pinfo.h_active_low,
-		debug->panel->pinfo.v_active_low);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\th_skew = %d\n",
-		debug->panel->pinfo.h_skew);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	rc = snprintf(buf + len, max_size,
-		"\t\trefresh rate = %d\n",
+		debug->panel->pinfo.v_active,
 		debug->panel->pinfo.refresh_rate);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tpixel clock khz = %d\n",
+	rc = snprintf(buf + len, max_size, "\tpclock=%dKHz\n",
 		debug->panel->pinfo.pixel_clk_khz);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
-	rc = snprintf(buf + len, max_size,
-		"\t\tbpp = %d\n",
+	rc = snprintf(buf + len, max_size, "\tbpp=%d\n",
 		debug->panel->pinfo.bpp);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	/* Link Information */
-	rc = snprintf(buf + len, max_size,
-		"\tdp_link:\n\t\ttest_requested = %d\n",
-		debug->link->sink_request);
+	rc = snprintf(buf + len, max_size, "\ttest_req=%s\n",
+		dp_link_get_test_name(debug->link->sink_request));
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tlane_count = %d\n", debug->link->link_params.lane_count);
+		"\tlane_count=%d\n", debug->link->link_params.lane_count);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tbw_code = %d\n", debug->link->link_params.bw_code);
-	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
-		goto error;
-
-	lclk = drm_dp_bw_code_to_link_rate(
-			debug->link->link_params.bw_code) * 1000;
-	rc = snprintf(buf + len, max_size,
-		"\t\tlclk = %lld\n", lclk);
+		"\tbw_code=%d\n", debug->link->link_params.bw_code);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tv_level = %d\n", debug->link->phy_params.v_level);
+		"\tv_level=%d\n", debug->link->phy_params.v_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
 	rc = snprintf(buf + len, max_size,
-		"\t\tp_level = %d\n", debug->link->phy_params.p_level);
+		"\tp_level=%d\n", debug->link->phy_params.p_level);
 	if (dp_debug_check_buffer_overflow(rc, &max_size, &len))
 		goto error;
 
@@ -816,6 +826,90 @@ 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)
+{
+	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;
+
+		if (dp_debug_get_dpcd_buf(debug))
+			goto error;
+	} else {
+		if (debug->edid) {
+			devm_kfree(debug->dev, debug->edid);
+			debug->edid = NULL;
+		}
+
+		if (debug->dpcd) {
+			devm_kfree(debug->dev, debug->dpcd);
+			debug->dpcd = NULL;
+		}
+	}
+
+	debug->dp_debug.sim_mode = !!sim;
+
+	debug->aux->set_sim_mode(debug->aux, debug->dp_debug.sim_mode,
+			debug->edid, debug->dpcd);
+end:
+	return len;
+error:
+	devm_kfree(debug->dev, debug->edid);
+	return len;
+}
+
+static ssize_t dp_debug_write_attention(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 vdo;
+
+	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, &vdo) != 0)
+		goto end;
+
+	debug->vdo = vdo;
+
+	schedule_work(&debug->sim_work);
+end:
+	return len;
+}
+
 static const struct file_operations dp_debug_fops = {
 	.open = simple_open,
 	.read = dp_debug_read_info,
@@ -840,6 +934,7 @@ static const struct file_operations edid_fops = {
 static const struct file_operations dpcd_fops = {
 	.open = simple_open,
 	.write = dp_debug_write_dpcd,
+	.read = dp_debug_read_dpcd,
 };
 
 static const struct file_operations connected_fops = {
@@ -865,6 +960,16 @@ static const struct file_operations hdr_fops = {
 	.read = dp_debug_read_hdr,
 };
 
+static const struct file_operations sim_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_sim,
+};
+
+static const struct file_operations attention_fops = {
+	.open = simple_open,
+	.write = dp_debug_write_attention,
+};
+
 static int dp_debug_init(struct dp_debug *dp_debug)
 {
 	int rc = 0;
@@ -967,6 +1072,26 @@ static int dp_debug_init(struct dp_debug *dp_debug)
 		goto error_remove_dir;
 	}
 
+	file = debugfs_create_file("sim", 0644, dir,
+		debug, &sim_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs sim failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
+	file = debugfs_create_file("attention", 0644, dir,
+		debug, &attention_fops);
+
+	if (IS_ERR_OR_NULL(file)) {
+		rc = PTR_ERR(file);
+		pr_err("[%s] debugfs attention failed, rc=%d\n",
+			DEBUG_NAME, rc);
+		goto error_remove_dir;
+	}
+
 	return 0;
 
 error_remove_dir:
@@ -977,9 +1102,17 @@ static int dp_debug_init(struct dp_debug *dp_debug)
 	return rc;
 }
 
+static void dp_debug_sim_work(struct work_struct *work)
+{
+	struct dp_debug_private *debug =
+		container_of(work, typeof(*debug), sim_work);
+
+	debug->usbpd->simulate_attention(debug->usbpd, debug->vdo);
+}
+
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector)
+			struct dp_aux *aux, struct drm_connector **connector)
 {
 	int rc = 0;
 	struct dp_debug_private *debug;
@@ -997,28 +1130,13 @@ struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 		goto error;
 	}
 
-	debug->edid = devm_kzalloc(dev, SZ_256, GFP_KERNEL);
-	if (!debug->edid) {
-		rc = -ENOMEM;
-		kfree(debug);
-		goto error;
-	}
-
-	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;
+	INIT_WORK(&debug->sim_work, dp_debug_sim_work);
 
 	debug->dp_debug.debug_en = false;
 	debug->usbpd = usbpd;
 	debug->link = link;
 	debug->panel = panel;
+	debug->aux = aux;
 	debug->dev = dev;
 	debug->connector = connector;
 
@@ -1063,7 +1181,11 @@ 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);
+	if (debug->edid)
+		devm_kfree(debug->dev, debug->edid);
+
+	if (debug->dpcd)
+		devm_kfree(debug->dev, debug->dpcd);
+
 	devm_kfree(debug->dev, debug);
 }
diff --git a/drivers/gpu/drm/msm/dp/dp_debug.h b/drivers/gpu/drm/msm/dp/dp_debug.h
index 3b2d23e..5a5a786 100644
--- a/drivers/gpu/drm/msm/dp/dp_debug.h
+++ b/drivers/gpu/drm/msm/dp/dp_debug.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-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
@@ -18,6 +18,7 @@
 #include "dp_panel.h"
 #include "dp_link.h"
 #include "dp_usbpd.h"
+#include "dp_aux.h"
 
 /**
  * struct dp_debug
@@ -29,6 +30,7 @@
  */
 struct dp_debug {
 	bool debug_en;
+	bool sim_mode;
 	bool psm_enabled;
 	int aspect_ratio;
 	int vdisplay;
@@ -52,7 +54,7 @@ struct dp_debug {
  */
 struct dp_debug *dp_debug_get(struct device *dev, struct dp_panel *panel,
 			struct dp_usbpd *usbpd, struct dp_link *link,
-			struct drm_connector **connector);
+			struct dp_aux *aux, struct drm_connector **connector);
 /**
  * dp_debug_put()
  *
diff --git a/drivers/gpu/drm/msm/dp/dp_display.c b/drivers/gpu/drm/msm/dp/dp_display.c
index c5f62a5..63bc021 100644
--- a/drivers/gpu/drm/msm/dp/dp_display.c
+++ b/drivers/gpu/drm/msm/dp/dp_display.c
@@ -466,6 +466,7 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
 		bool hpd)
 {
 	u32 timeout_sec;
+	int ret = 0;
 
 	dp->dp_display.is_connected = hpd;
 
@@ -474,16 +475,20 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp,
 	else
 		timeout_sec = 10;
 
+	dp->aux->state |= DP_STATE_NOTIFICATION_SENT;
+
 	reinit_completion(&dp->notification_comp);
 	dp_display_send_hpd_event(dp);
 
 	if (!wait_for_completion_timeout(&dp->notification_comp,
 						HZ * timeout_sec)) {
 		pr_warn("%s timeout\n", hpd ? "connect" : "disconnect");
-		return -EINVAL;
+		ret = -EINVAL;
 	}
 
-	return 0;
+	dp->aux->state &= ~DP_STATE_NOTIFICATION_SENT;
+
+	return ret;
 }
 
 static int dp_display_process_hpd_high(struct dp_display_private *dp)
@@ -531,6 +536,7 @@ static int dp_display_process_hpd_high(struct dp_display_private *dp)
 static void dp_display_host_init(struct dp_display_private *dp)
 {
 	bool flip = false;
+	bool reset;
 
 	if (dp->core_initialized) {
 		pr_debug("DP core already initialized\n");
@@ -540,8 +546,10 @@ static void dp_display_host_init(struct dp_display_private *dp)
 	if (dp->usbpd->orientation == ORIENTATION_CC2)
 		flip = true;
 
+	reset = dp->debug->sim_mode ? false : !dp->usbpd->multi_func;
+
 	dp->power->init(dp->power, flip);
-	dp->ctrl->init(dp->ctrl, flip, dp->usbpd->multi_func);
+	dp->ctrl->init(dp->ctrl, flip, reset);
 	enable_irq(dp->irq);
 	dp->core_initialized = true;
 }
@@ -557,6 +565,7 @@ static void dp_display_host_deinit(struct dp_display_private *dp)
 	dp->power->deinit(dp->power);
 	disable_irq(dp->irq);
 	dp->core_initialized = false;
+	dp->aux->state = 0;
 }
 
 static int dp_display_process_hpd_low(struct dp_display_private *dp)
@@ -935,7 +944,7 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
 	}
 
 	dp->debug = dp_debug_get(dev, dp->panel, dp->usbpd,
-				dp->link, &dp->dp_display.connector);
+				dp->link, dp->aux, &dp->dp_display.connector);
 	if (IS_ERR(dp->debug)) {
 		rc = PTR_ERR(dp->debug);
 		pr_err("failed to initialize debug, rc = %d\n", rc);
@@ -1101,6 +1110,7 @@ static int dp_display_post_enable(struct dp_display *dp_display)
 end:
 	/* clear framework event notifier */
 	dp_display->post_open = NULL;
+	dp->aux->state |= DP_STATE_CTRL_POWERED_ON;
 
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
@@ -1191,7 +1201,7 @@ static int dp_display_disable(struct dp_display *dp_display)
 		dp->dp_display.is_connected = false;
 	}
 	dp->power_on = false;
-
+	dp->aux->state = DP_STATE_CTRL_POWERED_OFF;
 end:
 	complete_all(&dp->notification_comp);
 	mutex_unlock(&dp->session_lock);
diff --git a/drivers/gpu/drm/msm/dp/dp_link.c b/drivers/gpu/drm/msm/dp/dp_link.c
index 3ca247c..05629dd 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.c
+++ b/drivers/gpu/drm/msm/dp/dp_link.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -724,24 +724,6 @@ static int dp_link_parse_phy_test_params(struct dp_link_private *link)
 	return ret;
 }
 
-static char *dp_link_get_test_name(u32 test_requested)
-{
-	switch (test_requested) {
-	case DP_TEST_LINK_TRAINING:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
-	case DP_TEST_LINK_VIDEO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
-	case DP_TEST_LINK_EDID_READ:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
-	case DP_TEST_LINK_PHY_TEST_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
-	case DP_TEST_LINK_AUDIO_PATTERN:
-		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
-	default:
-		return "unknown";
-	}
-}
-
 /**
  * dp_link_is_video_audio_test_requested() - checks for audio/video link request
  * @link: link requested by the sink
diff --git a/drivers/gpu/drm/msm/dp/dp_link.h b/drivers/gpu/drm/msm/dp/dp_link.h
index 6f79b6a..46d30a7 100644
--- a/drivers/gpu/drm/msm/dp/dp_link.h
+++ b/drivers/gpu/drm/msm/dp/dp_link.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -83,6 +83,24 @@ struct dp_link_params {
 	u32 bw_code;
 };
 
+static inline char *dp_link_get_test_name(u32 test_requested)
+{
+	switch (test_requested) {
+	case DP_TEST_LINK_TRAINING:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_TRAINING);
+	case DP_TEST_LINK_VIDEO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_VIDEO_PATTERN);
+	case DP_TEST_LINK_EDID_READ:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_EDID_READ);
+	case DP_TEST_LINK_PHY_TEST_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_PHY_TEST_PATTERN);
+	case DP_TEST_LINK_AUDIO_PATTERN:
+		return DP_LINK_ENUM_STR(DP_TEST_LINK_AUDIO_PATTERN);
+	default:
+		return "unknown";
+	}
+}
+
 struct dp_link {
 	u32 sink_request;
 	u32 test_response;
diff --git a/drivers/gpu/drm/msm/dp/dp_panel.c b/drivers/gpu/drm/msm/dp/dp_panel.c
index d455ca1..822097c 100644
--- a/drivers/gpu/drm/msm/dp/dp_panel.c
+++ b/drivers/gpu/drm/msm/dp/dp_panel.c
@@ -136,9 +136,6 @@ static int dp_panel_read_dpcd(struct dp_panel *dp_panel)
 
 			goto end;
 		}
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK DPCD: ",
-			DUMP_PREFIX_NONE, 8, 1, dp_panel->dpcd, rlen, false);
 	}
 
 	rlen = drm_dp_dpcd_read(panel->aux->drm_aux,
@@ -271,35 +268,31 @@ static int dp_panel_set_dpcd(struct dp_panel *dp_panel, u8 *dpcd)
 static int dp_panel_read_edid(struct dp_panel *dp_panel,
 	struct drm_connector *connector)
 {
+	int ret = 0;
 	struct dp_panel_private *panel;
 
 	if (!dp_panel) {
 		pr_err("invalid input\n");
-		return -EINVAL;
+		ret = -EINVAL;
+		goto end;
 	}
 
 	panel = container_of(dp_panel, struct dp_panel_private, dp_panel);
 
 	if (panel->custom_edid) {
 		pr_debug("skip edid read in debug mode\n");
-		return 0;
+		goto end;
 	}
 
 	sde_get_edid(connector, &panel->aux->drm_aux->ddc,
 		(void **)&dp_panel->edid_ctrl);
 	if (!dp_panel->edid_ctrl->edid) {
 		pr_err("EDID read failed\n");
-	} else {
-		u8 *buf = (u8 *)dp_panel->edid_ctrl->edid;
-		u32 size = buf[0x7E] ? 256 : 128;
-
-		print_hex_dump(KERN_DEBUG, "[drm-dp] SINK EDID: ",
-			DUMP_PREFIX_NONE, 16, 1, buf, size, false);
-
-		return 0;
+		ret = -EINVAL;
+		goto end;
 	}
-
-	return -EINVAL;
+end:
+	return ret;
 }
 
 static int dp_panel_read_sink_caps(struct dp_panel *dp_panel,
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.c b/drivers/gpu/drm/msm/dp/dp_usbpd.c
index 2bd3bd4..42eb9b05 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.c
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -426,6 +426,28 @@ static int dp_usbpd_simulate_connect(struct dp_usbpd *dp_usbpd, bool hpd)
 	return rc;
 }
 
+static int dp_usbpd_simulate_attention(struct dp_usbpd *dp_usbpd, int vdo)
+{
+	int rc = 0;
+	struct dp_usbpd_private *pd;
+
+	if (!dp_usbpd) {
+		pr_err("invalid input\n");
+		rc = -EINVAL;
+		goto error;
+	}
+
+	pd = container_of(dp_usbpd, struct dp_usbpd_private, dp_usbpd);
+
+	pd->vdo = vdo;
+	dp_usbpd_get_status(pd);
+
+	if (pd->dp_cb && pd->dp_cb->attention)
+		pd->dp_cb->attention(pd->dev);
+error:
+	return rc;
+}
+
 struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
 {
 	int rc = 0;
@@ -475,6 +497,7 @@ struct dp_usbpd *dp_usbpd_get(struct device *dev, struct dp_usbpd_cb *cb)
 
 	dp_usbpd = &usbpd->dp_usbpd;
 	dp_usbpd->simulate_connect = dp_usbpd_simulate_connect;
+	dp_usbpd->simulate_attention = dp_usbpd_simulate_attention;
 
 	return dp_usbpd;
 error:
diff --git a/drivers/gpu/drm/msm/dp/dp_usbpd.h b/drivers/gpu/drm/msm/dp/dp_usbpd.h
index e70ad7d..0a7efd9 100644
--- a/drivers/gpu/drm/msm/dp/dp_usbpd.h
+++ b/drivers/gpu/drm/msm/dp/dp_usbpd.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012-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
@@ -50,6 +50,7 @@ enum dp_usbpd_port {
  * @alt_mode_cfg_done: bool to specify alt mode status
  * @debug_en: bool to specify debug mode
  * @simulate_connect: simulate disconnect or connect for debug mode
+ * @simulate_attention: simulate attention messages for debug mode
  */
 struct dp_usbpd {
 	enum dp_usbpd_port port;
@@ -65,6 +66,7 @@ struct dp_usbpd {
 	bool debug_en;
 
 	int (*simulate_connect)(struct dp_usbpd *dp_usbpd, bool hpd);
+	int (*simulate_attention)(struct dp_usbpd *dp_usbpd, int vdo);
 };
 
 /**