[PATCH 35/43] drm/i915: Enable HDCP version that is best capable

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



hdcp_enable_work is extended to choose the better hdcp version based
on the system and panel capability.

And intel_hdcp_disable will find the version that is inforce, if any.
And corresponding version specific disable function alone called.

Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx>
---
 drivers/gpu/drm/i915/intel_hdcp.c | 112 ++++++++++++++++++++++++++++++++++----
 1 file changed, 100 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c
index 69ae47eaff49..2fe73f7eb6dd 100644
--- a/drivers/gpu/drm/i915/intel_hdcp.c
+++ b/drivers/gpu/drm/i915/intel_hdcp.c
@@ -27,6 +27,43 @@ static int _intel_hdcp2_disable(struct intel_hdcp *hdcp);
 static void intel_hdcp2_check_work(struct work_struct *work);
 static int intel_hdcp2_check_link(struct intel_hdcp *hdcp);
 
+static inline bool intel_hdcp1_supported(struct intel_hdcp *hdcp)
+{
+	return (hdcp->plat_cap & HDCP_CAPABILITY &&
+		hdcp->panel_cap & HDCP_CAPABILITY);
+}
+
+static inline bool intel_hdcp2_supported(struct intel_hdcp *hdcp)
+{
+	return (hdcp->plat_cap & HDCP2_CAPABILITY &&
+		hdcp->panel_cap & HDCP2_CAPABILITY);
+}
+
+static inline bool intel_hdcp_in_force(struct intel_hdcp *hdcp)
+{
+	struct drm_i915_private *dev_priv = to_i915(hdcp->connector->base.dev);
+	enum port port = hdcp->connector->encoder->port;
+	u32 reg;
+
+	reg = I915_READ(PORT_HDCP_STATUS(port));
+	if (reg & HDCP_STATUS_AUTH || reg & HDCP_STATUS_ENC)
+		return true;
+	return false;
+
+}
+
+static inline bool intel_hdcp2_in_force(struct intel_hdcp *hdcp)
+{
+	struct drm_i915_private *dev_priv = to_i915(hdcp->connector->base.dev);
+	enum port port = hdcp->connector->encoder->port;
+	u32 reg;
+
+	reg = I915_READ(HDCP2_STATUS_DDI(port));
+	if (reg & LINK_ENCRYPTION_STATUS || reg & LINK_AUTH_STATUS)
+		return true;
+	return false;
+}
+
 static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port,
 				    const struct intel_hdcp_shim *shim)
 {
@@ -650,7 +687,11 @@ static void intel_hdcp_enable_work(struct work_struct *work)
 					       hdcp_enable_work);
 
 	mutex_lock(&hdcp->hdcp_mutex);
-	_intel_hdcp_enable(hdcp);
+	if (intel_hdcp2_supported(hdcp))
+		_intel_hdcp2_enable(hdcp);
+	else if (intel_hdcp1_supported(hdcp))
+		_intel_hdcp_enable(hdcp);
+
 	mutex_unlock(&hdcp->hdcp_mutex);
 }
 
@@ -727,13 +768,48 @@ int intel_hdcp_init(struct intel_connector *connector,
 	return ret;
 }
 
+static void intel_hdcp_probe_panel_cap(struct intel_hdcp *hdcp)
+{
+	struct intel_digital_port *intel_dig_port =
+					conn_to_dig_port(hdcp->connector);
+	bool capable = false;
+	u8 bksv[5];
+
+	hdcp->panel_cap = 0;
+
+	if (hdcp->plat_cap & HDCP_CAPABILITY) {
+		if (hdcp->hdcp_shim->hdcp_capable) {
+			hdcp->hdcp_shim->hdcp_capable(intel_dig_port, &capable);
+		} else {
+			if (!intel_hdcp_read_valid_bksv(intel_dig_port,
+							hdcp->hdcp_shim, bksv))
+				capable = true;
+		}
+		if (capable)
+			hdcp->panel_cap |= HDCP_CAPABILITY;
+	}
+
+	if (hdcp->plat_cap & HDCP2_CAPABILITY) {
+		hdcp->hdcp2_shim->hdcp_capable(intel_dig_port, &capable);
+		if (capable)
+			hdcp->panel_cap |= HDCP2_CAPABILITY;
+	}
+	DRM_DEBUG_KMS("plat_cap: 0x%X, panel_cap: 0x%X\n",
+		      hdcp->plat_cap, hdcp->panel_cap);
+}
+
 int intel_hdcp_enable(struct intel_connector *connector)
 {
 	struct intel_hdcp *hdcp = connector->hdcp;
 
-	if (!hdcp || !hdcp->hdcp_shim)
+	if (!hdcp)
 		return -ENOENT;
 
+	intel_hdcp_probe_panel_cap(hdcp);
+
+	if (!intel_hdcp1_supported(hdcp) && !intel_hdcp2_supported(hdcp))
+		return -EINVAL;
+
 	mutex_lock(&hdcp->hdcp_mutex);
 	schedule_work(&hdcp->hdcp_enable_work);
 	mutex_unlock(&hdcp->hdcp_mutex);
@@ -744,21 +820,33 @@ int intel_hdcp_enable(struct intel_connector *connector)
 int intel_hdcp_disable(struct intel_connector *connector)
 {
 	struct intel_hdcp *hdcp = connector->hdcp;
-	int ret = 0;
 
-	if (!hdcp || !hdcp->hdcp_shim)
+	if (!hdcp)
 		return -ENOENT;
 
-	mutex_lock(&hdcp->hdcp_mutex);
+	if (hdcp->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+		return 0;
 
-	if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-		hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
-		ret = _intel_hdcp_disable(hdcp);
-	}
+	/*
+	 * Setting it out of mutex, so that other on going process like check
+	 * link and auth can check for this state change and terminate themself.
+	 */
+	hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
+	cancel_work_sync(&hdcp->hdcp_enable_work);
 
-	mutex_unlock(&hdcp->hdcp_mutex);
 	cancel_delayed_work_sync(&hdcp->hdcp_check_work);
-	return ret;
+	cancel_delayed_work_sync(&hdcp->hdcp2_check_work);
+
+	mutex_lock(&hdcp->hdcp_mutex);
+	if (hdcp->plat_cap & HDCP_CAPABILITY)
+		if (intel_hdcp_in_force(hdcp))
+			_intel_hdcp_disable(hdcp);
+	if (hdcp->plat_cap & HDCP2_CAPABILITY)
+		if (intel_hdcp2_in_force(hdcp))
+			_intel_hdcp2_disable(hdcp);
+	mutex_unlock(&hdcp->hdcp_mutex);
+
+	return 0;
 }
 
 void intel_hdcp_atomic_check(struct drm_connector *connector,
@@ -1437,7 +1525,7 @@ static int _intel_hdcp2_disable(struct intel_hdcp *hdcp)
 {
 	int ret;
 
-	DRM_ERROR("[%s:%d] HDCP2.2 is being Disabled\n",
+	DRM_INFO("[%s:%d] HDCP2.2 is being Disabled\n",
 		  hdcp->connector->base.name, hdcp->connector->base.base.id);
 
 	ret = hdcp2_disable_encryption(hdcp);
-- 
2.7.4

_______________________________________________
Intel-gfx mailing list
Intel-gfx@xxxxxxxxxxxxxxxxxxxxx
https://lists.freedesktop.org/mailman/listinfo/intel-gfx




[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux