diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index da4036d..2dada18 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -33,6 +33,7 @@
 #include <linux/slab.h>
 #include <linux/export.h>
 #include <linux/list_sort.h>
+#include <linux/string.h>
 #include <asm/msr-index.h>
 #include <drm/drmP.h>
 #include "intel_drv.h"
@@ -51,6 +52,46 @@ static const char *yesno(int v)
 	return v ? "yes" : "no";
 }
 
+#define DP_PARAMETER_COUNT		8
+#define MAX_DP_CONFIG_LINE_COUNT	64
+
+enum dp_config_param {
+	DP_CONFIG_PARAM_INVALID = -1,
+	DP_CONFIG_PARAM_CONNECTOR = 0,
+	DP_CONFIG_PARAM_LINK_RATE,
+	DP_CONFIG_PARAM_LANE_COUNT,
+	DP_CONFIG_PARAM_VOLTAGE_SWING,
+	DP_CONFIG_PARAM_PREEMPHASIS,
+	DP_CONFIG_PARAM_HRES,
+	DP_CONFIG_PARAM_VRES,
+	DP_CONFIG_PARAM_BPP
+};
+
+struct dp_config {
+	enum dp_config_param type;
+	unsigned long value;
+};
+
+const char *dp_conf_tokens[DP_PARAMETER_COUNT] = {
+		 "Connector",
+		 "Link Rate",
+		 "Lane Count",
+		 "Voltage Swing Level",
+		 "Preemphasis Level",
+		 "Horizontal Resolution",
+		 "Vertical Resolution",
+		 "Bits Per Pixel"
+};
+/* Strings for writing out dp_configs */
+#define DP_CONF_STR_CONNECTOR	"Connector:             %s\n"
+#define DP_CONF_STR_LINKRATE	"Link Rate:             %02x\n"
+#define DP_CONF_STR_LANES	"Lane Count:            %u\n"
+#define DP_CONF_STR_VSWING	"Voltage Swing Level:   %u\n"
+#define DP_CONF_STR_PREEMP	"Preemphasis Level:     %u\n"
+#define DP_CONF_STR_HRES	"Horizontal Resolution: %d\n"
+#define DP_CONF_STR_VRES	"Vertical Resolution:   %d\n"
+#define DP_CONF_STR_BPP		"Bits Per Pixel:        %u\n"
+
 /* As the drm_debugfs_init() routines are called before dev->dev_private is
  * allocated we need to hook into the minor for release. */
 static int
@@ -3505,6 +3546,353 @@ static const struct file_operations i915_display_crc_ctl_fops = {
 	.write = display_crc_ctl_write
 };
 
+static void displayport_show_config_info(struct seq_file *m,
+			  struct intel_connector *intel_connector)
+{
+	struct intel_encoder *intel_encoder = intel_connector->encoder;
+	struct intel_dp *intel_dp;
+	struct intel_crtc *icrtc;
+	int pipe_bpp, hres, vres;
+	uint8_t vs[4], pe[4];
+	struct drm_display_mode *mode;
+	int i = 0;
+
+	if (intel_encoder) {
+		intel_dp = enc_to_intel_dp(&intel_encoder->base);
+		for (i = 0; i < intel_dp->lane_count; i++) {
+			vs[i] = intel_dp->train_set[i]
+				& DP_TRAIN_VOLTAGE_SWING_MASK;
+			pe[i] = (intel_dp->train_set[i]
+			      & DP_TRAIN_PRE_EMPHASIS_MASK) >> 3;
+		}
+		if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT) {
+			if (intel_encoder->new_crtc) {
+				pipe_bpp = intel_encoder->new_crtc->config.pipe_bpp;
+				mode = &intel_encoder->new_crtc->config.adjusted_mode;
+				hres = mode->hdisplay;
+				vres = mode->vdisplay;
+			} else if (intel_encoder->base.crtc) {
+				icrtc = to_intel_crtc(intel_encoder->base.crtc);
+				pipe_bpp = icrtc->config.pipe_bpp;
+				mode = &icrtc->config.adjusted_mode;
+				hres = mode->hdisplay;
+				vres = mode->vdisplay;
+			} else {
+				pipe_bpp = 0;
+				hres = vres = 0;
+			}
+			seq_printf(m, DP_CONF_STR_CONNECTOR,
+				   intel_connector->base.name);
+			seq_printf(m, DP_CONF_STR_LINKRATE, intel_dp->link_bw);
+			seq_printf(m, DP_CONF_STR_LANES, intel_dp->lane_count);
+			seq_printf(m, DP_CONF_STR_VSWING, vs[0]);
+			seq_printf(m, DP_CONF_STR_PREEMP, pe[0]);
+			seq_printf(m, DP_CONF_STR_HRES, hres);
+			seq_printf(m, DP_CONF_STR_VRES, vres);
+			seq_printf(m, DP_CONF_STR_BPP, pipe_bpp);
+		}
+	}
+}
+
+enum dp_config_param displayport_get_config_param_type(char *input_string)
+{
+	enum dp_config_param param_type = DP_CONFIG_PARAM_INVALID;
+	int i = 0;
+
+	for (i = 0; i < DP_PARAMETER_COUNT; i++) {
+		if (strncmp(input_string, dp_conf_tokens[i],
+			    strlen(dp_conf_tokens[i])) == 0) {
+			param_type = (enum dp_config_param) i;
+			break;
+		}
+	}
+	return param_type;
+}
+
+int value_for_config_param(enum dp_config_param param,
+			   char *input_string,
+			   void *output_value)
+{
+	int status = 0;
+	unsigned int *out_ptr = (unsigned int *)output_value;
+	char *index = input_string;
+
+	switch (param) {
+	case DP_CONFIG_PARAM_CONNECTOR:
+		output_value = (char *)index;
+		break;
+	case DP_CONFIG_PARAM_LINK_RATE:
+	case DP_CONFIG_PARAM_LANE_COUNT:
+	case DP_CONFIG_PARAM_VOLTAGE_SWING:
+	case DP_CONFIG_PARAM_PREEMPHASIS:
+		status = kstrtol(index, 16, (long *)out_ptr);
+		break;
+	case DP_CONFIG_PARAM_HRES:
+	case DP_CONFIG_PARAM_VRES:
+	case DP_CONFIG_PARAM_BPP:
+		status = kstrtol(index, 10, (long *)out_ptr);
+		break;
+	default:
+		/* Unhandled case */
+		status = -EINVAL;
+		*out_ptr = 0;
+		break;
+	}
+
+	return status;
+}
+
+int tokenize_dp_config(char *input_buffer, char *output[])
+{
+	char *base = input_buffer, *index, *end;
+	int line_count = 0;
+	int i = 0, len = 0;
+	int done = 0;
+
+	if (!input_buffer)
+		return 0;
+
+	while (!done) {
+		index = strpbrk(base, ":");
+		if (index) {
+			len = index - base;
+			*index = '\0';
+			index++;
+			/* Save the type string */
+			output[i] = base;
+			i++;
+			line_count++;
+			end = strpbrk(index, "\n\0");
+			if (end) {
+				*end = '\0';
+				/* Eat up whitespace */
+				while (*index <= 0x20)
+					index++;
+				output[i] = index;
+				i++;
+				line_count++;
+			} else
+				done = 1;
+			/* Move to the next section of the string */
+			base = end + 1;
+		} else
+			done = 1;
+	}
+	return line_count;
+}
+
+static int displayport_parse_config(char *input_buffer,
+				    ssize_t buffer_size,
+				    struct intel_dp_link_config *dp_conf)
+{
+	int status = 0;
+	char *lines[MAX_DP_CONFIG_LINE_COUNT];
+	int i = 0;
+	struct dp_config parms[DP_PARAMETER_COUNT];
+	int line_count = 0;
+	char *buffer = input_buffer;
+	enum dp_config_param parm_type;
+	unsigned long parm_value;
+
+	line_count = tokenize_dp_config(buffer, lines);
+
+	if (line_count == 0) {
+		DRM_DEBUG_DRIVER("No lines to process\n");
+		return 0;
+	}
+
+	for (i = 0; i < line_count; i += 2) {
+		parm_type = displayport_get_config_param_type(lines[i]);
+		if (parm_type != DP_CONFIG_PARAM_INVALID) {
+			status = value_for_config_param(parm_type,
+							lines[i+1],
+							&parm_value);
+			if (status == 0) {
+				parms[parm_type].type = parm_type;
+				parms[parm_type].value = parm_value;
+			}
+		}
+	}
+
+	for (i = 1; i < DP_PARAMETER_COUNT; i++)
+		DRM_DEBUG_DRIVER("%s = %lu\n",
+					dp_conf_tokens[parms[i].type],
+					parms[i].value);
+
+	/* Validate any/all incoming parameters */
+	strcpy(dp_conf->connector_name,
+	       (char *)parms[DP_CONFIG_PARAM_CONNECTOR].value);
+
+	if (parms[DP_CONFIG_PARAM_LINK_RATE].value == 0x06 ||
+	    parms[DP_CONFIG_PARAM_LINK_RATE].value == 0x0a ||
+	    parms[DP_CONFIG_PARAM_LINK_RATE].value == 0x14) {
+		dp_conf->link_rate =
+			parms[DP_CONFIG_PARAM_LINK_RATE].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_LANE_COUNT].value == 0x01 ||
+	    parms[DP_CONFIG_PARAM_LANE_COUNT].value == 0x02 ||
+	    parms[DP_CONFIG_PARAM_LANE_COUNT].value == 0x04) {
+		dp_conf->lane_count =
+			parms[DP_CONFIG_PARAM_LANE_COUNT].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_VOLTAGE_SWING].value <= 0x03 &&
+	    parms[DP_CONFIG_PARAM_VOLTAGE_SWING].value >= 0x00) {
+		dp_conf->vswing_level =
+			parms[DP_CONFIG_PARAM_VOLTAGE_SWING].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_PREEMPHASIS].value <= 0x03 &&
+	    parms[DP_CONFIG_PARAM_PREEMPHASIS].value >= 0x00) {
+		dp_conf->preemp_level =
+			parms[DP_CONFIG_PARAM_PREEMPHASIS].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_BPP].value == 18 ||
+	    parms[DP_CONFIG_PARAM_BPP].value == 24 ||
+	    parms[DP_CONFIG_PARAM_BPP].value == 30 ||
+	    parms[DP_CONFIG_PARAM_BPP].value == 36) {
+		dp_conf->bits_per_pixel =
+			parms[DP_CONFIG_PARAM_PREEMPHASIS].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_HRES].value > 0 &&
+	    parms[DP_CONFIG_PARAM_HRES].value <= 8192) {
+		dp_conf->hres =
+			parms[DP_CONFIG_PARAM_HRES].value;
+	} else
+		return -EINVAL;
+
+	if (parms[DP_CONFIG_PARAM_VRES].value > 0 &&
+	    parms[DP_CONFIG_PARAM_VRES].value <= 8192) {
+		dp_conf->vres =
+			parms[DP_CONFIG_PARAM_VRES].value;
+	} else
+		return -EINVAL;
+
+	return status;
+}
+
+static int displayport_config_ctl_show(struct seq_file *m, void *data)
+{
+	struct drm_device *dev = m->private;
+	struct drm_connector *connector;
+	struct intel_encoder *intel_encoder;
+	struct intel_connector *intel_connector;
+
+	if (!dev)
+		return -ENODEV;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		intel_connector = to_intel_connector(connector);
+		intel_encoder = intel_connector->encoder;
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+			if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+			    intel_encoder->type == INTEL_OUTPUT_UNKNOWN) {
+				if (connector->status == connector_status_connected) {
+					displayport_show_config_info(m, intel_connector);
+				} else {
+					seq_printf(m, DP_CONF_STR_CONNECTOR,
+						   intel_connector->base.name);
+					seq_printf(m, "disconnected\n");
+				}
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int displayport_config_ctl_open(struct inode *inode,
+				       struct file *file)
+{
+	struct drm_device *dev = inode->i_private;
+
+	return single_open(file, displayport_config_ctl_show, dev);
+}
+
+static ssize_t displayport_config_ctl_write(struct file *file,
+					    const char __user *ubuf,
+					    size_t len, loff_t *offp)
+{
+	char *input_buffer;
+	int status = 0;
+	struct seq_file *m;
+	struct drm_device *dev;
+	struct drm_connector *connector;
+	struct intel_encoder *intel_encoder;
+	struct intel_connector *intel_connector;
+	struct intel_dp *intel_dp;
+	struct intel_dp_link_config dp_conf;
+
+	m = file->private_data;
+	if (!m) {
+		status = -ENODEV;
+		return status;
+	}
+	dev = m->private;
+
+	if (!dev) {
+		status = -ENODEV;
+		return status;
+	}
+
+	if (len == 0)
+		return 0;
+
+	input_buffer = kmalloc(len + 1, GFP_KERNEL);
+	if (!input_buffer)
+		return -ENOMEM;
+
+	if (copy_from_user(input_buffer, ubuf, len)) {
+		status = -EFAULT;
+		goto out;
+	}
+
+	input_buffer[len] = '\0';
+	memset(&dp_conf, 0, sizeof(struct intel_dp_link_config));
+	DRM_DEBUG_DRIVER("Copied %d bytes from user\n", (unsigned int)len);
+	status = displayport_parse_config(input_buffer, len, &dp_conf);
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		intel_connector = to_intel_connector(connector);
+		intel_encoder = intel_connector->encoder;
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+			if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+			    intel_encoder->type == INTEL_OUTPUT_UNKNOWN) {
+				intel_dp = enc_to_intel_dp(&intel_encoder->base);
+				memcpy(&intel_dp->compliance_config,
+				       &dp_conf,
+				       sizeof(struct intel_dp_link_config));
+			}
+		}
+	}
+
+
+out:
+	kfree(input_buffer);
+	if (status < 0)
+		return status;
+
+	*offp += len;
+	return len;
+}
+
+static const struct file_operations i915_displayport_config_ctl_fops = {
+	.owner = THIS_MODULE,
+	.open = displayport_config_ctl_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+	.write = displayport_config_ctl_write
+};
+
 static void wm_latency_show(struct seq_file *m, const uint16_t wm[5])
 {
 	struct drm_device *dev = m->private;
@@ -4208,6 +4596,7 @@ static const struct i915_debugfs_files {
 	{"i915_spr_wm_latency", &i915_spr_wm_latency_fops},
 	{"i915_cur_wm_latency", &i915_cur_wm_latency_fops},
 	{"i915_fbc_false_color", &i915_fbc_fc_fops},
+	{"i915_displayport_config_ctl", &i915_displayport_config_ctl_fops}
 };
 
 void intel_display_crc_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index a7acc61..b3ddd15 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -3968,7 +3968,7 @@ intel_dp_get_sink_irq_esi(struct intel_dp *intel_dp, u8 *sink_irq_vector)
 static uint8_t
 intel_dp_autotest_link_training(struct intel_dp *intel_dp)
 {
-	uint8_t test_result = DP_TEST_NAK;
+	uint8_t test_result = DP_TEST_ACK;
 	return test_result;
 }
 
@@ -4013,21 +4013,25 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
 		DRM_DEBUG_KMS("Executing LINK_TRAINING request\n");
 		intel_dp->compliance_test_data = DP_TEST_LINK_TRAINING;
 		response = intel_dp_autotest_link_training(intel_dp);
+		status = intel_dp_signal_userspace(intel_dp);
 		break;
 	case DP_TEST_LINK_VIDEO_PATTERN:
 		DRM_DEBUG_KMS("Executing TEST_PATTERN request\n");
 		intel_dp->compliance_test_data = DP_TEST_LINK_VIDEO_PATTERN;
 		response = intel_dp_autotest_video_pattern(intel_dp);
+		status = intel_dp_signal_userspace(intel_dp);
 		break;
 	case DP_TEST_LINK_EDID_READ:
 		DRM_DEBUG_KMS("Executing EDID request\n");
 		intel_dp->compliance_test_data = DP_TEST_LINK_EDID_READ;
 		response = intel_dp_autotest_edid(intel_dp);
+		status = intel_dp_signal_userspace(intel_dp);
 		break;
 	case DP_TEST_LINK_PHY_TEST_PATTERN:
 		DRM_DEBUG_KMS("Executing PHY_PATTERN request\n");
 		intel_dp->compliance_test_data = DP_TEST_LINK_PHY_TEST_PATTERN;
 		response = intel_dp_autotest_phy_pattern(intel_dp);
+		status = intel_dp_signal_userspace(intel_dp);
 		break;
 		/* FAUX is optional in DP 1.2*/
 	case DP_TEST_LINK_FAUX_PATTERN:
@@ -4038,10 +4042,9 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
 		DRM_DEBUG_KMS("Unhandled test request\n");
 		break;
 	}
-	if (status != 0) {
-		response = DP_TEST_NAK;
-		DRM_DEBUG_KMS("Error %d processing test request\n", status);
-	}
+	if (status != 0)
+		DRM_DEBUG_KMS("Status code %d processing test request\n",
+			      status);
 	status = drm_dp_dpcd_write(&intel_dp->aux,
 				   DP_TEST_RESPONSE,
 				   &response, 1);
