From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: "Romli, Khairul Anuar" Date: Tue, 16 Oct 2018 11:38:41 +0800 Subject: [PATCH] i915: Add cp_downstream property Implements drm blob property cp_downstream_info property on HDCP capable connectors. Downstream topology info is gathered across authentication stages and stored in intel_conenctor. When HDCP authentication is successful, new blob with latest downstream topology information is updated to cp_downstream_info property. Change-Id: I4646ce3c1e971573bab815e655c2bb66da170a40 Signed-off-by: Ramalingam C Signed-off-by: Romli, Khairul Anuar --- drivers/gpu/drm/i915/intel_drv.h | 3 + drivers/gpu/drm/i915/intel_hdcp.c | 119 +++++++++++++++++++++--------- include/drm/drm_hdcp.h | 1 + 3 files changed, 88 insertions(+), 35 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 8bc603ec9b66..98a147235a9c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -434,6 +434,9 @@ struct intel_connector { unsigned int revocated_ksv_cnt; u8 *revocated_ksv_list; u32 srm_blob_id; + + /* Downstream info like, depth, device_count, bksv and ksv_list etc */ + struct cp_downstream_info *downstream_info; }; struct intel_digital_connector_state { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 20f78b572d1b..d9869b64a3f1 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -234,25 +234,28 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) struct drm_i915_private *dev_priv = to_i915(connector->base.dev); u32 vprime, sha_text, sha_leftovers, rep_ctl; u8 bstatus[2], num_downstream, *ksv_fifo; - int ret, i, j, sha_idx; + int ret = 0, i, j, sha_idx; - if(intel_dig_port == NULL) - return EINVAL; + if(intel_dig_port == NULL) { + ret = -EINVAL; + goto out; + } ret = intel_hdcp_poll_ksv_fifo(intel_dig_port, shim); if (ret) { DRM_ERROR("KSV list failed to become ready (%d)\n", ret); - return ret; + goto out; } ret = shim->read_bstatus(intel_dig_port, bstatus); if (ret) - return ret; + goto out; if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) || DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) { DRM_ERROR("Max Topology Limit Exceeded\n"); - return -EPERM; + ret = -EPERM; + goto out; } /* @@ -263,27 +266,38 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) * authentication. */ num_downstream = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]); - if (num_downstream == 0) - return -EINVAL; + if (num_downstream == 0) { + ret = -EINVAL; + goto out; + } + + connector->downstream_info->device_count = num_downstream; + connector->downstream_info->depth = DRM_HDCP_DEPTH(bstatus[1]); ksv_fifo = kzalloc(num_downstream * DRM_HDCP_KSV_LEN, GFP_KERNEL); - if (!ksv_fifo) - return -ENOMEM; + if (!ksv_fifo) { + ret = -ENOMEM; + goto out; + } ret = shim->read_ksv_fifo(intel_dig_port, num_downstream, ksv_fifo); if (ret) - return ret; + goto kfree_out; if (intel_hdcp_ksvs_revocated(connector, ksv_fifo, num_downstream)) { DRM_ERROR("Revocated Ksv(s) in ksv_fifo\n"); - return -EPERM; + ret = -EPERM; + goto kfree_out; } + memcpy(connector->downstream_info->ksv_list, ksv_fifo, + num_downstream * DRM_HDCP_KSV_LEN); + /* Process V' values from the receiver */ for (i = 0; i < DRM_HDCP_V_PRIME_NUM_PARTS; i++) { ret = shim->read_v_prime_part(intel_dig_port, i, &vprime); if (ret) - return ret; + goto kfree_out; I915_WRITE(HDCP_SHA_V_PRIME(i), vprime); } @@ -313,7 +327,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; /* Programming guide writes this every 64 bytes */ sha_idx += sizeof(sha_text); @@ -336,7 +350,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; sha_leftovers = 0; sha_text = 0; sha_idx += sizeof(sha_text); @@ -354,21 +368,21 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) ret = intel_write_sha_text(dev_priv, bstatus[0] << 8 | bstatus[1]); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 32 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 16 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_16); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); } else if (sha_leftovers == 1) { @@ -379,21 +393,21 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) sha_text = (sha_text & 0xffffff00) >> 8; ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 32 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 24 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_8); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); } else if (sha_leftovers == 2) { @@ -402,7 +416,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) sha_text |= bstatus[0] << 24 | bstatus[1] << 16; ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 64 bits of M0 */ @@ -410,7 +424,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) for (i = 0; i < 2; i++) { ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); } } else if (sha_leftovers == 3) { @@ -419,33 +433,34 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) sha_text |= bstatus[0] << 24; ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 8 bits of text, 24 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_8); ret = intel_write_sha_text(dev_priv, bstatus[1]); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 32 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_0); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); /* Write 8 bits of M0 */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_24); ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); } else { DRM_DEBUG_KMS("Invalid number of leftovers %d\n", sha_leftovers); - return -EINVAL; + ret = -EINVAL; + goto kfree_out; } I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_TEXT_32); @@ -453,7 +468,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) while ((sha_idx % 64) < (64 - sizeof(sha_text))) { ret = intel_write_sha_text(dev_priv, 0); if (ret < 0) - return ret; + goto kfree_out; sha_idx += sizeof(sha_text); } @@ -465,7 +480,7 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) sha_text = (num_downstream * 5 + 10) * 8; ret = intel_write_sha_text(dev_priv, sha_text); if (ret < 0) - return ret; + goto kfree_out; /* Tell the HW we're done with the hash and wait for it to ACK */ I915_WRITE(HDCP_REP_CTL, rep_ctl | HDCP_SHA1_COMPLETE_HASH); @@ -473,14 +488,19 @@ int intel_hdcp_auth_downstream(struct intel_connector *connector) HDCP_SHA1_COMPLETE, HDCP_SHA1_COMPLETE, 1)) { DRM_DEBUG_KMS("Timed out waiting for SHA1 complete\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto kfree_out; } if (!(I915_READ(HDCP_REP_CTL) & HDCP_SHA1_V_MATCH)) { DRM_DEBUG_KMS("SHA-1 mismatch, HDCP failed\n"); - return -ENXIO; + ret = -ENXIO; + goto kfree_out; } - return 0; +kfree_out: + kfree(ksv_fifo); +out: + return ret; } /* Implements Part 1 of the HDCP authorization procedure */ @@ -568,15 +588,20 @@ static int intel_hdcp_auth(struct intel_connector *connector) return -EPERM; } + memcpy(connector->downstream_info->bksv, bksv.shim, + DRM_MODE_HDCP_KSV_LEN); + I915_WRITE(PORT_HDCP_BKSVLO(port), bksv.reg[0]); I915_WRITE(PORT_HDCP_BKSVHI(port), bksv.reg[1]); ret = shim->repeater_present(intel_dig_port, &repeater_present); if (ret) return ret; - if (repeater_present) + if (repeater_present) { I915_WRITE(HDCP_REP_CTL, intel_hdcp_get_repeater_ctl(intel_dig_port)); + connector->downstream_info->is_repeater = true; + } ret = shim->toggle_signalling(intel_dig_port, true); if (ret) @@ -669,6 +694,9 @@ static int _intel_hdcp_disable(struct intel_connector *connector) return ret; } + memset(connector->downstream_info, 0, + sizeof(struct cp_downstream_info)); + DRM_DEBUG_KMS("HDCP is disabled\n"); return 0; } @@ -715,6 +743,9 @@ static int _intel_hdcp_enable(struct intel_connector *connector) _intel_hdcp_disable(connector); } + memset(connector->downstream_info, 0, + sizeof(struct cp_downstream_info)); + DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret); return ret; } @@ -724,9 +755,18 @@ static void intel_hdcp_enable_work(struct work_struct *work) struct intel_connector *connector = container_of(work, struct intel_connector, hdcp_enable_work); + int ret; mutex_lock(&connector->hdcp_mutex); - _intel_hdcp_enable(connector); + ret = _intel_hdcp_enable(connector); + if (!ret) { + ret = drm_mode_connector_update_cp_downstream_property( + &connector->base, + connector->downstream_info); + if (ret) + DRM_ERROR("Downstream_property update failed.%d\n", + ret); + } mutex_unlock(&connector->hdcp_mutex); } @@ -786,6 +826,15 @@ int intel_hdcp_init(struct intel_connector *connector, if (ret) return ret; + ret = drm_connector_attach_cp_downstream_property(&connector->base); + if (ret) + return ret; + + connector->downstream_info = kzalloc(sizeof(struct cp_downstream_info), + GFP_KERNEL); + if (!connector->downstream_info) + return -ENOMEM; + connector->hdcp_shim = hdcp_shim; mutex_init(&connector->hdcp_mutex); INIT_DELAYED_WORK(&connector->hdcp_check_work, intel_hdcp_check_work); diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index f17eb2910bdb..8f5831d4b483 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -20,6 +20,7 @@ #define DRM_HDCP_V_PRIME_PART_LEN 4 #define DRM_HDCP_V_PRIME_NUM_PARTS 5 #define DRM_HDCP_NUM_DOWNSTREAM(x) (x & 0x7f) +#define DRM_HDCP_DEPTH(x) (x & 0x7) #define DRM_HDCP_MAX_CASCADE_EXCEEDED(x) (x & BIT(3)) #define DRM_HDCP_MAX_DEVICE_EXCEEDED(x) (x & BIT(7)) -- https://clearlinux.org