diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index cf1c5f20b62e..ec840c1178bb 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -25,6 +25,8 @@
 static int intel_hdcp2_init(struct intel_connector *connector);
 static int _intel_hdcp2_enable(struct intel_connector *connector);
 static int _intel_hdcp2_disable(struct intel_connector *connector);
+static void intel_hdcp2_check_work(struct work_struct *work);
+static int intel_hdcp2_check_link(struct intel_connector *connector);
 static
 int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port,
 			       const struct intel_hdcp_shim *shim, u8 *bksv);
@@ -841,6 +843,7 @@ int intel_hdcp_init(struct intel_connector *connector,
 	hdcp->hdcp_shim = hdcp_shim;
 	mutex_init(&hdcp->hdcp_mutex);
 	INIT_DELAYED_WORK(&hdcp->hdcp_check_work, intel_hdcp_check_work);
+	INIT_DELAYED_WORK(&hdcp->hdcp2_check_work, intel_hdcp2_check_work);
 	INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work);
 
 	if (hdcp2_supported)
@@ -1709,6 +1712,8 @@ static int _intel_hdcp2_enable(struct intel_connector *connector)
 	hdcp->hdcp2_in_use = true;
 	hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
 	schedule_work(&hdcp->hdcp_prop_work);
+	schedule_delayed_work(&hdcp->hdcp2_check_work,
+			      DRM_HDCP2_CHECK_PERIOD_MS);
 	return 0;
 }
 
@@ -1914,3 +1919,80 @@ static int intel_hdcp2_init(struct intel_connector *connector)
 exit:
 	return ret;
 }
+
+static int intel_hdcp2_check_link(struct intel_connector *connector)
+{
+	struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
+	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
+	struct intel_hdcp *hdcp = &connector->hdcp;
+	enum port port = connector->encoder->port;
+	int ret = 0;
+
+	if (!hdcp->hdcp_shim)
+		return -ENOENT;
+
+	mutex_lock(&hdcp->hdcp_mutex);
+
+	if (hdcp->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		goto out;
+
+	if (!(I915_READ(HDCP2_STATUS_DDI(port)) & LINK_ENCRYPTION_STATUS)) {
+		DRM_ERROR("HDCP check failed: link is not encrypted, %x\n",
+			  I915_READ(HDCP2_STATUS_DDI(port)));
+		ret = -ENXIO;
+		hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&hdcp->hdcp_prop_work);
+		goto out;
+	}
+
+	ret = hdcp->hdcp_shim->check_2_2_link(intel_dig_port);
+	if (ret == DRM_HDCP_LINK_PROTECTED) {
+		if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+			hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+			schedule_work(&hdcp->hdcp_prop_work);
+		}
+		goto out;
+	}
+
+	DRM_ERROR("[%s:%d] HDCP2.2 link failed, retrying auth\n",
+		  connector->base.name, connector->base.base.id);
+
+	ret = _intel_hdcp2_disable(connector);
+	if (ret) {
+		DRM_ERROR("[%s:%d] Failed to disable hdcp2.2 (%d)\n",
+			  connector->base.name, connector->base.base.id, ret);
+
+		hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&hdcp->hdcp_prop_work);
+		goto out;
+	}
+
+	ret = _intel_hdcp2_enable(connector);
+	if (ret) {
+		DRM_ERROR("[%s:%d] Failed to enable hdcp2.2 (%d)\n",
+			  connector->base.name, connector->base.base.id, ret);
+
+		hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+		schedule_work(&hdcp->hdcp_prop_work);
+		goto out;
+	}
+
+out:
+	mutex_unlock(&hdcp->hdcp_mutex);
+
+	return ret;
+}
+
+static void intel_hdcp2_check_work(struct work_struct *work)
+{
+	struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
+						struct intel_hdcp,
+						hdcp2_check_work);
+	struct intel_connector *connector = container_of(hdcp,
+						struct intel_connector,
+						hdcp);
+
+	if (!intel_hdcp2_check_link(connector))
+		schedule_delayed_work(&hdcp->hdcp2_check_work,
+				      DRM_HDCP2_CHECK_PERIOD_MS);
+}
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h
index 0c222b5b685c..76c84d60202f 100644
--- a/include/drm/drm_hdcp.h
+++ b/include/drm/drm_hdcp.h
@@ -11,6 +11,14 @@
 
 /* Period of hdcp checks (to ensure we're still authenticated) */
 #define DRM_HDCP_CHECK_PERIOD_MS		(128 * 16)
+#define DRM_HDCP2_CHECK_PERIOD_MS		500
+
+enum check_link_response {
+	DRM_HDCP_LINK_PROTECTED	= 0,
+	DRM_HDCP_TOPOLOGY_CHANGE,
+	DRM_HDCP_LINK_INTEGRITY_FAILURE,
+	DRM_HDCP_REAUTH_REQUEST
+};
 
 /* Shared lengths/masks between HDMI/DVI/DisplayPort */
 #define DRM_HDCP_AN_LEN				8
