@@ -3500,7 +3500,8 @@ static void intel_enable_ddi(struct intel_encoder *encoder,
if (conn_state->content_protection ==
DRM_MODE_CONTENT_PROTECTION_DESIRED)
intel_hdcp_enable(to_intel_connector(conn_state->connector),
- (u8)conn_state->cp_content_type);
+ (u8)conn_state->cp_content_type,
+ conn_state->cp_srm_blob_id);
}
static void intel_disable_ddi_dp(struct intel_encoder *encoder,
@@ -3570,7 +3571,8 @@ static void intel_ddi_update_hdcp(struct intel_encoder *encoder,
if (conn_state->content_protection ==
DRM_MODE_CONTENT_PROTECTION_DESIRED)
intel_hdcp_enable(to_intel_connector(conn_state->connector),
- (u8)conn_state->cp_content_type);
+ (u8)conn_state->cp_content_type,
+ conn_state->cp_srm_blob_id);
else if (conn_state->content_protection ==
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
intel_hdcp_disable(to_intel_connector(conn_state->connector));
@@ -482,6 +482,11 @@ struct intel_hdcp {
wait_queue_head_t cp_irq_queue;
atomic_t cp_irq_count;
int cp_irq_count_cached;
+
+ /* list of Revocated KSVs and their count from SRM blob Parsing */
+ unsigned int revocated_ksv_cnt;
+ u8 *revocated_ksv_list;
+ u32 srm_blob_id;
};
struct intel_connector {
@@ -2151,7 +2156,8 @@ void intel_hdcp_atomic_check(struct drm_connector *connector,
struct drm_connector_state *new_state);
int intel_hdcp_init(struct intel_connector *connector,
const struct intel_hdcp_shim *hdcp_shim);
-int intel_hdcp_enable(struct intel_connector *connector, u8 content_type);
+int intel_hdcp_enable(struct intel_connector *connector, u8 content_type,
+ u32 srm_blob_id);
int intel_hdcp_disable(struct intel_connector *connector);
bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port);
bool intel_hdcp_capable(struct intel_connector *connector);
@@ -1805,6 +1805,10 @@ int intel_hdcp_init(struct intel_connector *connector,
if (ret)
return ret;
+ ret = drm_connector_attach_cp_srm_property(&connector->base);
+ if (ret)
+ return ret;
+
hdcp->shim = shim;
mutex_init(&hdcp->mutex);
INIT_DELAYED_WORK(&hdcp->check_work, intel_hdcp_check_work);
@@ -1817,7 +1821,144 @@ int intel_hdcp_init(struct intel_connector *connector,
return 0;
}
-int intel_hdcp_enable(struct intel_connector *connector, u8 content_type)
+static u32 intel_hdcp_get_revocated_ksv_count(u8 *buf, u32 vrls_length)
+{
+ u32 parsed_bytes = 0, ksv_count = 0, vrl_ksv_cnt, vrl_sz;
+
+ do {
+ vrl_ksv_cnt = *buf;
+ ksv_count += vrl_ksv_cnt;
+
+ vrl_sz = (vrl_ksv_cnt * DRM_HDCP_KSV_LEN) + 1;
+ buf += vrl_sz;
+ parsed_bytes += vrl_sz;
+ } while (parsed_bytes < vrls_length);
+
+ return ksv_count;
+}
+
+static u32 intel_hdcp_get_revocated_ksvs(u8 *ksv_list, const u8 *buf,
+ u32 vrls_length)
+{
+ u32 parsed_bytes = 0, ksv_count = 0;
+ u32 vrl_ksv_cnt, vrl_ksv_sz, vrl_idx = 0;
+
+ do {
+ vrl_ksv_cnt = *buf;
+ vrl_ksv_sz = vrl_ksv_cnt * DRM_HDCP_KSV_LEN;
+ buf++;
+
+ DRM_DEBUG_KMS("vrl: %d, Revoked KSVs: %d\n", vrl_idx++,
+ vrl_ksv_cnt);
+ memcpy(ksv_list, buf, vrl_ksv_sz);
+ ksv_count += vrl_ksv_cnt;
+ ksv_list += vrl_ksv_sz;
+ buf += vrl_ksv_sz;
+
+ parsed_bytes += (vrl_ksv_sz + 1);
+ } while (parsed_bytes < vrls_length);
+
+ return ksv_count;
+}
+
+static int intel_hdcp_parse_srm(struct drm_connector *connector,
+ struct drm_property_blob *blob)
+{
+ struct intel_hdcp *hdcp = &(to_intel_connector(connector)->hdcp);
+ struct hdcp_srm_header *header;
+ u32 vrl_length, ksv_count;
+ u8 *buf;
+
+ if (blob->length < (sizeof(struct hdcp_srm_header) +
+ DRM_HDCP_1_4_VRL_LENGTH_SIZE + DRM_HDCP_1_4_DCP_SIG_SIZE)) {
+ DRM_ERROR("Invalid blob length\n");
+ return -EINVAL;
+ }
+
+ header = (struct hdcp_srm_header *)blob->data;
+
+ DRM_DEBUG_KMS("SRM ID: 0x%x, SRM Ver: 0x%x, SRM Gen No: 0x%x\n",
+ header->spec_indicator.srm_id,
+ __swab16(header->srm_version), header->srm_gen_no);
+ WARN_ON(header->spec_indicator.reserved_hi ||
+ header->spec_indicator.reserved_lo);
+
+ if (header->spec_indicator.srm_id != DRM_HDCP_1_4_SRM_ID) {
+ DRM_ERROR("Invalid srm_id\n");
+ return -EINVAL;
+ }
+
+ buf = blob->data + sizeof(*header);
+ vrl_length = (*buf << 16 | *(buf + 1) << 8 | *(buf + 2));
+ if (blob->length < (sizeof(struct hdcp_srm_header) + vrl_length) ||
+ vrl_length < (DRM_HDCP_1_4_VRL_LENGTH_SIZE +
+ DRM_HDCP_1_4_DCP_SIG_SIZE)) {
+ DRM_ERROR("Invalid blob length or vrl length\n");
+ return -EINVAL;
+ }
+
+ /* Length of the all vrls combined */
+ vrl_length -= (DRM_HDCP_1_4_VRL_LENGTH_SIZE +
+ DRM_HDCP_1_4_DCP_SIG_SIZE);
+ if (!vrl_length) {
+ DRM_DEBUG("No vrl found\n");
+ return -EINVAL;
+ }
+ buf += DRM_HDCP_1_4_VRL_LENGTH_SIZE;
+
+ ksv_count = intel_hdcp_get_revocated_ksv_count(buf, vrl_length);
+ if (!ksv_count) {
+ DRM_DEBUG_KMS("Revocated KSV count is 0\n");
+ return 0;
+ }
+
+ kfree(hdcp->revocated_ksv_list);
+ hdcp->revocated_ksv_list = kzalloc(ksv_count * DRM_HDCP_KSV_LEN,
+ GFP_KERNEL);
+ if (!hdcp->revocated_ksv_list) {
+ DRM_ERROR("Out of Memory\n");
+ return -ENOMEM;
+ }
+
+ if (intel_hdcp_get_revocated_ksvs(hdcp->revocated_ksv_list,
+ buf, vrl_length) != ksv_count) {
+ hdcp->revocated_ksv_cnt = 0;
+ kfree(hdcp->revocated_ksv_list);
+ return -EINVAL;
+ }
+
+ hdcp->revocated_ksv_cnt = ksv_count;
+ return 0;
+}
+
+static void intel_hdcp_update_srm(struct intel_connector *intel_connector,
+ u32 srm_blob_id)
+{
+ struct drm_connector *connector = &intel_connector->base;
+ struct intel_hdcp *hdcp = &intel_connector->hdcp;
+ struct drm_property_blob *blob;
+
+ DRM_DEBUG_KMS("srm_blob_id %u\n", srm_blob_id);
+
+ if (!srm_blob_id) {
+ kfree(hdcp->revocated_ksv_list);
+ hdcp->revocated_ksv_cnt = 0;
+ hdcp->srm_blob_id = srm_blob_id;
+ return;
+ }
+
+ blob = drm_property_lookup_blob(connector->dev, srm_blob_id);
+ if (!blob || !blob->data)
+ return;
+
+ if (!intel_hdcp_parse_srm(connector, blob))
+ hdcp->srm_blob_id = srm_blob_id;
+
+ drm_property_blob_put(blob);
+}
+
+int intel_hdcp_enable(struct intel_connector *connector, u8 content_type,
+ u32 srm_blob_id)
{
struct intel_hdcp *hdcp = &connector->hdcp;
unsigned long check_link_interval = DRM_HDCP_CHECK_PERIOD_MS;
@@ -1828,9 +1969,11 @@ int intel_hdcp_enable(struct intel_connector *connector, u8 content_type)
mutex_lock(&hdcp->mutex);
WARN_ON(hdcp->value == DRM_MODE_CONTENT_PROTECTION_ENABLED);
-
hdcp->content_type = content_type;
+ if (srm_blob_id != hdcp->srm_blob_id)
+ intel_hdcp_update_srm(connector, srm_blob_id);
+
/*
* Considering that HDCP2.2 is more secure than HDCP1.4, If the setup
* is capable of HDCP2.2, it is preferred to use HDCP2.2.
@@ -265,4 +265,18 @@ void drm_hdcp2_u32_to_seq_num(u8 seq_num[HDCP_2_2_SEQ_NUM_LEN], u32 val)
seq_num[2] = val;
}
+#define DRM_HDCP_1_4_SRM_ID 0x8
+#define DRM_HDCP_1_4_VRL_LENGTH_SIZE 3
+#define DRM_HDCP_1_4_DCP_SIG_SIZE 40
+
+struct hdcp_srm_header {
+ struct {
+ u8 reserved_hi:4;
+ u8 srm_id:4;
+ u8 reserved_lo;
+ } spec_indicator;
+ u16 srm_version;
+ u8 srm_gen_no;
+} __packed;
+
#endif
This patch adds a drm blob property to selected connectors. And also adds capability to parse the new HDCP1.4 srm blob passed through cp_srm_property. The revocated KSV list and their counts are stored in the intel_hdcp. This list should be used for revocation check of BKSVs in first stage HDCP authentication and for revocation check of ksv_fifo in second stage authentication. Signed-off-by: Ramalingam C <ramalingam.c@intel.com> --- drivers/gpu/drm/i915/intel_ddi.c | 6 +- drivers/gpu/drm/i915/intel_drv.h | 8 ++- drivers/gpu/drm/i915/intel_hdcp.c | 147 +++++++++++++++++++++++++++++++++++++- include/drm/drm_hdcp.h | 14 ++++ 4 files changed, 170 insertions(+), 5 deletions(-)