diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 2dada18..d16612c 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -54,6 +54,7 @@ static const char *yesno(int v)
 
 #define DP_PARAMETER_COUNT		8
 #define MAX_DP_CONFIG_LINE_COUNT	64
+#define PID_BUFFER_SIZE			16
 
 enum dp_config_param {
 	DP_CONFIG_PARAM_INVALID = -1,
@@ -3884,6 +3885,126 @@ out:
 	return len;
 }
 
+static int displayport_user_pid_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;
+	struct intel_dp *intel_dp;
+
+	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;
+		DRM_DEBUG_DRIVER("Got connector %s with type %08x\n",
+				 connector->name, connector->connector_type);
+		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);
+				seq_printf(m, "%s: %lu\n",
+					   connector->name,
+					   intel_dp->compliance_app_pid);
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int i915_displayport_user_pid_open(struct inode *inode,
+					  struct file *file)
+{
+	struct drm_device *dev = inode->i_private;
+
+	return single_open(file, displayport_user_pid_show, dev);
+}
+
+static ssize_t displayport_user_pid_write(struct file *file,
+					    const char __user *ubuf,
+					    size_t len, loff_t *offp)
+{
+	/* Userspace app writes its PID in here and is stored in the intel_dp
+	   struct for the connector. The PID is used when the driver receives
+	   an intrrupt for a compliance request to notify userspace of the
+	   event. */
+	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;
+	int status = 0;
+	long user_pid = 0;
+	char pidbuf[PID_BUFFER_SIZE+1];
+	char *start = pidbuf;
+
+	m = file->private_data;
+	if (!m) {
+		status = -ENODEV;
+		goto out;
+	}
+
+	dev = m->private;
+	if (!dev) {
+		status = -ENODEV;
+		goto out;
+	}
+
+	if (len > PID_BUFFER_SIZE) {
+		status = -EINVAL;
+		goto out;
+	}
+
+	if (copy_from_user(pidbuf, ubuf, len)) {
+		status = -EFAULT;
+		goto out;
+	}
+
+	pidbuf[len] = '\0';
+	/* Skip to separator */
+	while (*start != ':')
+		start++;
+	start++;
+	/* skip whitespace */
+	while (*start <= 0x20)
+		start++;
+	/* Get the PID now */
+	status = kstrtol(start, 10, &user_pid);
+	if (status < 0)
+		goto out;
+
+	list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+		intel_connector = to_intel_connector(connector);
+		intel_encoder = intel_connector->encoder;
+		DRM_DEBUG_DRIVER("Got connector %s with type %08x\n",
+				 connector->name, connector->connector_type);
+		if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort) {
+			if (intel_encoder->type == INTEL_OUTPUT_DISPLAYPORT ||
+			    intel_encoder->type == INTEL_OUTPUT_UNKNOWN) {
+				DRM_DEBUG_DRIVER("Pid %ld added to Connector %s\n",
+						 user_pid, connector->name);
+				intel_dp = enc_to_intel_dp(&intel_encoder->base);
+				intel_dp->compliance_app_pid = user_pid;
+			}
+		}
+	}
+out:
+	return status;
+}
+
+static const struct file_operations displayport_user_pid_fops = {
+	.owner = THIS_MODULE,
+	.write = displayport_user_pid_write,
+	.open = i915_displayport_user_pid_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release
+};
+
 static const struct file_operations i915_displayport_config_ctl_fops = {
 	.owner = THIS_MODULE,
 	.open = displayport_config_ctl_open,
@@ -4596,7 +4717,8 @@ 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}
+	{"i915_displayport_config_ctl", &i915_displayport_config_ctl_fops},
+	{"i915_displayport_user_pid", &displayport_user_pid_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 b3ddd15..717cb5d 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -39,6 +39,7 @@
 #include "i915_drv.h"
 
 #define DP_LINK_CHECK_TIMEOUT	(10 * 1000)
+#define SIG_DP_COMPLIANCE	47
 
 struct dp_link_dpll {
 	int link_bw;
@@ -157,6 +158,37 @@ static u8 intel_dp_max_lane_count(struct intel_dp *intel_dp)
 	return min(source_max, sink_max);
 }
 
+int intel_dp_signal_userspace(struct intel_dp *intel_dp)
+{
+	int status = 0;
+	struct siginfo s_info;
+	struct task_struct *compliance_app;
+
+	/* Setup signal structure */
+	memset(&s_info, 0, sizeof(struct siginfo));
+	s_info.si_signo = SIG_DP_COMPLIANCE;
+	s_info.si_code = SI_QUEUE;
+	s_info.si_int = intel_dp->compliance_test_data;
+
+	rcu_read_lock();
+	compliance_app = pid_task(find_pid_ns(intel_dp->compliance_app_pid,
+					      &init_pid_ns), PIDTYPE_PID);
+	if (compliance_app == NULL) {
+		rcu_read_unlock();
+		DRM_DEBUG_DRIVER("Compliance test requested with no available userspace handler. Testing aborted\n");
+		status = -ENODEV;
+		goto out;
+	}
+	rcu_read_unlock();
+
+	/* Send signal */
+	status = send_sig_info(SIG_DP_COMPLIANCE, &s_info, compliance_app);
+	if (status < 0)
+		DRM_DEBUG_DRIVER("Error: Could not send signal\n");
+out:
+	return status;
+}
+
 /*
  * The units on the numbers in the next two are... bizarre.  Examples will
  * make it clearer; this one parallels an example in the eDP spec.
@@ -4006,6 +4038,8 @@ intel_dp_handle_test_request(struct intel_dp *intel_dp)
 	DRM_DEBUG_KMS("Received automated test request\n");
 	status = drm_dp_dpcd_read(&intel_dp->aux, DP_TEST_REQUEST, &rxdata, 1);
 
+	intel_dp->compliance_test_data = rxdata;
+
 	/* ACK/NAK response based on test function response
 	   Unimplemented/unsupported tests will NAK by default */
 	switch (rxdata) {
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index e8f4839..29d51f9 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -613,6 +613,10 @@ struct intel_dp {
 		enum edp_drrs_refresh_rate_type refresh_rate_type;
 		struct mutex mutex;
 	} drrs_state;
+	/* Displayport compliance testing */
+	unsigned long compliance_app_pid;
+	unsigned long compliance_test_data;
+	bool compliance_testing_active;
 
 };
 
