Message ID | 1548917996-28081-10-git-send-email-ramalingam.c@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | drm/i915: Implement HDCP2.2 | expand |
>-----Original Message----- >From: C, Ramalingam >Sent: Thursday, January 31, 2019 12:29 PM >To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; >daniel.vetter@ffwll.ch; Winkler, Tomas <tomas.winkler@intel.com>; Shankar, >Uma <uma.shankar@intel.com> >Cc: C, Ramalingam <ramalingam.c@intel.com> >Subject: [PATCH v10 09/40] drm/i915: Implement HDCP2.2 receiver >authentication > >Implements HDCP2.2 authentication for hdcp2.2 receivers, with following steps: > Authentication and Key exchange (AKE). > Locality Check (LC). > Session Key Exchange(SKE). > DP Errata for stream type configuration for receivers. > >At AKE, the HDCP Receiver’s public key certificate is verified by the HDCP >Transmitter. A Master Key k m is exchanged. > >At LC, the HDCP Transmitter enforces locality on the content by requiring that the >Round Trip Time (RTT) between a pair of messages is not more than 20 ms. > >At SKE, The HDCP Transmitter exchanges Session Key ks with the HDCP Receiver. > >In DP HDCP2.2 encryption and decryption logics use the stream type as one of the >parameter. So Before enabling the Encryption DP HDCP2.2 receiver needs to be >communicated with stream type. This is added to spec as ERRATA. > >This generic implementation is complete only with the hdcp2 specific functions >defined at hdcp_shim. > >v2: Rebased. >v3: > %s/PARING/PAIRING > Coding style fixing [Uma] >v4: > Rebased as part of patch reordering. > Defined the functions for mei services. [Daniel] >v5: > Redefined the mei service functions as per comp redesign. > Required intel_hdcp members are defined [Sean Paul] >v6: > Typo of cipher is Fixed [Uma] > %s/uintxx_t/uxx > Check for comp_master is removed. >v7: > Adjust to the new interface. > Avoid using bool structure members. [Tomas] >v8: Rebased. >v9: > bool is used in struct intel_hdcp [Daniel] > config_stream_type is redesigned [Daniel] > >Signed-off-by: Ramalingam C <ramalingam.c@intel.com> >Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Looks ok to me. Reviewed-by: Uma Shankar <uma.shankar@intel.com> >--- > drivers/gpu/drm/i915/intel_drv.h | 34 +++++++ >drivers/gpu/drm/i915/intel_hdcp.c | 197 >+++++++++++++++++++++++++++++++++++--- > 2 files changed, 216 insertions(+), 15 deletions(-) > >diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h >index 31c7a4577ca9..e6792304520a 100644 >--- a/drivers/gpu/drm/i915/intel_drv.h >+++ b/drivers/gpu/drm/i915/intel_drv.h >@@ -393,6 +393,22 @@ struct intel_hdcp_shim { > /* Detects whether Panel is HDCP2.2 capable */ > int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port, > bool *capable); >+ >+ /* Write HDCP2.2 messages */ >+ int (*write_2_2_msg)(struct intel_digital_port *intel_dig_port, >+ void *buf, size_t size); >+ >+ /* Read HDCP2.2 messages */ >+ int (*read_2_2_msg)(struct intel_digital_port *intel_dig_port, >+ u8 msg_id, void *buf, size_t size); >+ >+ /* >+ * Implementation of DP HDCP2.2 Errata for the communication of >stream >+ * type to Receivers. In DP HDCP2.2 Stream type is one of the input to >+ * the HDCP2.2 Cipher for En/De-Cryption. Not applicable for HDMI. >+ */ >+ int (*config_stream_type)(struct intel_digital_port *intel_dig_port, >+ bool is_repeater, u8 type); > }; > > struct intel_hdcp { >@@ -420,6 +436,24 @@ struct intel_hdcp { > */ > u8 content_type; > struct hdcp_port_data port_data; >+ >+ bool is_paired; >+ bool is_repeater; >+ >+ /* >+ * Count of ReceiverID_List received. Initialized to 0 at AKE_INIT. >+ * Incremented after processing the RepeaterAuth_Send_ReceiverID_List. >+ * When it rolls over re-auth has to be triggered. >+ */ >+ u32 seq_num_v; >+ >+ /* >+ * Count of RepeaterAuth_Stream_Manage msg propagated. >+ * Initialized to 0 on AKE_INIT. Incremented after every successful >+ * transmission of RepeaterAuth_Stream_Manage message. When it rolls >+ * over re-Auth has to be triggered. >+ */ >+ u32 seq_num_m; > }; > > struct intel_connector { >diff --git a/drivers/gpu/drm/i915/intel_hdcp.c >b/drivers/gpu/drm/i915/intel_hdcp.c >index fbf8b7893bfa..1c81e17dc6c4 100644 >--- a/drivers/gpu/drm/i915/intel_hdcp.c >+++ b/drivers/gpu/drm/i915/intel_hdcp.c >@@ -17,6 +17,7 @@ > > #define KEY_LOAD_TRIES 5 > #define ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50 >+#define HDCP2_LC_RETRY_CNT 3 > > static > bool intel_hdcp_is_ksv_valid(u8 *ksv) >@@ -853,7 +854,7 @@ bool is_hdcp_supported(struct drm_i915_private >*dev_priv, enum port port) > return INTEL_GEN(dev_priv) >= 9 && port < PORT_E; } > >-static __attribute__((unused)) int >+static int > hdcp2_prepare_ake_init(struct intel_connector *connector, > struct hdcp2_ake_init *ake_data) { @@ -878,7 +879,7 @@ >hdcp2_prepare_ake_init(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector, > struct hdcp2_ake_send_cert *rx_cert, > bool *paired, >@@ -908,9 +909,8 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >-hdcp2_verify_hprime(struct intel_connector *connector, >- struct hdcp2_ake_send_hprime *rx_hprime) >+static int hdcp2_verify_hprime(struct intel_connector *connector, >+ struct hdcp2_ake_send_hprime *rx_hprime) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-933,7 +933,7 @@ hdcp2_verify_hprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_store_pairing_info(struct intel_connector *connector, > struct hdcp2_ake_send_pairing_info *pairing_info) { >@@ -958,7 +958,7 @@ hdcp2_store_pairing_info(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_prepare_lc_init(struct intel_connector *connector, > struct hdcp2_lc_init *lc_init) > { >@@ -983,7 +983,7 @@ hdcp2_prepare_lc_init(struct intel_connector >*connector, > return ret; > } > >-static __attribute__((unused)) int >+static int > hdcp2_verify_lprime(struct intel_connector *connector, > struct hdcp2_lc_send_lprime *rx_lprime) { @@ -1008,9 >+1008,8 @@ hdcp2_verify_lprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) >-int hdcp2_prepare_skey(struct intel_connector *connector, >- struct hdcp2_ske_send_eks *ske_data) >+static int hdcp2_prepare_skey(struct intel_connector *connector, >+ struct hdcp2_ske_send_eks *ske_data) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-1087,8 +1086,7 @@ hdcp2_verify_mprime(struct intel_connector *connector, > return ret; > } > >-static __attribute__((unused)) >-int hdcp2_authenticate_port(struct intel_connector *connector) >+static int hdcp2_authenticate_port(struct intel_connector *connector) > { > struct hdcp_port_data *data = &connector->hdcp.port_data; > struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ >-1137,11 +1135,180 @@ static int hdcp2_deauthenticate_port(struct >intel_connector *connector) > return hdcp2_close_mei_session(connector); > } > >+/* Authentication flow starts from here */ static int >+hdcp2_authentication_key_exchange(struct intel_connector *connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ union { >+ struct hdcp2_ake_init ake_init; >+ struct hdcp2_ake_send_cert send_cert; >+ struct hdcp2_ake_no_stored_km no_stored_km; >+ struct hdcp2_ake_send_hprime send_hprime; >+ struct hdcp2_ake_send_pairing_info pairing_info; >+ } msgs; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ size_t size; >+ int ret; >+ >+ /* Init for seq_num */ >+ hdcp->seq_num_v = 0; >+ hdcp->seq_num_m = 0; >+ >+ ret = hdcp2_prepare_ake_init(connector, &msgs.ake_init); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.ake_init, >+ sizeof(msgs.ake_init)); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_AKE_SEND_CERT, >+ &msgs.send_cert, sizeof(msgs.send_cert)); >+ if (ret < 0) >+ return ret; >+ >+ if (msgs.send_cert.rx_caps[0] != HDCP_2_2_RX_CAPS_VERSION_VAL) >+ return -EINVAL; >+ >+ hdcp->is_repeater = >HDCP_2_2_RX_REPEATER(msgs.send_cert.rx_caps[2]); >+ >+ /* >+ * Here msgs.no_stored_km will hold msgs corresponding to the km >+ * stored also. >+ */ >+ ret = hdcp2_verify_rx_cert_prepare_km(connector, &msgs.send_cert, >+ &hdcp->is_paired, >+ &msgs.no_stored_km, &size); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.no_stored_km, size); >+ if (ret < 0) >+ return ret; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, >HDCP_2_2_AKE_SEND_HPRIME, >+ &msgs.send_hprime, >sizeof(msgs.send_hprime)); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp2_verify_hprime(connector, &msgs.send_hprime); >+ if (ret < 0) >+ return ret; >+ >+ if (!hdcp->is_paired) { >+ /* Pairing is required */ >+ ret = shim->read_2_2_msg(intel_dig_port, >+ HDCP_2_2_AKE_SEND_PAIRING_INFO, >+ &msgs.pairing_info, >+ sizeof(msgs.pairing_info)); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp2_store_pairing_info(connector, &msgs.pairing_info); >+ if (ret < 0) >+ return ret; >+ hdcp->is_paired = true; >+ } >+ >+ return 0; >+} >+ >+static int hdcp2_locality_check(struct intel_connector *connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ union { >+ struct hdcp2_lc_init lc_init; >+ struct hdcp2_lc_send_lprime send_lprime; >+ } msgs; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ int tries = HDCP2_LC_RETRY_CNT, ret, i; >+ >+ for (i = 0; i < tries; i++) { >+ ret = hdcp2_prepare_lc_init(connector, &msgs.lc_init); >+ if (ret < 0) >+ continue; >+ >+ ret = shim->write_2_2_msg(intel_dig_port, &msgs.lc_init, >+ sizeof(msgs.lc_init)); >+ if (ret < 0) >+ continue; >+ >+ ret = shim->read_2_2_msg(intel_dig_port, >+ HDCP_2_2_LC_SEND_LPRIME, >+ &msgs.send_lprime, >+ sizeof(msgs.send_lprime)); >+ if (ret < 0) >+ continue; >+ >+ ret = hdcp2_verify_lprime(connector, &msgs.send_lprime); >+ if (!ret) >+ break; >+ } >+ >+ return ret; >+} >+ >+static int hdcp2_session_key_exchange(struct intel_connector >+*connector) { >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ struct hdcp2_ske_send_eks send_eks; >+ int ret; >+ >+ ret = hdcp2_prepare_skey(connector, &send_eks); >+ if (ret < 0) >+ return ret; >+ >+ ret = hdcp->shim->write_2_2_msg(intel_dig_port, &send_eks, >+ sizeof(send_eks)); >+ if (ret < 0) >+ return ret; >+ >+ return 0; >+} >+ > static int hdcp2_authenticate_sink(struct intel_connector *connector) { >- DRM_ERROR("Sink authentication is done in subsequent patches\n"); >+ struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); >+ struct intel_hdcp *hdcp = &connector->hdcp; >+ const struct intel_hdcp_shim *shim = hdcp->shim; >+ int ret; > >- return -EINVAL; >+ ret = hdcp2_authentication_key_exchange(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("AKE Failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ ret = hdcp2_locality_check(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("Locality Check failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ ret = hdcp2_session_key_exchange(connector); >+ if (ret < 0) { >+ DRM_DEBUG_KMS("SKE Failed. Err : %d\n", ret); >+ return ret; >+ } >+ >+ if (shim->config_stream_type) { >+ ret = shim->config_stream_type(intel_dig_port, >+ hdcp->is_repeater, >+ hdcp->content_type); >+ if (ret < 0) >+ return ret; >+ } >+ >+ hdcp->port_data.streams[0].stream_type = hdcp->content_type; >+ ret = hdcp2_authenticate_port(connector); >+ if (ret < 0) >+ return ret; >+ >+ return ret; > } > > static int hdcp2_enable_encryption(struct intel_connector *connector) >-- >2.7.4
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 31c7a4577ca9..e6792304520a 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -393,6 +393,22 @@ struct intel_hdcp_shim { /* Detects whether Panel is HDCP2.2 capable */ int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port, bool *capable); + + /* Write HDCP2.2 messages */ + int (*write_2_2_msg)(struct intel_digital_port *intel_dig_port, + void *buf, size_t size); + + /* Read HDCP2.2 messages */ + int (*read_2_2_msg)(struct intel_digital_port *intel_dig_port, + u8 msg_id, void *buf, size_t size); + + /* + * Implementation of DP HDCP2.2 Errata for the communication of stream + * type to Receivers. In DP HDCP2.2 Stream type is one of the input to + * the HDCP2.2 Cipher for En/De-Cryption. Not applicable for HDMI. + */ + int (*config_stream_type)(struct intel_digital_port *intel_dig_port, + bool is_repeater, u8 type); }; struct intel_hdcp { @@ -420,6 +436,24 @@ struct intel_hdcp { */ u8 content_type; struct hdcp_port_data port_data; + + bool is_paired; + bool is_repeater; + + /* + * Count of ReceiverID_List received. Initialized to 0 at AKE_INIT. + * Incremented after processing the RepeaterAuth_Send_ReceiverID_List. + * When it rolls over re-auth has to be triggered. + */ + u32 seq_num_v; + + /* + * Count of RepeaterAuth_Stream_Manage msg propagated. + * Initialized to 0 on AKE_INIT. Incremented after every successful + * transmission of RepeaterAuth_Stream_Manage message. When it rolls + * over re-Auth has to be triggered. + */ + u32 seq_num_m; }; struct intel_connector { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index fbf8b7893bfa..1c81e17dc6c4 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -17,6 +17,7 @@ #define KEY_LOAD_TRIES 5 #define ENCRYPT_STATUS_CHANGE_TIMEOUT_MS 50 +#define HDCP2_LC_RETRY_CNT 3 static bool intel_hdcp_is_ksv_valid(u8 *ksv) @@ -853,7 +854,7 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) return INTEL_GEN(dev_priv) >= 9 && port < PORT_E; } -static __attribute__((unused)) int +static int hdcp2_prepare_ake_init(struct intel_connector *connector, struct hdcp2_ake_init *ake_data) { @@ -878,7 +879,7 @@ hdcp2_prepare_ake_init(struct intel_connector *connector, return ret; } -static __attribute__((unused)) int +static int hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector, struct hdcp2_ake_send_cert *rx_cert, bool *paired, @@ -908,9 +909,8 @@ hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector, return ret; } -static __attribute__((unused)) int -hdcp2_verify_hprime(struct intel_connector *connector, - struct hdcp2_ake_send_hprime *rx_hprime) +static int hdcp2_verify_hprime(struct intel_connector *connector, + struct hdcp2_ake_send_hprime *rx_hprime) { struct hdcp_port_data *data = &connector->hdcp.port_data; struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ -933,7 +933,7 @@ hdcp2_verify_hprime(struct intel_connector *connector, return ret; } -static __attribute__((unused)) int +static int hdcp2_store_pairing_info(struct intel_connector *connector, struct hdcp2_ake_send_pairing_info *pairing_info) { @@ -958,7 +958,7 @@ hdcp2_store_pairing_info(struct intel_connector *connector, return ret; } -static __attribute__((unused)) int +static int hdcp2_prepare_lc_init(struct intel_connector *connector, struct hdcp2_lc_init *lc_init) { @@ -983,7 +983,7 @@ hdcp2_prepare_lc_init(struct intel_connector *connector, return ret; } -static __attribute__((unused)) int +static int hdcp2_verify_lprime(struct intel_connector *connector, struct hdcp2_lc_send_lprime *rx_lprime) { @@ -1008,9 +1008,8 @@ hdcp2_verify_lprime(struct intel_connector *connector, return ret; } -static __attribute__((unused)) -int hdcp2_prepare_skey(struct intel_connector *connector, - struct hdcp2_ske_send_eks *ske_data) +static int hdcp2_prepare_skey(struct intel_connector *connector, + struct hdcp2_ske_send_eks *ske_data) { struct hdcp_port_data *data = &connector->hdcp.port_data; struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ -1087,8 +1086,7 @@ hdcp2_verify_mprime(struct intel_connector *connector, return ret; } -static __attribute__((unused)) -int hdcp2_authenticate_port(struct intel_connector *connector) +static int hdcp2_authenticate_port(struct intel_connector *connector) { struct hdcp_port_data *data = &connector->hdcp.port_data; struct drm_i915_private *dev_priv = to_i915(connector->base.dev); @@ -1137,11 +1135,180 @@ static int hdcp2_deauthenticate_port(struct intel_connector *connector) return hdcp2_close_mei_session(connector); } +/* Authentication flow starts from here */ +static int hdcp2_authentication_key_exchange(struct intel_connector *connector) +{ + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + union { + struct hdcp2_ake_init ake_init; + struct hdcp2_ake_send_cert send_cert; + struct hdcp2_ake_no_stored_km no_stored_km; + struct hdcp2_ake_send_hprime send_hprime; + struct hdcp2_ake_send_pairing_info pairing_info; + } msgs; + const struct intel_hdcp_shim *shim = hdcp->shim; + size_t size; + int ret; + + /* Init for seq_num */ + hdcp->seq_num_v = 0; + hdcp->seq_num_m = 0; + + ret = hdcp2_prepare_ake_init(connector, &msgs.ake_init); + if (ret < 0) + return ret; + + ret = shim->write_2_2_msg(intel_dig_port, &msgs.ake_init, + sizeof(msgs.ake_init)); + if (ret < 0) + return ret; + + ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_AKE_SEND_CERT, + &msgs.send_cert, sizeof(msgs.send_cert)); + if (ret < 0) + return ret; + + if (msgs.send_cert.rx_caps[0] != HDCP_2_2_RX_CAPS_VERSION_VAL) + return -EINVAL; + + hdcp->is_repeater = HDCP_2_2_RX_REPEATER(msgs.send_cert.rx_caps[2]); + + /* + * Here msgs.no_stored_km will hold msgs corresponding to the km + * stored also. + */ + ret = hdcp2_verify_rx_cert_prepare_km(connector, &msgs.send_cert, + &hdcp->is_paired, + &msgs.no_stored_km, &size); + if (ret < 0) + return ret; + + ret = shim->write_2_2_msg(intel_dig_port, &msgs.no_stored_km, size); + if (ret < 0) + return ret; + + ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_AKE_SEND_HPRIME, + &msgs.send_hprime, sizeof(msgs.send_hprime)); + if (ret < 0) + return ret; + + ret = hdcp2_verify_hprime(connector, &msgs.send_hprime); + if (ret < 0) + return ret; + + if (!hdcp->is_paired) { + /* Pairing is required */ + ret = shim->read_2_2_msg(intel_dig_port, + HDCP_2_2_AKE_SEND_PAIRING_INFO, + &msgs.pairing_info, + sizeof(msgs.pairing_info)); + if (ret < 0) + return ret; + + ret = hdcp2_store_pairing_info(connector, &msgs.pairing_info); + if (ret < 0) + return ret; + hdcp->is_paired = true; + } + + return 0; +} + +static int hdcp2_locality_check(struct intel_connector *connector) +{ + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + union { + struct hdcp2_lc_init lc_init; + struct hdcp2_lc_send_lprime send_lprime; + } msgs; + const struct intel_hdcp_shim *shim = hdcp->shim; + int tries = HDCP2_LC_RETRY_CNT, ret, i; + + for (i = 0; i < tries; i++) { + ret = hdcp2_prepare_lc_init(connector, &msgs.lc_init); + if (ret < 0) + continue; + + ret = shim->write_2_2_msg(intel_dig_port, &msgs.lc_init, + sizeof(msgs.lc_init)); + if (ret < 0) + continue; + + ret = shim->read_2_2_msg(intel_dig_port, + HDCP_2_2_LC_SEND_LPRIME, + &msgs.send_lprime, + sizeof(msgs.send_lprime)); + if (ret < 0) + continue; + + ret = hdcp2_verify_lprime(connector, &msgs.send_lprime); + if (!ret) + break; + } + + return ret; +} + +static int hdcp2_session_key_exchange(struct intel_connector *connector) +{ + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + struct hdcp2_ske_send_eks send_eks; + int ret; + + ret = hdcp2_prepare_skey(connector, &send_eks); + if (ret < 0) + return ret; + + ret = hdcp->shim->write_2_2_msg(intel_dig_port, &send_eks, + sizeof(send_eks)); + if (ret < 0) + return ret; + + return 0; +} + static int hdcp2_authenticate_sink(struct intel_connector *connector) { - DRM_ERROR("Sink authentication is done in subsequent patches\n"); + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + const struct intel_hdcp_shim *shim = hdcp->shim; + int ret; - return -EINVAL; + ret = hdcp2_authentication_key_exchange(connector); + if (ret < 0) { + DRM_DEBUG_KMS("AKE Failed. Err : %d\n", ret); + return ret; + } + + ret = hdcp2_locality_check(connector); + if (ret < 0) { + DRM_DEBUG_KMS("Locality Check failed. Err : %d\n", ret); + return ret; + } + + ret = hdcp2_session_key_exchange(connector); + if (ret < 0) { + DRM_DEBUG_KMS("SKE Failed. Err : %d\n", ret); + return ret; + } + + if (shim->config_stream_type) { + ret = shim->config_stream_type(intel_dig_port, + hdcp->is_repeater, + hdcp->content_type); + if (ret < 0) + return ret; + } + + hdcp->port_data.streams[0].stream_type = hdcp->content_type; + ret = hdcp2_authenticate_port(connector); + if (ret < 0) + return ret; + + return ret; } static int hdcp2_enable_encryption(struct intel_connector *connector)