The sequence for HDCP2.2 authentication and encryption is implemented in I915. Encoder specific implementations are moved into hdcp_shim.
Intel HWs supports HDCP2.2 through ME FW. Hence this series introduces a client driver for mei bus, so that for HDCP2.2 authentication, HDCP2.2 stack in I915 can avail the services from ME FW.
DRM_I915 selects INTEL_MEI_HDCP, which selects INTEL_MEI_ME and INTEL_MEI. If we are interested in disabling the MEI_HDCP and MEI Bus then we need an option to disable the HDCP2.2 in I915 (like DRM_I915_HDCP2.2!?). Till then they are binded.
Userspace interface remains unchanged as version agnostic. When userspace request for HDCP enable, Kernel will detect the HDCP source and sink's HDCP version(1.4/2.2)capability and enable the best capable version for that combination.
This series enables the HDCP2.2 for Type0 content streams. Thanks a lot for Daniel vetter for reviewing v4.
Major Changes in v5: - Component is used for I915-MEI HDCP interface [Daniel]. - Patches are restructured for bisecting. - Lookup tables are used for DP and HDMI HDCP2.2 messages [Daniel].
GMBus changes are added here for completeness of the series. They are in review at https://patchwork.freedesktop.org/series/41632/ also.
Complete series is hosted at https://github.com/ramalingampc2008/drm-tip.git hdcp2_2_v5
Ramalingam C (39): drm: hdcp2.2 authentication msg definitions drm: HDMI and DP specific HDCP2.2 defines linux/mei: Header for mei_hdcp driver interface drm/i915: wrapping all hdcp var into intel_hdcp drm/i915: Define HDCP2.2 related variables drm/i915: Define Intel HDCP2.2 registers drm/i915: Initialize HDCP2.2 and its MEI interface drm/i915: Schedule hdcp_check_link in _intel_hdcp_enable drm/i915: Pullout the bksv read and validation drm/i915: Enable superior HDCP ver that is capable drm/i915: Enable HDCP1.4 incase of HDCP2.2 failure drm/i915: Implement HDCP2.2 Enable and Disable drm/i915: Enable and Disable HDCP2.2 port encryption drm/i915: Implement HDCP2.2 receiver authentication drm/i915: Implement HDCP2.2 repeater authentication drm/i915: Implement HDCP2.2 link integrity check drm/i915: Handle HDCP2.2 downstream topology change drm/i915: hdcp_check_link only on CP_IRQ drm/i915: Check HDCP 1.4 and 2.2 link on CP_IRQ drm/i915/gmbus: Increase the Bytes per Rd/Wr Op drm/i915/gmbus: Enable burst read drm/i915: Implement the HDCP2.2 support for DP drm/i915: Implement the HDCP2.2 support for HDMI drm/i915: Add HDCP2.2 support for DP connectors drm/i915: Add HDCP2.2 support for HDMI connectors misc/mei/hdcp: Client driver for HDCP application misc/mei/hdcp: Component framework for I915 Interface misc/mei/hdcp: Define ME FW interface for HDCP2.2 misc/mei/hdcp: Initiate Wired HDCP2.2 Tx Session misc/mei/hdcp: Verify Receiver Cert and prepare km misc/mei/hdcp: Verify H_prime misc/mei/hdcp: Store the HDCP Pairing info misc/mei/hdcp: Initiate Locality check misc/mei/hdcp: Verify L_prime misc/mei/hdcp: Prepare Session Key misc/mei/hdcp: Repeater topology verification and ack misc/mei/hdcp: Verify M_prime misc/mei/hdcp: Enabling the HDCP authentication misc/mei/hdcp: Closing wired HDCP2.2 Tx Session
Tomas Winkler (1): mei: bus: whitelist hdcp client
drivers/gpu/drm/i915/Kconfig | 1 + drivers/gpu/drm/i915/i915_drv.h | 5 + drivers/gpu/drm/i915/i915_reg.h | 34 + drivers/gpu/drm/i915/intel_display.c | 7 +- drivers/gpu/drm/i915/intel_dp.c | 345 ++++++++- drivers/gpu/drm/i915/intel_drv.h | 88 ++- drivers/gpu/drm/i915/intel_hdcp.c | 1289 ++++++++++++++++++++++++++++++++-- drivers/gpu/drm/i915/intel_hdmi.c | 190 ++++- drivers/gpu/drm/i915/intel_i2c.c | 71 +- drivers/misc/mei/Kconfig | 7 + drivers/misc/mei/Makefile | 2 + drivers/misc/mei/bus-fixup.c | 16 + drivers/misc/mei/hdcp/Makefile | 6 + drivers/misc/mei/hdcp/mei_hdcp.c | 862 +++++++++++++++++++++++ drivers/misc/mei/hdcp/mei_hdcp.h | 408 +++++++++++ include/drm/drm_dp_helper.h | 51 ++ include/drm/drm_hdcp.h | 232 ++++++ include/drm/i915_component.h | 88 +++ include/linux/mei_hdcp.h | 100 +++ 19 files changed, 3710 insertions(+), 92 deletions(-) create mode 100644 drivers/misc/mei/hdcp/Makefile create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.c create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.h create mode 100644 include/linux/mei_hdcp.h
This patch defines the hdcp2.2 protocol messages for authentication.
v2: bit_fields are removed. Instead bitmasking used. [Tomas and Jani] prefix HDCP_2_2_ is added to the macros. [Tomas] v3: No Changes. v4: Style and spellings are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- include/drm/drm_hdcp.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+)
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 98e63d870139..3e963c5d04b2 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -38,4 +38,183 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43
+#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 + +/* Protocol message definition for HDCP2.2 specification */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01 + +/* HDCP2.2 Msg IDs */ +#define HDCP_2_2_NULL_MSG 1 +#define HDCP_2_2_AKE_INIT 2 +#define HDCP_2_2_AKE_SEND_CERT 3 +#define HDCP_2_2_AKE_NO_STORED_KM 4 +#define HDCP_2_2_AKE_STORED_KM 5 +#define HDCP_2_2_AKE_SEND_HPRIME 7 +#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 +#define HDCP_2_2_LC_INIT 9 +#define HDCP_2_2_LC_SEND_LPRIME 10 +#define HDCP_2_2_SKE_SEND_EKS 11 +#define HDCP_2_2_REP_SEND_RECVID_LIST 12 +#define HDCP_2_2_REP_SEND_ACK 15 +#define HDCP_2_2_REP_STREAM_MANAGE 16 +#define HDCP_2_2_REP_STREAM_READY 17 +#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50 + +#define HDCP_2_2_RTX_LEN 8 +#define HDCP_2_2_RRX_LEN 8 + +#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 +#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 +#define HDCP_2_2_K_PUB_RX_LEN (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \ + HDCP_2_2_K_PUB_RX_EXP_E_LEN) + +#define HDCP_2_2_DCP_LLC_SIG_LEN 384 + +#define HDCP_2_2_E_KPUB_KM_LEN 128 +#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) +#define HDCP_2_2_H_PRIME_LEN 32 +#define HDCP_2_2_E_KH_KM_LEN 16 +#define HDCP_2_2_RN_LEN 8 +#define HDCP_2_2_L_PRIME_LEN 32 +#define HDCP_2_2_E_DKEY_KS_LEN 16 +#define HDCP_2_2_RIV_LEN 8 +#define HDCP_2_2_SEQ_NUM_LEN 3 +#define HDCP_2_2_LPRIME_HALF_LEN (HDCP_2_2_L_PRIME_LEN / 2) +#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN +#define HDCP_2_2_MAX_DEVICE_COUNT 31 +#define HDCP_2_2_RECEIVER_IDS_MAX_LEN (HDCP_2_2_RECEIVER_ID_LEN * \ + HDCP_2_2_MAX_DEVICE_COUNT) +#define HDCP_2_2_MPRIME_LEN 32 + +/* Following Macros take a byte at a time for bit(s) masking */ +/* + * TODO: This has to be changed for DP MST, as multiple stream on + * same port is possible. + * For HDCP2.2 on HDMI and DP SST this value is always 1. + */ +#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 1 +#define HDCP_2_2_TXCAP_MASK_LEN 2 +#define HDCP_2_2_RXCAPS_LEN 3 +#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) +#define HDCP_2_2_RXINFO_LEN 2 + +/* HDCP1.x compliant device in downstream */ +#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0)) + +/* HDCP2.0 Compliant repeater in downstream */ +#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) +#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) +#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) +#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) +#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) +#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1) + +struct hdcp2_cert_rx { + uint8_t receiver_id[HDCP_2_2_RECEIVER_ID_LEN]; + uint8_t kpub_rx[HDCP_2_2_K_PUB_RX_LEN]; + uint8_t reserved[2]; + uint8_t dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN]; +} __packed; + +struct hdcp2_streamid_type { + uint8_t stream_id; + uint8_t stream_type; +} __packed; + +/* + * The TxCaps field specified in the HDCP HDMI, DP specs + * This field is big endian as specified in the errata. + */ +struct hdcp2_tx_caps { + /* Transmitter must set this to 0x2 */ + uint8_t version; + + /* Reserved for HDCP and DP Spec. Read as Zero */ + uint8_t tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN]; +} __packed; + +/* Main structures for HDCP2.2 protocol communication */ +struct hdcp2_ake_init { + uint8_t msg_id; + uint8_t r_tx[HDCP_2_2_RTX_LEN]; + struct hdcp2_tx_caps tx_caps; +} __packed; + +struct hdcp2_ake_send_cert { + uint8_t msg_id; + struct hdcp2_cert_rx cert_rx; + uint8_t r_rx[HDCP_2_2_RRX_LEN]; + uint8_t rx_caps[HDCP_2_2_RXCAPS_LEN]; +} __packed; + +struct hdcp2_ake_no_stored_km { + uint8_t msg_id; + uint8_t e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN]; +} __packed; + +struct hdcp2_ake_stored_km { + uint8_t msg_id; + uint8_t e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN]; +} __packed; + +struct hdcp2_ake_send_hprime { + uint8_t msg_id; + uint8_t h_prime[HDCP_2_2_H_PRIME_LEN]; +} __packed; + +struct hdcp2_ake_send_pairing_info { + uint8_t msg_id; + uint8_t e_kh_km[HDCP_2_2_E_KH_KM_LEN]; +} __packed; + +struct hdcp2_lc_init { + uint8_t msg_id; + uint8_t r_n[HDCP_2_2_RN_LEN]; +} __packed; + +struct hdcp2_lc_send_lprime { + uint8_t msg_id; + uint8_t l_prime[HDCP_2_2_L_PRIME_LEN]; +} __packed; + +struct hdcp2_ske_send_eks { + uint8_t msg_id; + uint8_t e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN]; + uint8_t riv[HDCP_2_2_RIV_LEN]; +} __packed; + +struct hdcp2_rep_send_receiverid_list { + uint8_t msg_id; + uint8_t rx_info[HDCP_2_2_RXINFO_LEN]; + uint8_t seq_num_v[HDCP_2_2_SEQ_NUM_LEN]; + uint8_t v_prime[HDCP_2_2_LPRIME_HALF_LEN]; + uint8_t receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN]; +} __packed; + +struct hdcp2_rep_send_ack { + uint8_t msg_id; + uint8_t v[HDCP_2_2_LPRIME_HALF_LEN]; +} __packed; + +struct hdcp2_rep_stream_manage { + uint8_t msg_id; + uint8_t seq_num_m[HDCP_2_2_SEQ_NUM_LEN]; + __be16 k; + struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT]; +} __packed; + +struct hdcp2_rep_stream_ready { + uint8_t msg_id; + uint8_t m_prime[HDCP_2_2_MPRIME_LEN]; +} __packed; + +struct hdcp2_dp_errata_stream_type { + uint8_t msg_id; + uint8_t stream_type; +} __packed; + #endif
On Wed, Jun 27, 2018 at 02:09:50PM +0530, Ramalingam C wrote:
This patch defines the hdcp2.2 protocol messages for authentication.
v2: bit_fields are removed. Instead bitmasking used. [Tomas and Jani] prefix HDCP_2_2_ is added to the macros. [Tomas] v3: No Changes. v4: Style and spellings are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_hdcp.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+)
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 98e63d870139..3e963c5d04b2 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -38,4 +38,183 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43
+#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
These don't seem to be related to the patch?
+/* Protocol message definition for HDCP2.2 specification */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01
Why not HDCP_2_2 prefix?
+/* HDCP2.2 Msg IDs */ +#define HDCP_2_2_NULL_MSG 1 +#define HDCP_2_2_AKE_INIT 2 +#define HDCP_2_2_AKE_SEND_CERT 3 +#define HDCP_2_2_AKE_NO_STORED_KM 4 +#define HDCP_2_2_AKE_STORED_KM 5 +#define HDCP_2_2_AKE_SEND_HPRIME 7 +#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 +#define HDCP_2_2_LC_INIT 9 +#define HDCP_2_2_LC_SEND_LPRIME 10 +#define HDCP_2_2_SKE_SEND_EKS 11 +#define HDCP_2_2_REP_SEND_RECVID_LIST 12 +#define HDCP_2_2_REP_SEND_ACK 15 +#define HDCP_2_2_REP_STREAM_MANAGE 16 +#define HDCP_2_2_REP_STREAM_READY 17 +#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50
+#define HDCP_2_2_RTX_LEN 8 +#define HDCP_2_2_RRX_LEN 8
+#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 +#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 +#define HDCP_2_2_K_PUB_RX_LEN (HDCP_2_2_K_PUB_RX_MOD_N_LEN + \
HDCP_2_2_K_PUB_RX_EXP_E_LEN)
+#define HDCP_2_2_DCP_LLC_SIG_LEN 384
+#define HDCP_2_2_E_KPUB_KM_LEN 128 +#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) +#define HDCP_2_2_H_PRIME_LEN 32 +#define HDCP_2_2_E_KH_KM_LEN 16 +#define HDCP_2_2_RN_LEN 8 +#define HDCP_2_2_L_PRIME_LEN 32 +#define HDCP_2_2_E_DKEY_KS_LEN 16 +#define HDCP_2_2_RIV_LEN 8 +#define HDCP_2_2_SEQ_NUM_LEN 3 +#define HDCP_2_2_LPRIME_HALF_LEN (HDCP_2_2_L_PRIME_LEN / 2) +#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN +#define HDCP_2_2_MAX_DEVICE_COUNT 31 +#define HDCP_2_2_RECEIVER_IDS_MAX_LEN (HDCP_2_2_RECEIVER_ID_LEN * \
HDCP_2_2_MAX_DEVICE_COUNT)
+#define HDCP_2_2_MPRIME_LEN 32
+/* Following Macros take a byte at a time for bit(s) masking */ +/*
- TODO: This has to be changed for DP MST, as multiple stream on
- same port is possible.
- For HDCP2.2 on HDMI and DP SST this value is always 1.
- */
+#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 1 +#define HDCP_2_2_TXCAP_MASK_LEN 2 +#define HDCP_2_2_RXCAPS_LEN 3 +#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) +#define HDCP_2_2_RXINFO_LEN 2
+/* HDCP1.x compliant device in downstream */ +#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0))
+/* HDCP2.0 Compliant repeater in downstream */ +#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) +#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) +#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) +#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) +#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) +#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1)
+struct hdcp2_cert_rx {
- uint8_t receiver_id[HDCP_2_2_RECEIVER_ID_LEN];
- uint8_t kpub_rx[HDCP_2_2_K_PUB_RX_LEN];
- uint8_t reserved[2];
- uint8_t dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN];
+} __packed;
+struct hdcp2_streamid_type {
- uint8_t stream_id;
- uint8_t stream_type;
+} __packed;
+/*
- The TxCaps field specified in the HDCP HDMI, DP specs
- This field is big endian as specified in the errata.
- */
+struct hdcp2_tx_caps {
- /* Transmitter must set this to 0x2 */
- uint8_t version;
- /* Reserved for HDCP and DP Spec. Read as Zero */
- uint8_t tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN];
+} __packed;
+/* Main structures for HDCP2.2 protocol communication */ +struct hdcp2_ake_init {
- uint8_t msg_id;
- uint8_t r_tx[HDCP_2_2_RTX_LEN];
- struct hdcp2_tx_caps tx_caps;
+} __packed;
+struct hdcp2_ake_send_cert {
- uint8_t msg_id;
- struct hdcp2_cert_rx cert_rx;
- uint8_t r_rx[HDCP_2_2_RRX_LEN];
- uint8_t rx_caps[HDCP_2_2_RXCAPS_LEN];
+} __packed;
+struct hdcp2_ake_no_stored_km {
- uint8_t msg_id;
- uint8_t e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN];
+} __packed;
+struct hdcp2_ake_stored_km {
- uint8_t msg_id;
- uint8_t e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN];
+} __packed;
+struct hdcp2_ake_send_hprime {
- uint8_t msg_id;
- uint8_t h_prime[HDCP_2_2_H_PRIME_LEN];
+} __packed;
+struct hdcp2_ake_send_pairing_info {
- uint8_t msg_id;
- uint8_t e_kh_km[HDCP_2_2_E_KH_KM_LEN];
+} __packed;
+struct hdcp2_lc_init {
- uint8_t msg_id;
- uint8_t r_n[HDCP_2_2_RN_LEN];
+} __packed;
+struct hdcp2_lc_send_lprime {
- uint8_t msg_id;
- uint8_t l_prime[HDCP_2_2_L_PRIME_LEN];
+} __packed;
+struct hdcp2_ske_send_eks {
- uint8_t msg_id;
- uint8_t e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN];
- uint8_t riv[HDCP_2_2_RIV_LEN];
+} __packed;
+struct hdcp2_rep_send_receiverid_list {
- uint8_t msg_id;
- uint8_t rx_info[HDCP_2_2_RXINFO_LEN];
- uint8_t seq_num_v[HDCP_2_2_SEQ_NUM_LEN];
- uint8_t v_prime[HDCP_2_2_LPRIME_HALF_LEN];
- uint8_t receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN];
+} __packed;
+struct hdcp2_rep_send_ack {
- uint8_t msg_id;
- uint8_t v[HDCP_2_2_LPRIME_HALF_LEN];
+} __packed;
+struct hdcp2_rep_stream_manage {
- uint8_t msg_id;
- uint8_t seq_num_m[HDCP_2_2_SEQ_NUM_LEN];
- __be16 k;
- struct hdcp2_streamid_type streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT];
+} __packed;
+struct hdcp2_rep_stream_ready {
- uint8_t msg_id;
- uint8_t m_prime[HDCP_2_2_MPRIME_LEN];
+} __packed;
+struct hdcp2_dp_errata_stream_type {
- uint8_t msg_id;
- uint8_t stream_type;
+} __packed;
Perhaps this has already been asked and answered, but do all of these need to be __packed? This is kind of the problem with adding a bunch of unused structures to a patch, it's hard to see what their usage is. In future, these should probably be introduced when they're being used.
Sean
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Thanks seanpaul for the reviews.
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 1:51 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [Intel-gfx] [PATCH v5 01/40] drm: hdcp2.2 authentication msg definitions
On Wed, Jun 27, 2018 at 02:09:50PM +0530, Ramalingam C wrote:
This patch defines the hdcp2.2 protocol messages for authentication.
v2: bit_fields are removed. Instead bitmasking used. [Tomas and Jani] prefix HDCP_2_2_ is added to the macros. [Tomas] v3: No Changes. v4: Style and spellings are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_hdcp.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+)
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 98e63d870139..3e963c5d04b2 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -38,4 +38,183 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43
+#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
These don't seem to be related to the patch?
+/* Protocol message definition for HDCP2.2 specification */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01
Why not HDCP_2_2 prefix?
Though they are introduced at HDCP2.2, this is classification of the streams. And Type 0 can be transmitted on HDCP1.4. So keeping it as generic name with no version mentioned.
+/* HDCP2.2 Msg IDs */ +#define HDCP_2_2_NULL_MSG 1 +#define HDCP_2_2_AKE_INIT 2 +#define HDCP_2_2_AKE_SEND_CERT 3 +#define HDCP_2_2_AKE_NO_STORED_KM 4 +#define HDCP_2_2_AKE_STORED_KM 5 +#define HDCP_2_2_AKE_SEND_HPRIME 7 +#define HDCP_2_2_AKE_SEND_PAIRING_INFO 8 +#define HDCP_2_2_LC_INIT 9 +#define HDCP_2_2_LC_SEND_LPRIME 10 +#define HDCP_2_2_SKE_SEND_EKS 11 +#define HDCP_2_2_REP_SEND_RECVID_LIST 12 +#define HDCP_2_2_REP_SEND_ACK 15 +#define HDCP_2_2_REP_STREAM_MANAGE 16 +#define HDCP_2_2_REP_STREAM_READY 17 +#define HDCP_2_2_ERRATA_DP_STREAM_TYPE 50
+#define HDCP_2_2_RTX_LEN 8 +#define HDCP_2_2_RRX_LEN 8
+#define HDCP_2_2_K_PUB_RX_MOD_N_LEN 128 +#define HDCP_2_2_K_PUB_RX_EXP_E_LEN 3 +#define HDCP_2_2_K_PUB_RX_LEN
(HDCP_2_2_K_PUB_RX_MOD_N_LEN + \
HDCP_2_2_K_PUB_RX_EXP_E_LEN)
+#define HDCP_2_2_DCP_LLC_SIG_LEN 384
+#define HDCP_2_2_E_KPUB_KM_LEN 128 +#define HDCP_2_2_E_KH_KM_M_LEN (16 + 16) +#define HDCP_2_2_H_PRIME_LEN 32 +#define HDCP_2_2_E_KH_KM_LEN 16 +#define HDCP_2_2_RN_LEN 8 +#define HDCP_2_2_L_PRIME_LEN 32 +#define HDCP_2_2_E_DKEY_KS_LEN 16 +#define HDCP_2_2_RIV_LEN 8 +#define HDCP_2_2_SEQ_NUM_LEN 3 +#define HDCP_2_2_LPRIME_HALF_LEN
(HDCP_2_2_L_PRIME_LEN / 2)
+#define HDCP_2_2_RECEIVER_ID_LEN DRM_HDCP_KSV_LEN +#define HDCP_2_2_MAX_DEVICE_COUNT 31 +#define HDCP_2_2_RECEIVER_IDS_MAX_LEN
(HDCP_2_2_RECEIVER_ID_LEN * \
HDCP_2_2_MAX_DEVICE_COUNT)
+#define HDCP_2_2_MPRIME_LEN 32
+/* Following Macros take a byte at a time for bit(s) masking */ +/*
- TODO: This has to be changed for DP MST, as multiple stream on
- same port is possible.
- For HDCP2.2 on HDMI and DP SST this value is always 1.
- */
+#define HDCP_2_2_MAX_CONTENT_STREAMS_CNT 1 +#define HDCP_2_2_TXCAP_MASK_LEN 2 +#define HDCP_2_2_RXCAPS_LEN 3 +#define HDCP_2_2_RX_REPEATER(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_HDCP_CAPABLE(x) ((x) & BIT(1)) +#define HDCP_2_2_RXINFO_LEN 2
+/* HDCP1.x compliant device in downstream */ +#define HDCP_2_2_HDCP1_DEVICE_CONNECTED(x) ((x) & BIT(0))
+/* HDCP2.0 Compliant repeater in downstream */ +#define HDCP_2_2_HDCP_2_0_REP_CONNECTED(x) ((x) & BIT(1)) +#define HDCP_2_2_MAX_CASCADE_EXCEEDED(x) ((x) & BIT(2)) +#define HDCP_2_2_MAX_DEVS_EXCEEDED(x) ((x) & BIT(3)) +#define HDCP_2_2_DEV_COUNT_LO(x) (((x) & (0xF << 4)) >> 4) +#define HDCP_2_2_DEV_COUNT_HI(x) ((x) & BIT(0)) +#define HDCP_2_2_DEPTH(x) (((x) & (0x7 << 1)) >> 1)
+struct hdcp2_cert_rx {
- uint8_t receiver_id[HDCP_2_2_RECEIVER_ID_LEN];
- uint8_t kpub_rx[HDCP_2_2_K_PUB_RX_LEN];
- uint8_t reserved[2];
- uint8_t dcp_signature[HDCP_2_2_DCP_LLC_SIG_LEN];
+} __packed;
+struct hdcp2_streamid_type {
- uint8_t stream_id;
- uint8_t stream_type;
+} __packed;
+/*
- The TxCaps field specified in the HDCP HDMI, DP specs
- This field is big endian as specified in the errata.
- */
+struct hdcp2_tx_caps {
- /* Transmitter must set this to 0x2 */
- uint8_t version;
- /* Reserved for HDCP and DP Spec. Read as Zero */
- uint8_t tx_cap_mask[HDCP_2_2_TXCAP_MASK_LEN];
+} __packed;
+/* Main structures for HDCP2.2 protocol communication */ struct +hdcp2_ake_init {
- uint8_t msg_id;
- uint8_t r_tx[HDCP_2_2_RTX_LEN];
- struct hdcp2_tx_caps tx_caps;
+} __packed;
+struct hdcp2_ake_send_cert {
- uint8_t msg_id;
- struct hdcp2_cert_rx cert_rx;
- uint8_t r_rx[HDCP_2_2_RRX_LEN];
- uint8_t rx_caps[HDCP_2_2_RXCAPS_LEN];
+} __packed;
+struct hdcp2_ake_no_stored_km {
- uint8_t msg_id;
- uint8_t e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN];
+} __packed;
+struct hdcp2_ake_stored_km {
- uint8_t msg_id;
- uint8_t e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN];
+} __packed;
+struct hdcp2_ake_send_hprime {
- uint8_t msg_id;
- uint8_t h_prime[HDCP_2_2_H_PRIME_LEN];
+} __packed;
+struct hdcp2_ake_send_pairing_info {
- uint8_t msg_id;
- uint8_t e_kh_km[HDCP_2_2_E_KH_KM_LEN];
+} __packed;
+struct hdcp2_lc_init {
- uint8_t msg_id;
- uint8_t r_n[HDCP_2_2_RN_LEN];
+} __packed;
+struct hdcp2_lc_send_lprime {
- uint8_t msg_id;
- uint8_t l_prime[HDCP_2_2_L_PRIME_LEN];
+} __packed;
+struct hdcp2_ske_send_eks {
- uint8_t msg_id;
- uint8_t e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN];
- uint8_t riv[HDCP_2_2_RIV_LEN];
+} __packed;
+struct hdcp2_rep_send_receiverid_list {
- uint8_t msg_id;
- uint8_t rx_info[HDCP_2_2_RXINFO_LEN];
- uint8_t seq_num_v[HDCP_2_2_SEQ_NUM_LEN];
- uint8_t v_prime[HDCP_2_2_LPRIME_HALF_LEN];
- uint8_t
receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN];
+} __packed;
+struct hdcp2_rep_send_ack {
- uint8_t msg_id;
- uint8_t v[HDCP_2_2_LPRIME_HALF_LEN];
+} __packed;
+struct hdcp2_rep_stream_manage {
- uint8_t msg_id;
- uint8_t seq_num_m[HDCP_2_2_SEQ_NUM_LEN];
- __be16 k;
- struct hdcp2_streamid_type
+streams[HDCP_2_2_MAX_CONTENT_STREAMS_CNT]; +} __packed;
+struct hdcp2_rep_stream_ready {
- uint8_t msg_id;
- uint8_t m_prime[HDCP_2_2_MPRIME_LEN];
+} __packed;
+struct hdcp2_dp_errata_stream_type {
- uint8_t msg_id;
- uint8_t stream_type;
+} __packed;
Perhaps this has already been asked and answered, but do all of these need to be __packed? This is kind of the problem with adding a bunch of unused structures to a patch, it's hard to see what their usage is. In future, these should probably be introduced when they're being used.
These are the HDCP2.2 message defined at HDCP2.2 spec. And they needs to be __packed just to have exact size mentioned by spec.
Like how we have HDCP1.4 and 2.2 macros defined as per the HDCP spec definitions, defined the HDCP2.2 messages together here.
Thanks, Ram.
Sean
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Sean Paul, Software Engineer, Google / Chromium OS
On Wed, Jul 11, 2018 at 05:57:08PM +0000, C, Ramalingam wrote:
Thanks seanpaul for the reviews.
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 1:51 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [Intel-gfx] [PATCH v5 01/40] drm: hdcp2.2 authentication msg definitions
On Wed, Jun 27, 2018 at 02:09:50PM +0530, Ramalingam C wrote:
This patch defines the hdcp2.2 protocol messages for authentication.
v2: bit_fields are removed. Instead bitmasking used. [Tomas and Jani] prefix HDCP_2_2_ is added to the macros. [Tomas] v3: No Changes. v4: Style and spellings are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_hdcp.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+)
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 98e63d870139..3e963c5d04b2 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -38,4 +38,183 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43
+#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
These don't seem to be related to the patch?
+/* Protocol message definition for HDCP2.2 specification */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01
Why not HDCP_2_2 prefix?
Though they are introduced at HDCP2.2, this is classification of the streams. And Type 0 can be transmitted on HDCP1.4. So keeping it as generic name with no version mentioned.
Ok, I guess it's the comment that was throwing me off. Perhaps you could improve it to:
/* * Protected video streams are classified into 2 types: * - Type0: Can be transmitted with HDCP 1.4+ * - Type1: Can be transmitted with HDCP 2.2+ */
/snip
+} __packed;
Perhaps this has already been asked and answered, but do all of these need to be __packed? This is kind of the problem with adding a bunch of unused structures to a patch, it's hard to see what their usage is. In future, these should probably be introduced when they're being used.
These are the HDCP2.2 message defined at HDCP2.2 spec. And they needs to be __packed just to have exact size mentioned by spec.
Like how we have HDCP1.4 and 2.2 macros defined as per the HDCP spec definitions, defined the HDCP2.2 messages together here.
Thanks for the explanation.
Sean
Thanks, Ram.
Sean
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Sean Paul, Software Engineer, Google / Chromium OS
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Thursday, July 12, 2018 12:38 AM To: C, Ramalingam ramalingam.c@intel.com Cc: Sean Paul seanpaul@chromium.org; intel-gfx@lists.freedesktop.org; dri- devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [Intel-gfx] [PATCH v5 01/40] drm: hdcp2.2 authentication msg definitions
On Wed, Jul 11, 2018 at 05:57:08PM +0000, C, Ramalingam wrote:
Thanks seanpaul for the reviews.
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 1:51 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [Intel-gfx] [PATCH v5 01/40] drm: hdcp2.2 authentication msg definitions
On Wed, Jun 27, 2018 at 02:09:50PM +0530, Ramalingam C wrote:
This patch defines the hdcp2.2 protocol messages for authentication.
v2: bit_fields are removed. Instead bitmasking used. [Tomas and Jani] prefix HDCP_2_2_ is added to the macros. [Tomas] v3: No Changes. v4: Style and spellings are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_hdcp.h | 179 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 179 insertions(+)
diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 98e63d870139..3e963c5d04b2 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -38,4 +38,183 @@ #define DRM_HDCP_DDC_BSTATUS 0x41 #define DRM_HDCP_DDC_KSV_FIFO 0x43
+#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
These don't seem to be related to the patch?
+/* Protocol message definition for HDCP2.2 specification */ +#define HDCP_STREAM_TYPE0 0x00 +#define HDCP_STREAM_TYPE1 0x01
Why not HDCP_2_2 prefix?
Though they are introduced at HDCP2.2, this is classification of the streams. And Type 0 can be transmitted on HDCP1.4. So keeping it as generic name with no version mentioned.
Ok, I guess it's the comment that was throwing me off. Perhaps you could improve it to:
/*
- Protected video streams are classified into 2 types:
- Type0: Can be transmitted with HDCP 1.4+
- Type1: Can be transmitted with HDCP 2.2+ */
/snip
Sure I will fix this.
Thanks, Ram.
+} __packed;
Perhaps this has already been asked and answered, but do all of these need to be __packed? This is kind of the problem with adding a bunch of unused structures to a patch, it's hard to see what their usage is. In future, these should probably be introduced when they're being
used.
These are the HDCP2.2 message defined at HDCP2.2 spec. And they needs to be __packed just to have exact size mentioned by spec.
Like how we have HDCP1.4 and 2.2 macros defined as per the HDCP spec definitions, defined the HDCP2.2 messages together here.
Thanks for the explanation.
Sean
Thanks, Ram.
Sean
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Sean Paul, Software Engineer, Google / Chromium OS
-- Sean Paul, Software Engineer, Google / Chromium OS
This patch adds HDCP register definitions for HDMI and DP HDCP adaptations.
HDMI specific HDCP2.2 register definitions are added into drm_hdcp.h, where as HDCP2.2 register offsets in DPCD offsets are defined at drm_dp_helper.h.
v2: bit_field definitions are replaced by macros. [Tomas and Jani] v3: No Changes. v4: Comments style and typos are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- include/drm/drm_dp_helper.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_hdcp.h | 30 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c01564991a9f..17e0889d6aaa 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -904,6 +904,57 @@ #define DP_AUX_HDCP_KSV_FIFO 0x6802C #define DP_AUX_HDCP_AINFO 0x6803B
+/* DP HDCP2.2 parameter offsets in DPCD address space */ +#define DP_HDCP_2_2_REG_RTX_OFFSET 0x69000 +#define DP_HDCP_2_2_REG_TXCAPS_OFFSET 0x69008 +#define DP_HDCP_2_2_REG_CERT_RX_OFFSET 0x6900B +#define DP_HDCP_2_2_REG_RRX_OFFSET 0x69215 +#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET 0x6921D +#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET 0x69220 +#define DP_HDCP_2_2_REG_EKH_KM_OFFSET 0x692A0 +#define DP_HDCP_2_2_REG_M_OFFSET 0x692B0 +#define DP_HDCP_2_2_REG_HPRIME_OFFSET 0x692C0 +#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET 0x692E0 +#define DP_HDCP_2_2_REG_RN_OFFSET 0x692F0 +#define DP_HDCP_2_2_REG_LPRIME_OFFSET 0x692F8 +#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET 0x69318 +#define DP_HDCP_2_2_REG_RIV_OFFSET 0x69328 +#define DP_HDCP_2_2_REG_RXINFO_OFFSET 0x69330 +#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET 0x69332 +#define DP_HDCP_2_2_REG_VPRIME_OFFSET 0x69335 +#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET 0x69345 +#define DP_HDCP_2_2_REG_V_OFFSET 0x693E0 +#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET 0x693F0 +#define DP_HDCP_2_2_REG_K_OFFSET 0x693F3 +#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5 +#define DP_HDCP_2_2_REG_MPRIME_OFFSET 0x69473 +#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET 0x69493 +#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 +#define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518 + +/* DP HDCP message start offsets in DPCD address space */ +#define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET +#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET +#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKPUB_KM_OFFSET +#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKH_KM_OFFSET +#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET DP_HDCP_2_2_REG_HPRIME_OFFSET +#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \ + DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET +#define DP_HDCP_2_2_LC_INIT_OFFSET DP_HDCP_2_2_REG_RN_OFFSET +#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET DP_HDCP_2_2_REG_LPRIME_OFFSET +#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET DP_HDCP_2_2_REG_EDKEY_KS_OFFSET +#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET DP_HDCP_2_2_REG_RXINFO_OFFSET +#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET DP_HDCP_2_2_REG_V_OFFSET +#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET +#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET DP_HDCP_2_2_REG_MPRIME_OFFSET + +#define HDCP_2_2_DP_RXSTATUS_LEN 1 +#define HDCP_2_2_DP_RXSTATUS_READY(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x) ((x) & BIT(1)) +#define HDCP_2_2_DP_RXSTATUS_PAIRING(x) ((x) & BIT(2)) +#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) +#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x) ((x) & BIT(4)) + /* DP 1.2 Sideband message defines */ /* peer device type - DP 1.2a Table 2-92 */ #define DP_PEER_DEVICE_NONE 0x0 diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 3e963c5d04b2..2fc6311dc060 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -217,4 +217,34 @@ struct hdcp2_dp_errata_stream_type { uint8_t stream_type; } __packed;
+/* HDCP2.2 TIMEOUTs in mSec */ +#define HDCP_2_2_CERT_TIMEOUT 100 +#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT 1000 +#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT 200 +#define HDCP_2_2_PAIRING_TIMEOUT 200 +#define HDCP_2_2_HDMI_LPRIME_TIMEOUT 20 +#define HDCP_2_2_DP_LPRIME_TIMEOUT 7 +#define HDCP_2_2_RECVID_LIST_TIMEOUT 3000 +#define HDCP_2_2_STREAM_READY_TIMEOUT 100 + +/* HDMI HDCP2.2 Register Offsets */ +#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 +#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 +#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 +#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 +#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0 + +#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) +#define HDCP_2_2_RXCAPS_VERSION_VAL 0x2 + +#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 +#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF +#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200 + +/* Below macros take a byte at a time and mask the bit(s) */ +#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 +#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) +#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) +#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) + #endif
On Wed, Jun 27, 2018 at 02:09:51PM +0530, Ramalingam C wrote:
This patch adds HDCP register definitions for HDMI and DP HDCP adaptations.
HDMI specific HDCP2.2 register definitions are added into drm_hdcp.h, where as HDCP2.2 register offsets in DPCD offsets are defined at drm_dp_helper.h.
v2: bit_field definitions are replaced by macros. [Tomas and Jani] v3: No Changes. v4: Comments style and typos are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_dp_helper.h | 51 +++++++++++++++++++++++++++++++++++++++++++++ include/drm/drm_hdcp.h | 30 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c01564991a9f..17e0889d6aaa 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -904,6 +904,57 @@ #define DP_AUX_HDCP_KSV_FIFO 0x6802C #define DP_AUX_HDCP_AINFO 0x6803B
+/* DP HDCP2.2 parameter offsets in DPCD address space */ +#define DP_HDCP_2_2_REG_RTX_OFFSET 0x69000 +#define DP_HDCP_2_2_REG_TXCAPS_OFFSET 0x69008 +#define DP_HDCP_2_2_REG_CERT_RX_OFFSET 0x6900B +#define DP_HDCP_2_2_REG_RRX_OFFSET 0x69215 +#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET 0x6921D +#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET 0x69220 +#define DP_HDCP_2_2_REG_EKH_KM_OFFSET 0x692A0 +#define DP_HDCP_2_2_REG_M_OFFSET 0x692B0 +#define DP_HDCP_2_2_REG_HPRIME_OFFSET 0x692C0 +#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET 0x692E0 +#define DP_HDCP_2_2_REG_RN_OFFSET 0x692F0 +#define DP_HDCP_2_2_REG_LPRIME_OFFSET 0x692F8 +#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET 0x69318 +#define DP_HDCP_2_2_REG_RIV_OFFSET 0x69328 +#define DP_HDCP_2_2_REG_RXINFO_OFFSET 0x69330 +#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET 0x69332 +#define DP_HDCP_2_2_REG_VPRIME_OFFSET 0x69335 +#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET 0x69345 +#define DP_HDCP_2_2_REG_V_OFFSET 0x693E0 +#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET 0x693F0 +#define DP_HDCP_2_2_REG_K_OFFSET 0x693F3 +#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5 +#define DP_HDCP_2_2_REG_MPRIME_OFFSET 0x69473 +#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET 0x69493 +#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 +#define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518
+/* DP HDCP message start offsets in DPCD address space */ +#define DP_HDCP_2_2_AKE_INIT_OFFSET DP_HDCP_2_2_REG_RTX_OFFSET +#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET DP_HDCP_2_2_REG_CERT_RX_OFFSET +#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKPUB_KM_OFFSET +#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET DP_HDCP_2_2_REG_EKH_KM_OFFSET +#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET DP_HDCP_2_2_REG_HPRIME_OFFSET +#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \
DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET
+#define DP_HDCP_2_2_LC_INIT_OFFSET DP_HDCP_2_2_REG_RN_OFFSET +#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET DP_HDCP_2_2_REG_LPRIME_OFFSET +#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET DP_HDCP_2_2_REG_EDKEY_KS_OFFSET +#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET DP_HDCP_2_2_REG_RXINFO_OFFSET +#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET DP_HDCP_2_2_REG_V_OFFSET +#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET +#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET DP_HDCP_2_2_REG_MPRIME_OFFSET
+#define HDCP_2_2_DP_RXSTATUS_LEN 1 +#define HDCP_2_2_DP_RXSTATUS_READY(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x) ((x) & BIT(1)) +#define HDCP_2_2_DP_RXSTATUS_PAIRING(x) ((x) & BIT(2)) +#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) +#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x) ((x) & BIT(4))
/* DP 1.2 Sideband message defines */ /* peer device type - DP 1.2a Table 2-92 */ #define DP_PEER_DEVICE_NONE 0x0 diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 3e963c5d04b2..2fc6311dc060 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -217,4 +217,34 @@ struct hdcp2_dp_errata_stream_type { uint8_t stream_type; } __packed;
+/* HDCP2.2 TIMEOUTs in mSec */
Minor nit: it's usually better to add _MS postfix to the var names so it's obvious at the point of use what unit the #define is in.
Otherwise,
Reviewed-by: Sean Paul seanpaul@chromium.org
+#define HDCP_2_2_CERT_TIMEOUT 100 +#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT 1000 +#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT 200 +#define HDCP_2_2_PAIRING_TIMEOUT 200 +#define HDCP_2_2_HDMI_LPRIME_TIMEOUT 20 +#define HDCP_2_2_DP_LPRIME_TIMEOUT 7 +#define HDCP_2_2_RECVID_LIST_TIMEOUT 3000 +#define HDCP_2_2_STREAM_READY_TIMEOUT 100
+/* HDMI HDCP2.2 Register Offsets */ +#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 +#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 +#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 +#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 +#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0
+#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) +#define HDCP_2_2_RXCAPS_VERSION_VAL 0x2
+#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 +#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF +#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200
+/* Below macros take a byte at a time and mask the bit(s) */ +#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 +#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) +#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) +#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3))
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 1:53 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [Intel-gfx] [PATCH v5 02/40] drm: HDMI and DP specific HDCP2.2 defines
On Wed, Jun 27, 2018 at 02:09:51PM +0530, Ramalingam C wrote:
This patch adds HDCP register definitions for HDMI and DP HDCP adaptations.
HDMI specific HDCP2.2 register definitions are added into drm_hdcp.h, where as HDCP2.2 register offsets in DPCD offsets are defined at drm_dp_helper.h.
v2: bit_field definitions are replaced by macros. [Tomas and Jani] v3: No Changes. v4: Comments style and typos are fixed [Uma] v5: Fix for macros.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
include/drm/drm_dp_helper.h | 51
+++++++++++++++++++++++++++++++++++++++++++++
include/drm/drm_hdcp.h | 30 ++++++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h index c01564991a9f..17e0889d6aaa 100644 --- a/include/drm/drm_dp_helper.h +++ b/include/drm/drm_dp_helper.h @@ -904,6 +904,57 @@ #define DP_AUX_HDCP_KSV_FIFO 0x6802C #define DP_AUX_HDCP_AINFO 0x6803B
+/* DP HDCP2.2 parameter offsets in DPCD address space */ +#define DP_HDCP_2_2_REG_RTX_OFFSET 0x69000 +#define DP_HDCP_2_2_REG_TXCAPS_OFFSET 0x69008 +#define DP_HDCP_2_2_REG_CERT_RX_OFFSET 0x6900B +#define DP_HDCP_2_2_REG_RRX_OFFSET 0x69215 +#define DP_HDCP_2_2_REG_RX_CAPS_OFFSET 0x6921D +#define DP_HDCP_2_2_REG_EKPUB_KM_OFFSET 0x69220 +#define DP_HDCP_2_2_REG_EKH_KM_OFFSET 0x692A0 +#define DP_HDCP_2_2_REG_M_OFFSET 0x692B0 +#define DP_HDCP_2_2_REG_HPRIME_OFFSET 0x692C0 +#define DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET 0x692E0 +#define DP_HDCP_2_2_REG_RN_OFFSET 0x692F0 +#define DP_HDCP_2_2_REG_LPRIME_OFFSET 0x692F8 +#define DP_HDCP_2_2_REG_EDKEY_KS_OFFSET 0x69318 +#define DP_HDCP_2_2_REG_RIV_OFFSET 0x69328 +#define DP_HDCP_2_2_REG_RXINFO_OFFSET 0x69330 +#define DP_HDCP_2_2_REG_SEQ_NUM_V_OFFSET 0x69332 +#define DP_HDCP_2_2_REG_VPRIME_OFFSET 0x69335 +#define DP_HDCP_2_2_REG_RECV_ID_LIST_OFFSET 0x69345 +#define DP_HDCP_2_2_REG_V_OFFSET 0x693E0 +#define DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET 0x693F0 +#define DP_HDCP_2_2_REG_K_OFFSET 0x693F3 +#define DP_HDCP_2_2_REG_STREAM_ID_TYPE_OFFSET 0x693F5 +#define DP_HDCP_2_2_REG_MPRIME_OFFSET 0x69473 +#define DP_HDCP_2_2_REG_RXSTATUS_OFFSET 0x69493 +#define DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET 0x69494 +#define DP_HDCP_2_2_REG_DBG_OFFSET 0x69518
+/* DP HDCP message start offsets in DPCD address space */ +#define DP_HDCP_2_2_AKE_INIT_OFFSET
DP_HDCP_2_2_REG_RTX_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_CERT_OFFSET
DP_HDCP_2_2_REG_CERT_RX_OFFSET
+#define DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET
DP_HDCP_2_2_REG_EKPUB_KM_OFFSET
+#define DP_HDCP_2_2_AKE_STORED_KM_OFFSET
DP_HDCP_2_2_REG_EKH_KM_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET
DP_HDCP_2_2_REG_HPRIME_OFFSET
+#define DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET \
DP_HDCP_2_2_REG_EKH_KM_RD_OFFSET
+#define DP_HDCP_2_2_LC_INIT_OFFSET
DP_HDCP_2_2_REG_RN_OFFSET
+#define DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET
DP_HDCP_2_2_REG_LPRIME_OFFSET
+#define DP_HDCP_2_2_SKE_SEND_EKS_OFFSET
DP_HDCP_2_2_REG_EDKEY_KS_OFFSET
+#define DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET
DP_HDCP_2_2_REG_RXINFO_OFFSET
+#define DP_HDCP_2_2_REP_SEND_ACK_OFFSET
DP_HDCP_2_2_REG_V_OFFSET
+#define DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET
DP_HDCP_2_2_REG_SEQ_NUM_M_OFFSET
+#define DP_HDCP_2_2_REP_STREAM_READY_OFFSET
DP_HDCP_2_2_REG_MPRIME_OFFSET
+#define HDCP_2_2_DP_RXSTATUS_LEN 1 +#define HDCP_2_2_DP_RXSTATUS_READY(x) ((x) & BIT(0)) +#define HDCP_2_2_DP_RXSTATUS_H_PRIME(x) ((x) & BIT(1)) +#define HDCP_2_2_DP_RXSTATUS_PAIRING(x) ((x) & BIT(2)) +#define HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3)) +#define HDCP_2_2_DP_RXSTATUS_LINK_FAILED(x) ((x) & BIT(4))
/* DP 1.2 Sideband message defines */ /* peer device type - DP 1.2a Table 2-92 */ #define DP_PEER_DEVICE_NONE 0x0 diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 3e963c5d04b2..2fc6311dc060 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -217,4 +217,34 @@ struct hdcp2_dp_errata_stream_type { uint8_t stream_type; } __packed;
+/* HDCP2.2 TIMEOUTs in mSec */
Minor nit: it's usually better to add _MS postfix to the var names so it's obvious at the point of use what unit the #define is in.
Otherwise,
Reviewed-by: Sean Paul seanpaul@chromium.org
Sure I will add _MS. Thanks for the R-b.
Thanks, Ram.
+#define HDCP_2_2_CERT_TIMEOUT 100 +#define HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT 1000 +#define HDCP_2_2_HPRIME_PAIRED_TIMEOUT 200 +#define HDCP_2_2_PAIRING_TIMEOUT 200 +#define HDCP_2_2_HDMI_LPRIME_TIMEOUT 20 +#define HDCP_2_2_DP_LPRIME_TIMEOUT 7 +#define HDCP_2_2_RECVID_LIST_TIMEOUT 3000 +#define HDCP_2_2_STREAM_READY_TIMEOUT 100
+/* HDMI HDCP2.2 Register Offsets */ +#define HDCP_2_2_HDMI_REG_VER_OFFSET 0x50 +#define HDCP_2_2_HDMI_REG_WR_MSG_OFFSET 0x60 +#define HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET 0x70 +#define HDCP_2_2_HDMI_REG_RD_MSG_OFFSET 0x80 +#define HDCP_2_2_HDMI_REG_DBG_OFFSET 0xC0
+#define HDCP_2_2_HDMI_SUPPORT_MASK BIT(2) +#define HDCP_2_2_RXCAPS_VERSION_VAL 0x2
+#define HDCP_2_2_RX_CAPS_VERSION_VAL 0x02 +#define HDCP_2_2_SEQ_NUM_MAX 0xFFFFFF +#define HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN 200
+/* Below macros take a byte at a time and mask the bit(s) */ +#define HDCP_2_2_HDMI_RXSTATUS_LEN 2 +#define HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(x) ((x) & 0x3) +#define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) +#define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3))
#endif
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- Sean Paul, Software Engineer, Google / Chromium OS
From: Tomas Winkler tomas.winkler@intel.com
Whitelist HDCP client for in kernel drm use
v2: Rebased. v3: No changes. v4: No changes. v5: No changes.
Signed-off-by: Tomas Winkler tomas.winkler@intel.com --- drivers/misc/mei/bus-fixup.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
diff --git a/drivers/misc/mei/bus-fixup.c b/drivers/misc/mei/bus-fixup.c index 0208c4b027c5..3df2a69fddfb 100644 --- a/drivers/misc/mei/bus-fixup.c +++ b/drivers/misc/mei/bus-fixup.c @@ -41,6 +41,9 @@ static const uuid_le mei_nfc_info_guid = MEI_UUID_NFC_INFO; #define MEI_UUID_MKHIF_FIX UUID_LE(0x55213584, 0x9a29, 0x4916, \ 0xba, 0xdf, 0xf, 0xb7, 0xed, 0x68, 0x2a, 0xeb)
+#define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, \ + 0xA5, 0x52, 0xD1, 0xC5, 0x4B, 0x62, 0x7F, 0x04) + #define MEI_UUID_ANY NULL_UUID_LE
/** @@ -72,6 +75,18 @@ static void blacklist(struct mei_cl_device *cldev) cldev->do_match = 0; }
+/** + * whitelist - forcefully whitelist client + * + * @cldev: me clients device + */ +static void whitelist(struct mei_cl_device *cldev) +{ + dev_dbg(&cldev->dev, "running hook %s\n", __func__); + + cldev->do_match = 1; +} + #define OSTYPE_LINUX 2 struct mei_os_ver { __le16 build; @@ -399,6 +414,7 @@ static struct mei_fixup { MEI_FIXUP(MEI_UUID_NFC_HCI, mei_nfc), MEI_FIXUP(MEI_UUID_WD, mei_wd), MEI_FIXUP(MEI_UUID_MKHIF_FIX, mei_mkhi_fix), + MEI_FIXUP(MEI_UUID_HDCP, whitelist), };
/**
Data structures and Enum for the I915-MEI_HDCP interface are defined at <linux/mei_hdcp.h>
v2: Rebased. v3: mei_cl_device is removed from mei_hdcp_data [Tomas] v4: Comment style and typo fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- include/linux/mei_hdcp.h | 100 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 include/linux/mei_hdcp.h
diff --git a/include/linux/mei_hdcp.h b/include/linux/mei_hdcp.h new file mode 100644 index 000000000000..f993e389d7cf --- /dev/null +++ b/include/linux/mei_hdcp.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright © 2017-2018 Intel Corporation + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of the copyright holders not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. The copyright holders make no representations + * about the suitability of this software for any purpose. It is provided "as + * is" without express or implied warranty. + * + * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE + * OF THIS SOFTWARE. + * + * Authors: + * Ramalingam C ramalingam.c@intel.com + */ + +#ifndef _LINUX_MEI_HDCP_H +#define _LINUX_MEI_HDCP_H + +#include <linux/mei_cl_bus.h> + +/* + * Enumeration of the physical DDI available on the platform + */ +enum hdcp_physical_port { + INVALID_PORT = 0x00, /* Not a valid port */ + + DDI_RANGE_BEGIN = 0x01, /* Beginning of the valid DDI port range */ + DDI_B = 0x01, /* Port DDI B */ + DDI_C = 0x02, /* Port DDI C */ + DDI_D = 0x03, /* Port DDI D */ + DDI_E = 0x04, /* Port DDI E */ + DDI_F = 0x05, /* Port DDI F */ + DDI_A = 0x07, /* Port DDI A */ + DDI_RANGE_END = DDI_A,/* End of the valid DDI port range */ +}; + +/* The types of HDCP 2.2 ports supported */ +enum hdcp_integrated_port_type { + HDCP_INVALID_TYPE = 0x00, + + /* HDCP 2.x ports that are integrated into Intel HW */ + INTEGRATED = 0x01, + + /* HDCP2.2 discrete wired Tx port with LSPCON (HDMI 2.0) solution */ + LSPCON = 0x02, + + /* HDCP2.2 discrete wired Tx port using the CPDP (DP 1.3) solution */ + CPDP = 0x03, +}; + +/* + * wired_protocol: Supported integrated wired HDCP protocol. + * Based on this value, Minor difference needed between wired specifications + * are handled. + */ +enum hdcp_protocol { + HDCP_PROTOCOL_INVALID, + HDCP_PROTOCOL_HDMI, + HDCP_PROTOCOL_DP +}; + +/* + * mei_hdcp_data: Input data to the mei_hdcp APIs. + */ +struct mei_hdcp_data { + enum hdcp_physical_port port; + enum hdcp_integrated_port_type port_type; + enum hdcp_protocol protocol; + + /* + * No of streams transmitted on a port. + * In case of HDMI & DP SST, single stream will be + * transmitted on a port. + */ + uint16_t k; + + /* + * 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. + */ + uint32_t seq_num_m; + + /* k(No of Streams per port) x structure of wired_streamid_type */ + struct hdcp2_streamid_type *streams; +}; + +#endif /* defined (_LINUX_MEI_HDCP_H) */
Considering significant number of HDCP specific variables, it will be clean to have separate struct for HDCP.
New structure called intel_hdcp is added within intel_connector.
v2: struct hdcp statically allocated. [Sean Paul] enable and disable function parameters are retained.[Sean Paul] v3: No Changes. v4: Commit msg is rephrased [Uma] v5: Comment for mutex definition.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_display.c | 7 +-- drivers/gpu/drm/i915/intel_drv.h | 15 ++++-- drivers/gpu/drm/i915/intel_hdcp.c | 94 ++++++++++++++++++++---------------- 3 files changed, 67 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d849ec17f5c..ef09bb89d2ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15856,9 +15856,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev) for_each_intel_connector_iter(connector, &conn_iter) { if (connector->modeset_retry_work.func) cancel_work_sync(&connector->modeset_retry_work); - if (connector->hdcp_shim) { - cancel_delayed_work_sync(&connector->hdcp_check_work); - cancel_work_sync(&connector->hdcp_prop_work); + if (connector->hdcp.hdcp_shim) { + cancel_delayed_work_sync( + &connector->hdcp.hdcp_check_work); + cancel_work_sync(&connector->hdcp.hdcp_prop_work); } } drm_connector_list_iter_end(&conn_iter); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 578346b8d7e2..eb480574a92e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -377,6 +377,15 @@ struct intel_hdcp_shim { bool *hdcp_capable); };
+struct intel_hdcp { + const struct intel_hdcp_shim *hdcp_shim; + /* Mutex for hdcp state of the connector */ + struct mutex hdcp_mutex; + uint64_t hdcp_value; + struct delayed_work hdcp_check_work; + struct work_struct hdcp_prop_work; +}; + struct intel_connector { struct drm_connector base; /* @@ -409,11 +418,7 @@ struct intel_connector { /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work;
- const struct intel_hdcp_shim *hdcp_shim; - struct mutex hdcp_mutex; - uint64_t hdcp_value; /* protected by hdcp_mutex */ - struct delayed_work hdcp_check_work; - struct work_struct hdcp_prop_work; + struct intel_hdcp hdcp; };
struct intel_digital_connector_state { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 0cc6a861bcf8..65bbe5874eee 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -626,6 +626,7 @@ struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector)
static int _intel_hdcp_disable(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port; @@ -641,7 +642,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector) return -ETIMEDOUT; }
- ret = connector->hdcp_shim->toggle_signalling(intel_dig_port, false); + ret = hdcp->hdcp_shim->toggle_signalling(intel_dig_port, false); if (ret) { DRM_ERROR("Failed to disable HDCP signalling\n"); return ret; @@ -653,6 +654,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
static int _intel_hdcp_enable(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; int i, ret, tries = 3;
@@ -678,7 +680,7 @@ static int _intel_hdcp_enable(struct intel_connector *connector) /* Incase of authentication failures, HDCP spec expects reauth. */ for (i = 0; i < tries; i++) { ret = intel_hdcp_auth(conn_to_dig_port(connector), - connector->hdcp_shim); + hdcp->hdcp_shim); if (!ret) return 0;
@@ -694,36 +696,42 @@ static int _intel_hdcp_enable(struct intel_connector *connector)
static void intel_hdcp_check_work(struct work_struct *work) { - struct intel_connector *connector = container_of(to_delayed_work(work), + struct intel_hdcp *hdcp = container_of(to_delayed_work(work), + struct intel_hdcp, + hdcp_check_work); + struct intel_connector *connector = container_of(hdcp, struct intel_connector, - hdcp_check_work); + hdcp); + if (!intel_hdcp_check_link(connector)) - schedule_delayed_work(&connector->hdcp_check_work, + schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS); }
static void intel_hdcp_prop_work(struct work_struct *work) { - struct intel_connector *connector = container_of(work, + struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp, + hdcp_prop_work); + struct intel_connector *connector = container_of(hdcp, struct intel_connector, - hdcp_prop_work); + hdcp); struct drm_device *dev = connector->base.dev; struct drm_connector_state *state;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL); - mutex_lock(&connector->hdcp_mutex); + mutex_lock(&hdcp->hdcp_mutex);
/* * This worker is only used to flip between ENABLED/DESIRED. Either of * those to UNDESIRED is handled by core. If hdcp_value == UNDESIRED, * we're running just after hdcp has been disabled, so just exit */ - if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { state = connector->base.state; - state->content_protection = connector->hdcp_value; + state->content_protection = hdcp->hdcp_value; }
- mutex_unlock(&connector->hdcp_mutex); + mutex_unlock(&hdcp->hdcp_mutex); drm_modeset_unlock(&dev->mode_config.connection_mutex); }
@@ -737,6 +745,7 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) int intel_hdcp_init(struct intel_connector *connector, const struct intel_hdcp_shim *hdcp_shim) { + struct intel_hdcp *hdcp = &connector->hdcp; int ret;
ret = drm_connector_attach_content_protection_property( @@ -744,51 +753,53 @@ int intel_hdcp_init(struct intel_connector *connector, if (ret) return ret;
- connector->hdcp_shim = hdcp_shim; - mutex_init(&connector->hdcp_mutex); - INIT_DELAYED_WORK(&connector->hdcp_check_work, intel_hdcp_check_work); - INIT_WORK(&connector->hdcp_prop_work, intel_hdcp_prop_work); + hdcp->hdcp_shim = hdcp_shim; + mutex_init(&hdcp->hdcp_mutex); + INIT_DELAYED_WORK(&hdcp->hdcp_check_work, intel_hdcp_check_work); + INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work); return 0; }
int intel_hdcp_enable(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; int ret;
- if (!connector->hdcp_shim) + if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex); + mutex_lock(&hdcp->hdcp_mutex);
ret = _intel_hdcp_enable(connector); if (ret) goto out;
- connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; - schedule_work(&connector->hdcp_prop_work); - schedule_delayed_work(&connector->hdcp_check_work, + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&hdcp->hdcp_prop_work); + schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS); out: - mutex_unlock(&connector->hdcp_mutex); + mutex_unlock(&hdcp->hdcp_mutex); return ret; }
int intel_hdcp_disable(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; int ret = 0;
- if (!connector->hdcp_shim) + if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex); + mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; + if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; ret = _intel_hdcp_disable(connector); }
- mutex_unlock(&connector->hdcp_mutex); - cancel_delayed_work_sync(&connector->hdcp_check_work); + mutex_unlock(&hdcp->hdcp_mutex); + cancel_delayed_work_sync(&hdcp->hdcp_check_work); return ret; }
@@ -828,17 +839,18 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, /* Implements Part 3 of the HDCP authorization procedure */ int intel_hdcp_check_link(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port; int ret = 0;
- if (!connector->hdcp_shim) + if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex); + mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + if (hdcp->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) goto out;
if (!(I915_READ(PORT_HDCP_STATUS(port)) & HDCP_STATUS_ENC)) { @@ -846,17 +858,17 @@ int intel_hdcp_check_link(struct intel_connector *connector) connector->base.name, connector->base.base.id, I915_READ(PORT_HDCP_STATUS(port))); ret = -ENXIO; - connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; - schedule_work(&connector->hdcp_prop_work); + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&hdcp->hdcp_prop_work); goto out; }
- if (connector->hdcp_shim->check_link(intel_dig_port)) { - if (connector->hdcp_value != + if (hdcp->hdcp_shim->check_link(intel_dig_port)) { + if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { - connector->hdcp_value = + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; - schedule_work(&connector->hdcp_prop_work); + schedule_work(&hdcp->hdcp_prop_work); } goto out; } @@ -867,20 +879,20 @@ int intel_hdcp_check_link(struct intel_connector *connector) ret = _intel_hdcp_disable(connector); if (ret) { DRM_ERROR("Failed to disable hdcp (%d)\n", ret); - connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; - schedule_work(&connector->hdcp_prop_work); + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&hdcp->hdcp_prop_work); goto out; }
ret = _intel_hdcp_enable(connector); if (ret) { DRM_ERROR("Failed to enable hdcp (%d)\n", ret); - connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; - schedule_work(&connector->hdcp_prop_work); + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED; + schedule_work(&hdcp->hdcp_prop_work); goto out; }
out: - mutex_unlock(&connector->hdcp_mutex); + mutex_unlock(&hdcp->hdcp_mutex); return ret; }
On Wed, Jun 27, 2018 at 02:09:54PM +0530, Ramalingam C wrote:
Considering significant number of HDCP specific variables, it will be clean to have separate struct for HDCP.
New structure called intel_hdcp is added within intel_connector.
v2: struct hdcp statically allocated. [Sean Paul] enable and disable function parameters are retained.[Sean Paul] v3: No Changes. v4: Commit msg is rephrased [Uma] v5: Comment for mutex definition.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_display.c | 7 +-- drivers/gpu/drm/i915/intel_drv.h | 15 ++++-- drivers/gpu/drm/i915/intel_hdcp.c | 94 ++++++++++++++++++++---------------- 3 files changed, 67 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d849ec17f5c..ef09bb89d2ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15856,9 +15856,10 @@ static void intel_hpd_poll_fini(struct drm_device *dev) for_each_intel_connector_iter(connector, &conn_iter) { if (connector->modeset_retry_work.func) cancel_work_sync(&connector->modeset_retry_work);
if (connector->hdcp_shim) {
cancel_delayed_work_sync(&connector->hdcp_check_work);
cancel_work_sync(&connector->hdcp_prop_work);
if (connector->hdcp.hdcp_shim) {
cancel_delayed_work_sync(
&connector->hdcp.hdcp_check_work);
} } drm_connector_list_iter_end(&conn_iter);cancel_work_sync(&connector->hdcp.hdcp_prop_work);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 578346b8d7e2..eb480574a92e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -377,6 +377,15 @@ struct intel_hdcp_shim { bool *hdcp_capable); };
+struct intel_hdcp {
- const struct intel_hdcp_shim *hdcp_shim;
- /* Mutex for hdcp state of the connector */
- struct mutex hdcp_mutex;
- uint64_t hdcp_value;
- struct delayed_work hdcp_check_work;
- struct work_struct hdcp_prop_work;
Now that they're in their own struct, you can probably drop the hdcp_* prefix from the struct members.
+};
struct intel_connector { struct drm_connector base; /* @@ -409,11 +418,7 @@ struct intel_connector { /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work;
- const struct intel_hdcp_shim *hdcp_shim;
- struct mutex hdcp_mutex;
- uint64_t hdcp_value; /* protected by hdcp_mutex */
- struct delayed_work hdcp_check_work;
- struct work_struct hdcp_prop_work;
- struct intel_hdcp hdcp;
};
struct intel_digital_connector_state { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 0cc6a861bcf8..65bbe5874eee 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -626,6 +626,7 @@ struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector)
static int _intel_hdcp_disable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port;
@@ -641,7 +642,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector) return -ETIMEDOUT; }
- ret = connector->hdcp_shim->toggle_signalling(intel_dig_port, false);
- ret = hdcp->hdcp_shim->toggle_signalling(intel_dig_port, false); if (ret) { DRM_ERROR("Failed to disable HDCP signalling\n"); return ret;
@@ -653,6 +654,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
static int _intel_hdcp_enable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; int i, ret, tries = 3;
@@ -678,7 +680,7 @@ static int _intel_hdcp_enable(struct intel_connector *connector) /* Incase of authentication failures, HDCP spec expects reauth. */ for (i = 0; i < tries; i++) { ret = intel_hdcp_auth(conn_to_dig_port(connector),
connector->hdcp_shim);
if (!ret) return 0;hdcp->hdcp_shim);
@@ -694,36 +696,42 @@ static int _intel_hdcp_enable(struct intel_connector *connector)
static void intel_hdcp_check_work(struct work_struct *work) {
- struct intel_connector *connector = container_of(to_delayed_work(work),
- struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
struct intel_hdcp,
hdcp_check_work);
- struct intel_connector *connector = container_of(hdcp, struct intel_connector,
hdcp_check_work);
hdcp);
Since you use this below, break this out into a static inline helper intel_hdcp_to_connector().
With those nits addressed,
Reviewed-by: Sean Paul seanpaul@chromium.org
- if (!intel_hdcp_check_link(connector))
schedule_delayed_work(&connector->hdcp_check_work,
schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS);
}
static void intel_hdcp_prop_work(struct work_struct *work) {
- struct intel_connector *connector = container_of(work,
- struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
hdcp_prop_work);
- struct intel_connector *connector = container_of(hdcp, struct intel_connector,
hdcp_prop_work);
hdcp);
struct drm_device *dev = connector->base.dev; struct drm_connector_state *state;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- mutex_lock(&connector->hdcp_mutex);
mutex_lock(&hdcp->hdcp_mutex);
/*
- This worker is only used to flip between ENABLED/DESIRED. Either of
- those to UNDESIRED is handled by core. If hdcp_value == UNDESIRED,
- we're running just after hdcp has been disabled, so just exit
*/
- if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { state = connector->base.state;
state->content_protection = connector->hdcp_value;
}state->content_protection = hdcp->hdcp_value;
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
@@ -737,6 +745,7 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) int intel_hdcp_init(struct intel_connector *connector, const struct intel_hdcp_shim *hdcp_shim) {
struct intel_hdcp *hdcp = &connector->hdcp; int ret;
ret = drm_connector_attach_content_protection_property(
@@ -744,51 +753,53 @@ int intel_hdcp_init(struct intel_connector *connector, if (ret) return ret;
- connector->hdcp_shim = hdcp_shim;
- mutex_init(&connector->hdcp_mutex);
- INIT_DELAYED_WORK(&connector->hdcp_check_work, intel_hdcp_check_work);
- INIT_WORK(&connector->hdcp_prop_work, intel_hdcp_prop_work);
- hdcp->hdcp_shim = hdcp_shim;
- mutex_init(&hdcp->hdcp_mutex);
- INIT_DELAYED_WORK(&hdcp->hdcp_check_work, intel_hdcp_check_work);
- INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work); return 0;
}
int intel_hdcp_enable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; int ret;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
mutex_lock(&hdcp->hdcp_mutex);
ret = _intel_hdcp_enable(connector); if (ret) goto out;
- connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&connector->hdcp_prop_work);
- schedule_delayed_work(&connector->hdcp_check_work,
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS);
out:
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); return ret;
}
int intel_hdcp_disable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; int ret = 0;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
- mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
- if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
ret = _intel_hdcp_disable(connector); }hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
- mutex_unlock(&connector->hdcp_mutex);
- cancel_delayed_work_sync(&connector->hdcp_check_work);
- mutex_unlock(&hdcp->hdcp_mutex);
- cancel_delayed_work_sync(&hdcp->hdcp_check_work); return ret;
}
@@ -828,17 +839,18 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, /* Implements Part 3 of the HDCP authorization procedure */ int intel_hdcp_check_link(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port; int ret = 0;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
- mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
if (hdcp->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) goto out;
if (!(I915_READ(PORT_HDCP_STATUS(port)) & HDCP_STATUS_ENC)) {
@@ -846,17 +858,17 @@ int intel_hdcp_check_link(struct intel_connector *connector) connector->base.name, connector->base.base.id, I915_READ(PORT_HDCP_STATUS(port))); ret = -ENXIO;
connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto out; }schedule_work(&hdcp->hdcp_prop_work);
- if (connector->hdcp_shim->check_link(intel_dig_port)) {
if (connector->hdcp_value !=
- if (hdcp->hdcp_shim->check_link(intel_dig_port)) {
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {if (hdcp->hdcp_value !=
connector->hdcp_value =
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
schedule_work(&connector->hdcp_prop_work);
} goto out; }schedule_work(&hdcp->hdcp_prop_work);
@@ -867,20 +879,20 @@ int intel_hdcp_check_link(struct intel_connector *connector) ret = _intel_hdcp_disable(connector); if (ret) { DRM_ERROR("Failed to disable hdcp (%d)\n", ret);
connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&hdcp->hdcp_prop_work);
goto out; }
ret = _intel_hdcp_enable(connector); if (ret) { DRM_ERROR("Failed to enable hdcp (%d)\n", ret);
connector->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto out; }schedule_work(&hdcp->hdcp_prop_work);
out:
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); return ret;
}
2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 2:00 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [PATCH v5 05/40] drm/i915: wrapping all hdcp var into intel_hdcp
On Wed, Jun 27, 2018 at 02:09:54PM +0530, Ramalingam C wrote:
Considering significant number of HDCP specific variables, it will be clean to have separate struct for HDCP.
New structure called intel_hdcp is added within intel_connector.
v2: struct hdcp statically allocated. [Sean Paul] enable and disable function parameters are retained.[Sean Paul] v3: No Changes. v4: Commit msg is rephrased [Uma] v5: Comment for mutex definition.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_display.c | 7 +-- drivers/gpu/drm/i915/intel_drv.h | 15 ++++-- drivers/gpu/drm/i915/intel_hdcp.c | 94 ++++++++++++++++++++--------------
--
3 files changed, 67 insertions(+), 49 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3d849ec17f5c..ef09bb89d2ca 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -15856,9 +15856,10 @@ static void intel_hpd_poll_fini(struct drm_device
*dev)
for_each_intel_connector_iter(connector, &conn_iter) { if (connector->modeset_retry_work.func) cancel_work_sync(&connector->modeset_retry_work);
if (connector->hdcp_shim) {
cancel_delayed_work_sync(&connector-
hdcp_check_work);
cancel_work_sync(&connector->hdcp_prop_work);
if (connector->hdcp.hdcp_shim) {
cancel_delayed_work_sync(
&connector->hdcp.hdcp_check_work);
cancel_work_sync(&connector-
hdcp.hdcp_prop_work); } } drm_connector_list_iter_end(&conn_iter); diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 578346b8d7e2..eb480574a92e 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -377,6 +377,15 @@ struct intel_hdcp_shim { bool *hdcp_capable); };
+struct intel_hdcp {
- const struct intel_hdcp_shim *hdcp_shim;
- /* Mutex for hdcp state of the connector */
- struct mutex hdcp_mutex;
- uint64_t hdcp_value;
- struct delayed_work hdcp_check_work;
- struct work_struct hdcp_prop_work;
Now that they're in their own struct, you can probably drop the hdcp_* prefix from the struct members.
Sure I will do that.
+};
struct intel_connector { struct drm_connector base; /* @@ -409,11 +418,7 @@ struct intel_connector { /* Work struct to schedule a uevent on link train failure */ struct work_struct modeset_retry_work;
- const struct intel_hdcp_shim *hdcp_shim;
- struct mutex hdcp_mutex;
- uint64_t hdcp_value; /* protected by hdcp_mutex */
- struct delayed_work hdcp_check_work;
- struct work_struct hdcp_prop_work;
- struct intel_hdcp hdcp;
};
struct intel_digital_connector_state { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 0cc6a861bcf8..65bbe5874eee 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -626,6 +626,7 @@ struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector)
static int _intel_hdcp_disable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port; @@ -641,7 +642,7 @@
static int _intel_hdcp_disable(struct intel_connector *connector) return -ETIMEDOUT; }
- ret = connector->hdcp_shim->toggle_signalling(intel_dig_port, false);
- ret = hdcp->hdcp_shim->toggle_signalling(intel_dig_port, false); if (ret) { DRM_ERROR("Failed to disable HDCP signalling\n"); return ret;
@@ -653,6 +654,7 @@ static int _intel_hdcp_disable(struct intel_connector *connector)
static int _intel_hdcp_enable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; int i, ret, tries = 3;
@@ -678,7 +680,7 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
/* Incase of authentication failures, HDCP spec expects reauth. */ for (i = 0; i < tries; i++) { ret = intel_hdcp_auth(conn_to_dig_port(connector),
connector->hdcp_shim);
if (!ret) return 0;hdcp->hdcp_shim);
@@ -694,36 +696,42 @@ static int _intel_hdcp_enable(struct intel_connector *connector)
static void intel_hdcp_check_work(struct work_struct *work) {
- struct intel_connector *connector =
container_of(to_delayed_work(work),
- struct intel_hdcp *hdcp = container_of(to_delayed_work(work),
struct intel_hdcp,
hdcp_check_work);
- struct intel_connector *connector = container_of(hdcp, struct
intel_connector,
hdcp_check_work);
hdcp);
Since you use this below, break this out into a static inline helper intel_hdcp_to_connector().
Sure.
With those nits addressed,
Reviewed-by: Sean Paul seanpaul@chromium.org
Thanks for the R-b.
Ram.
- if (!intel_hdcp_check_link(connector))
schedule_delayed_work(&connector->hdcp_check_work,
schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS);
}
static void intel_hdcp_prop_work(struct work_struct *work) {
- struct intel_connector *connector = container_of(work,
- struct intel_hdcp *hdcp = container_of(work, struct intel_hdcp,
hdcp_prop_work);
- struct intel_connector *connector = container_of(hdcp, struct
intel_connector,
hdcp_prop_work);
hdcp);
struct drm_device *dev = connector->base.dev; struct drm_connector_state *state;
drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
- mutex_lock(&connector->hdcp_mutex);
mutex_lock(&hdcp->hdcp_mutex);
/*
- This worker is only used to flip between ENABLED/DESIRED. Either of
- those to UNDESIRED is handled by core. If hdcp_value ==
UNDESIRED,
* we're running just after hdcp has been disabled, so just exit */
- if (connector->hdcp_value !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
- if (hdcp->hdcp_value !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
state = connector->base.state;
state->content_protection = connector->hdcp_value;
}state->content_protection = hdcp->hdcp_value;
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
@@ -737,6 +745,7 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) int intel_hdcp_init(struct intel_connector
*connector,
const struct intel_hdcp_shim *hdcp_shim) {
struct intel_hdcp *hdcp = &connector->hdcp; int ret;
ret = drm_connector_attach_content_protection_property(
@@ -744,51 +753,53 @@ int intel_hdcp_init(struct intel_connector
*connector,
if (ret) return ret;
- connector->hdcp_shim = hdcp_shim;
- mutex_init(&connector->hdcp_mutex);
- INIT_DELAYED_WORK(&connector->hdcp_check_work,
intel_hdcp_check_work);
- INIT_WORK(&connector->hdcp_prop_work, intel_hdcp_prop_work);
- hdcp->hdcp_shim = hdcp_shim;
- mutex_init(&hdcp->hdcp_mutex);
- INIT_DELAYED_WORK(&hdcp->hdcp_check_work,
intel_hdcp_check_work);
- INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work); return 0;
}
int intel_hdcp_enable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; int ret;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
mutex_lock(&hdcp->hdcp_mutex);
ret = _intel_hdcp_enable(connector); if (ret) goto out;
- connector->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&connector->hdcp_prop_work);
- schedule_delayed_work(&connector->hdcp_check_work,
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work, DRM_HDCP_CHECK_PERIOD_MS);
out:
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); return ret;
}
int intel_hdcp_disable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; int ret = 0;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
- mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
connector->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
- if (hdcp->hdcp_value !=
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
hdcp->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ret = _intel_hdcp_disable(connector);
}
- mutex_unlock(&connector->hdcp_mutex);
- cancel_delayed_work_sync(&connector->hdcp_check_work);
- mutex_unlock(&hdcp->hdcp_mutex);
- cancel_delayed_work_sync(&hdcp->hdcp_check_work); return ret;
}
@@ -828,17 +839,18 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, /* Implements Part 3 of the HDCP authorization procedure */ int intel_hdcp_check_link(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); enum port port = intel_dig_port->base.port; int ret = 0;
- if (!connector->hdcp_shim)
- if (!hdcp->hdcp_shim) return -ENOENT;
- mutex_lock(&connector->hdcp_mutex);
- mutex_lock(&hdcp->hdcp_mutex);
- if (connector->hdcp_value ==
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
- if (hdcp->hdcp_value ==
DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
goto out;
if (!(I915_READ(PORT_HDCP_STATUS(port)) & HDCP_STATUS_ENC)) {
@@
-846,17 +858,17 @@ int intel_hdcp_check_link(struct intel_connector
*connector)
connector->base.name, connector->base.base.id, I915_READ(PORT_HDCP_STATUS(port))); ret = -ENXIO;
connector->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto out; }schedule_work(&hdcp->hdcp_prop_work);
- if (connector->hdcp_shim->check_link(intel_dig_port)) {
if (connector->hdcp_value !=
- if (hdcp->hdcp_shim->check_link(intel_dig_port)) {
DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {if (hdcp->hdcp_value !=
connector->hdcp_value =
hdcp->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_ENABLED;
schedule_work(&connector->hdcp_prop_work);
} goto out; }schedule_work(&hdcp->hdcp_prop_work);
@@ -867,20 +879,20 @@ int intel_hdcp_check_link(struct intel_connector
*connector)
ret = _intel_hdcp_disable(connector); if (ret) { DRM_ERROR("Failed to disable hdcp (%d)\n", ret);
connector->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&hdcp->hdcp_prop_work);
goto out; }
ret = _intel_hdcp_enable(connector); if (ret) { DRM_ERROR("Failed to enable hdcp (%d)\n", ret);
connector->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
schedule_work(&connector->hdcp_prop_work);
hdcp->hdcp_value =
DRM_MODE_CONTENT_PROTECTION_DESIRED;
goto out; }schedule_work(&hdcp->hdcp_prop_work);
out:
- mutex_unlock(&connector->hdcp_mutex);
- mutex_unlock(&hdcp->hdcp_mutex); return ret;
}
2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-- Sean Paul, Software Engineer, Google / Chromium OS
For upcoming implementation of HDCP2.2 in I915, important variable required for HDCP2.2 are defined.
HDCP_shim is extended to support encoder specific HDCP2.2 flows.
v2: 1.4 shim is extended to support hdcp2.2. [Sean Paul] platform's/panel's hdcp ver capability is removed. [Sean Paul] mei references in i915_private are moved to later patches. [Chris Wilson] v3: mei_cl_device ref is moved into intel_hdcp v4: Extra * in comment is removed [Uma] v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eb480574a92e..b615ea4a44c3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/hdmi.h> #include <linux/sched/clock.h> +#include <linux/mei_hdcp.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include <drm/drm_crtc.h> @@ -375,6 +376,32 @@ struct intel_hdcp_shim { /* Detects panel's hdcp capability. This is optional for HDMI. */ int (*hdcp_capable)(struct intel_digital_port *intel_dig_port, bool *hdcp_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, + uint8_t 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 Chiper for En/De-Cryption. Not applicable for HDMI. + */ + int (*config_stream_type)(struct intel_digital_port *intel_dig_port, + void *buf, size_t size); + + /* HDCP2.2 Link Integrity Check */ + int (*check_2_2_link)(struct intel_digital_port *intel_dig_port); + + /* Detects whether Panel is HDCP2.2 capable */ + int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port, + bool *capable); + + /* Detects the HDCP protocol(DP/HDMI) required on the port */ + enum hdcp_protocol (*hdcp_protocol)(void); };
struct intel_hdcp { @@ -384,6 +411,40 @@ struct intel_hdcp { uint64_t hdcp_value; struct delayed_work hdcp_check_work; struct work_struct hdcp_prop_work; + + /* HDCP2.2 related definitions */ + bool hdcp2_supported; + + /* + * Content Stream Type defined by content owner. TYPE0(0x0) content can + * flow in the link protected by HDCP2.2 or HDCP1.4, where as TYPE1(0x1) + * content can flow only through a link protected by HDCP2.2. + */ + u8 content_type; + + 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. + */ + uint32_t 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. + */ + uint32_t seq_num_m; + + /* mei interface related information */ + struct mei_cl_device *cldev; + struct mei_hdcp_data mei_data; + + struct delayed_work hdcp2_check_work; };
struct intel_connector {
On Wed, Jun 27, 2018 at 02:09:55PM +0530, Ramalingam C wrote:
For upcoming implementation of HDCP2.2 in I915, important variable required for HDCP2.2 are defined.
Please just introduce them when you use them. I can't provide useful review on this patch unless I can see how the variables are used. This will also reduce the series size, which is an added bonus for reviewers :-)
Sean
HDCP_shim is extended to support encoder specific HDCP2.2 flows.
v2: 1.4 shim is extended to support hdcp2.2. [Sean Paul] platform's/panel's hdcp ver capability is removed. [Sean Paul] mei references in i915_private are moved to later patches. [Chris Wilson] v3: mei_cl_device ref is moved into intel_hdcp v4: Extra * in comment is removed [Uma] v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_drv.h | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eb480574a92e..b615ea4a44c3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/hdmi.h> #include <linux/sched/clock.h> +#include <linux/mei_hdcp.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include <drm/drm_crtc.h> @@ -375,6 +376,32 @@ struct intel_hdcp_shim { /* Detects panel's hdcp capability. This is optional for HDMI. */ int (*hdcp_capable)(struct intel_digital_port *intel_dig_port, bool *hdcp_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,
uint8_t 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 Chiper for En/De-Cryption. Not applicable for HDMI.
*/
- int (*config_stream_type)(struct intel_digital_port *intel_dig_port,
void *buf, size_t size);
- /* HDCP2.2 Link Integrity Check */
- int (*check_2_2_link)(struct intel_digital_port *intel_dig_port);
- /* Detects whether Panel is HDCP2.2 capable */
- int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port,
bool *capable);
- /* Detects the HDCP protocol(DP/HDMI) required on the port */
- enum hdcp_protocol (*hdcp_protocol)(void);
};
struct intel_hdcp { @@ -384,6 +411,40 @@ struct intel_hdcp { uint64_t hdcp_value; struct delayed_work hdcp_check_work; struct work_struct hdcp_prop_work;
- /* HDCP2.2 related definitions */
- bool hdcp2_supported;
- /*
* Content Stream Type defined by content owner. TYPE0(0x0) content can
* flow in the link protected by HDCP2.2 or HDCP1.4, where as TYPE1(0x1)
* content can flow only through a link protected by HDCP2.2.
*/
- u8 content_type;
- 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.
*/
- uint32_t 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.
*/
- uint32_t seq_num_m;
- /* mei interface related information */
- struct mei_cl_device *cldev;
- struct mei_hdcp_data mei_data;
- struct delayed_work hdcp2_check_work;
};
struct intel_connector {
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Tuesday 10 July 2018 02:01 AM, Sean Paul wrote:
On Wed, Jun 27, 2018 at 02:09:55PM +0530, Ramalingam C wrote:
For upcoming implementation of HDCP2.2 in I915, important variable required for HDCP2.2 are defined.
Please just introduce them when you use them. I can't provide useful review on this patch unless I can see how the variables are used. This will also reduce the series size, which is an added bonus for reviewers :-)
Squashed these change into the subsequent patches.
Ram.
Sean
HDCP_shim is extended to support encoder specific HDCP2.2 flows.
v2: 1.4 shim is extended to support hdcp2.2. [Sean Paul] platform's/panel's hdcp ver capability is removed. [Sean Paul] mei references in i915_private are moved to later patches. [Chris Wilson] v3: mei_cl_device ref is moved into intel_hdcp v4: Extra * in comment is removed [Uma] v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_drv.h | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index eb480574a92e..b615ea4a44c3 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -29,6 +29,7 @@ #include <linux/i2c.h> #include <linux/hdmi.h> #include <linux/sched/clock.h> +#include <linux/mei_hdcp.h> #include <drm/i915_drm.h> #include "i915_drv.h" #include <drm/drm_crtc.h> @@ -375,6 +376,32 @@ struct intel_hdcp_shim { /* Detects panel's hdcp capability. This is optional for HDMI. */ int (*hdcp_capable)(struct intel_digital_port *intel_dig_port, bool *hdcp_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,
uint8_t 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 Chiper for En/De-Cryption. Not applicable for HDMI.
*/
int (*config_stream_type)(struct intel_digital_port *intel_dig_port,
void *buf, size_t size);
/* HDCP2.2 Link Integrity Check */
int (*check_2_2_link)(struct intel_digital_port *intel_dig_port);
/* Detects whether Panel is HDCP2.2 capable */
int (*hdcp_2_2_capable)(struct intel_digital_port *intel_dig_port,
bool *capable);
/* Detects the HDCP protocol(DP/HDMI) required on the port */
enum hdcp_protocol (*hdcp_protocol)(void); };
struct intel_hdcp {
@@ -384,6 +411,40 @@ struct intel_hdcp { uint64_t hdcp_value; struct delayed_work hdcp_check_work; struct work_struct hdcp_prop_work;
/* HDCP2.2 related definitions */
bool hdcp2_supported;
/*
* Content Stream Type defined by content owner. TYPE0(0x0) content can
* flow in the link protected by HDCP2.2 or HDCP1.4, where as TYPE1(0x1)
* content can flow only through a link protected by HDCP2.2.
*/
u8 content_type;
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.
*/
uint32_t 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.
*/
uint32_t seq_num_m;
/* mei interface related information */
struct mei_cl_device *cldev;
struct mei_hdcp_data mei_data;
struct delayed_work hdcp2_check_work; };
struct intel_connector {
-- 2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Intel HDCP2.2 registers are defined with addr offsets and bit details.
v2: Replaced the arith calc with _PICK [Sean Paul] v3: No changes. v4: %s/HDCP2_CTR_DDI/HDCP2_CTL_DDI [Uma] v5: Added parentheses for the parameters of macro.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index caad19f5f557..822fee56931e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8697,6 +8697,38 @@ enum skl_power_gate { #define HDCP_STATUS_CIPHER BIT(16) #define HDCP_STATUS_FRAME_CNT(x) (((x) >> 8) & 0xff)
+/* HDCP2.2 Registers */ +#define _PORTA_HDCP2_BASE 0x66800 +#define _PORTB_HDCP2_BASE 0x66500 +#define _PORTC_HDCP2_BASE 0x66600 +#define _PORTD_HDCP2_BASE 0x66700 +#define _PORTE_HDCP2_BASE 0x66A00 +#define _PORTF_HDCP2_BASE 0x66900 +#define _PORT_HDCP2_BASE(port, x) _MMIO(_PICK((port), \ + _PORTA_HDCP2_BASE, \ + _PORTB_HDCP2_BASE, \ + _PORTC_HDCP2_BASE, \ + _PORTD_HDCP2_BASE, \ + _PORTE_HDCP2_BASE, \ + _PORTF_HDCP2_BASE) + (x)) + +#define HDCP2_AUTH_DDI(port) _PORT_HDCP2_BASE(port, 0x98) +#define AUTH_LINK_AUTHENTICATED BIT(31) +#define AUTH_LINK_TYPE BIT(30) +#define AUTH_FORCE_CLR_INPUTCTR BIT(19) +#define AUTH_CLR_KEYS BIT(18) + +#define HDCP2_CTL_DDI(port) _PORT_HDCP2_BASE(port, 0xB0) +#define CTL_LINK_ENCRYPTION_REQ BIT(31) + +#define HDCP2_STATUS_DDI(port) _PORT_HDCP2_BASE(port, 0xB4) +#define STREAM_ENCRYPTION_STATUS_A BIT(31) +#define STREAM_ENCRYPTION_STATUS_B BIT(30) +#define STREAM_ENCRYPTION_STATUS_C BIT(29) +#define LINK_TYPE_STATUS BIT(22) +#define LINK_AUTH_STATUS BIT(21) +#define LINK_ENCRYPTION_STATUS BIT(20) + /* Per-pipe DDI Function Control */ #define _TRANS_DDI_FUNC_CTL_A 0x60400 #define _TRANS_DDI_FUNC_CTL_B 0x61400
On Wed, Jun 27, 2018 at 02:09:56PM +0530, Ramalingam C wrote:
Intel HDCP2.2 registers are defined with addr offsets and bit details.
v2: Replaced the arith calc with _PICK [Sean Paul] v3: No changes. v4: %s/HDCP2_CTR_DDI/HDCP2_CTL_DDI [Uma] v5: Added parentheses for the parameters of macro.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
Reviewed-by: Sean Paul seanpaul@chromium.org
drivers/gpu/drm/i915/i915_reg.h | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index caad19f5f557..822fee56931e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -8697,6 +8697,38 @@ enum skl_power_gate { #define HDCP_STATUS_CIPHER BIT(16) #define HDCP_STATUS_FRAME_CNT(x) (((x) >> 8) & 0xff)
+/* HDCP2.2 Registers */ +#define _PORTA_HDCP2_BASE 0x66800 +#define _PORTB_HDCP2_BASE 0x66500 +#define _PORTC_HDCP2_BASE 0x66600 +#define _PORTD_HDCP2_BASE 0x66700 +#define _PORTE_HDCP2_BASE 0x66A00 +#define _PORTF_HDCP2_BASE 0x66900 +#define _PORT_HDCP2_BASE(port, x) _MMIO(_PICK((port), \
_PORTA_HDCP2_BASE, \
_PORTB_HDCP2_BASE, \
_PORTC_HDCP2_BASE, \
_PORTD_HDCP2_BASE, \
_PORTE_HDCP2_BASE, \
_PORTF_HDCP2_BASE) + (x))
+#define HDCP2_AUTH_DDI(port) _PORT_HDCP2_BASE(port, 0x98) +#define AUTH_LINK_AUTHENTICATED BIT(31) +#define AUTH_LINK_TYPE BIT(30) +#define AUTH_FORCE_CLR_INPUTCTR BIT(19) +#define AUTH_CLR_KEYS BIT(18)
+#define HDCP2_CTL_DDI(port) _PORT_HDCP2_BASE(port, 0xB0) +#define CTL_LINK_ENCRYPTION_REQ BIT(31)
+#define HDCP2_STATUS_DDI(port) _PORT_HDCP2_BASE(port, 0xB4) +#define STREAM_ENCRYPTION_STATUS_A BIT(31) +#define STREAM_ENCRYPTION_STATUS_B BIT(30) +#define STREAM_ENCRYPTION_STATUS_C BIT(29) +#define LINK_TYPE_STATUS BIT(22) +#define LINK_AUTH_STATUS BIT(21) +#define LINK_ENCRYPTION_STATUS BIT(20)
/* Per-pipe DDI Function Control */ #define _TRANS_DDI_FUNC_CTL_A 0x60400
#define _TRANS_DDI_FUNC_CTL_B 0x61400
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Initialize HDCP2.2 support. This includes the mei interface initialization along with required component registration.
v2: mei interface handle is protected with mutex. [Chris Wilson] v3: Notifiers are used for the mei interface state. v4: Poll for mei client device state Error msg for out of mem [Uma] Inline req for init function removed [Uma] v5: Rebase as Part of reordering. Component is used for the I915 and MEI_HDCP interface [Daniel]
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_dp.c | 3 +- drivers/gpu/drm/i915/intel_drv.h | 5 +- drivers/gpu/drm/i915/intel_hdcp.c | 204 +++++++++++++++++++++++++++++++++++++- drivers/gpu/drm/i915/intel_hdmi.c | 2 +- include/drm/i915_component.h | 88 ++++++++++++++++ 6 files changed, 298 insertions(+), 6 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 6f08ab310118..0e6fe140dc63 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2142,6 +2142,8 @@ struct drm_i915_private {
struct i915_pmu pmu;
+ struct i915_hdcp_component *hdcp_comp; + /* * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch * will be rejected. Instead look for a better place. diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c1b2f00f324b..6bcc52766ea3 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6404,7 +6404,8 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port, intel_dp_add_properties(intel_dp, connector);
if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) { - int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim); + int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim, + false); if (ret) DRM_DEBUG_KMS("HDCP init failed, skipping.\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b615ea4a44c3..2eeb82b04953 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -441,9 +441,7 @@ struct intel_hdcp { uint32_t seq_num_m;
/* mei interface related information */ - struct mei_cl_device *cldev; struct mei_hdcp_data mei_data; - struct delayed_work hdcp2_check_work; };
@@ -1962,7 +1960,8 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, struct drm_connector_state *old_state, struct drm_connector_state *new_state); int intel_hdcp_init(struct intel_connector *connector, - const struct intel_hdcp_shim *hdcp_shim); + const struct intel_hdcp_shim *hdcp_shim, + bool hdcp2_supported); int intel_hdcp_enable(struct intel_connector *connector); int intel_hdcp_disable(struct intel_connector *connector); int intel_hdcp_check_link(struct intel_connector *connector); diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 65bbe5874eee..769560591aa8 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -8,13 +8,19 @@
#include <drm/drmP.h> #include <drm/drm_hdcp.h> +#include <drm/i915_component.h> #include <linux/i2c.h> #include <linux/random.h> +#include <linux/component.h>
#include "intel_drv.h" #include "i915_reg.h"
#define KEY_LOAD_TRIES 5 +#define GET_MEI_DDI_INDEX(port) (((port) == PORT_A) ? DDI_A : \ + (enum hdcp_physical_port)(port)) + +static int intel_hdcp2_init(struct intel_connector *connector);
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) @@ -743,11 +749,15 @@ bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port) }
int intel_hdcp_init(struct intel_connector *connector, - const struct intel_hdcp_shim *hdcp_shim) + const struct intel_hdcp_shim *hdcp_shim, + bool hdcp2_supported) { struct intel_hdcp *hdcp = &connector->hdcp; int ret;
+ if (!hdcp_shim) + return -EINVAL; + ret = drm_connector_attach_content_protection_property( &connector->base); if (ret) @@ -757,6 +767,10 @@ int intel_hdcp_init(struct intel_connector *connector, mutex_init(&hdcp->hdcp_mutex); INIT_DELAYED_WORK(&hdcp->hdcp_check_work, intel_hdcp_check_work); INIT_WORK(&hdcp->hdcp_prop_work, intel_hdcp_prop_work); + + if (hdcp2_supported) + intel_hdcp2_init(connector); + return 0; }
@@ -896,3 +910,191 @@ int intel_hdcp_check_link(struct intel_connector *connector) mutex_unlock(&hdcp->hdcp_mutex); return ret; } + +static int i915_hdcp_component_master_bind(struct device *dev) +{ + struct drm_i915_private *dev_priv = kdev_to_i915(dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + mutex_lock(&comp->mutex); + ret = component_bind_all(dev, comp); + if (ret < 0) + return ret; + + /* + * Atm, we don't support dynamic unbinding initiated by the child + * component, so pin its containing module until we unbind. + */ + if (!try_module_get(comp->ops->owner)) { + ret = -ENODEV; + goto out_unbind; + } + + mutex_unlock(&comp->mutex); + return 0; + +out_unbind: + component_unbind_all(dev, comp); + mutex_unlock(&comp->mutex); + + return ret; +} + +static void i915_hdcp_component_master_unbind(struct device *dev) +{ + struct drm_i915_private *dev_priv = kdev_to_i915(dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + + mutex_lock(&comp->mutex); + module_put(comp->ops->owner); + component_unbind_all(dev, comp); + WARN_ON(comp->ops); + mutex_unlock(&comp->mutex); +} + +static const struct component_master_ops i915_hdcp_component_master_ops = { + .bind = i915_hdcp_component_master_bind, + .unbind = i915_hdcp_component_master_unbind, +}; + +static void intel_hdcp_component_cleanup(struct drm_i915_private *dev_priv) +{ + component_master_del(dev_priv->drm.dev, + &i915_hdcp_component_master_ops); + kfree(dev_priv->hdcp_comp); +} + +static void intel_hdcp2_exit(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + + /* TO-DO: Disable the HDCP here */ + kfree(connector->hdcp.mei_data.streams); + + if (dev_priv->hdcp_comp) + intel_hdcp_component_cleanup(dev_priv); +} + +static void intel_pull_down_mei_interface(struct device *kdev) +{ + struct drm_i915_private *dev_priv = kdev_to_i915(kdev); + struct drm_device *dev = &dev_priv->drm; + struct intel_connector *intel_connector; + struct drm_connector *connector; + struct drm_connector_list_iter conn_iter; + + DRM_INFO("MEI Device is Down"); + drm_connector_list_iter_begin(dev, &conn_iter); + drm_for_each_connector_iter(connector, &conn_iter) { + intel_connector = to_intel_connector(connector); + if (!intel_connector->hdcp.hdcp2_supported) + continue; + + intel_hdcp2_exit(intel_connector); + } + drm_connector_list_iter_end(&conn_iter); +} + +struct i915_hdcp_component_master_ops master_ops = { + .pull_down_interface = intel_pull_down_mei_interface, +}; + +static int i915_hdcp_component_master_match(struct device *dev, void *data) +{ + return !strcmp(dev->driver->name, "mei_hdcp"); +} + +static int intel_hdcp_component_init(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp; + struct component_match *match = NULL; + int ret; + + comp = kzalloc(sizeof(*comp), GFP_KERNEL); + if (!comp) + return -ENOMEM; + + mutex_init(&comp->mutex); + comp->master_ops = &master_ops; + dev_priv->hdcp_comp = comp; + + component_match_add(dev_priv->drm.dev, &match, + i915_hdcp_component_master_match, dev_priv); + ret = component_master_add_with_match(dev_priv->drm.dev, + &i915_hdcp_component_master_ops, + match); + if (ret < 0) + goto out_err; + + DRM_INFO("I915 hdcp component master added.\n"); + return ret; + +out_err: + component_master_del(dev_priv->drm.dev, + &i915_hdcp_component_master_ops); + kfree(comp); + dev_priv->hdcp_comp = NULL; + DRM_ERROR("Failed to add i915 hdcp component master (%d)\n", ret); + + return ret; +} + +static int initialize_mei_hdcp_data(struct intel_connector *connector) +{ + struct intel_hdcp *hdcp = &connector->hdcp; + struct mei_hdcp_data *data = &hdcp->mei_data; + enum port port; + + if (connector->encoder) { + port = connector->encoder->port; + data->port = GET_MEI_DDI_INDEX(port); + } + + data->port_type = INTEGRATED; + data->protocol = hdcp->hdcp_shim->hdcp_protocol(); + + data->k = 1; + if (!data->streams) + data->streams = kcalloc(data->k, + sizeof(struct hdcp2_streamid_type), + GFP_KERNEL); + if (!data->streams) { + DRM_ERROR("Out of Memory\n"); + return -ENOMEM; + } + + data->streams[0].stream_id = 0; + data->streams[0].stream_type = hdcp->content_type; + + return 0; +} + +bool is_hdcp2_supported(struct drm_i915_private *dev_priv) +{ + return (INTEL_GEN(dev_priv) >= 10 || IS_GEMINILAKE(dev_priv) || + IS_KABYLAKE(dev_priv)); +} + +static int intel_hdcp2_init(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct intel_hdcp *hdcp = &connector->hdcp; + int ret; + + WARN_ON(!is_hdcp2_supported(dev_priv)); + ret = initialize_mei_hdcp_data(connector); + if (ret) + goto exit; + + if (!dev_priv->hdcp_comp) + ret = intel_hdcp_component_init(connector); + + if (ret) + kfree(hdcp->mei_data.streams); + hdcp->hdcp2_supported = true; + +exit: + return ret; +} diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 8363fbd18ee8..7988f958d835 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2366,7 +2366,7 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
if (is_hdcp_supported(dev_priv, port)) { int ret = intel_hdcp_init(intel_connector, - &intel_hdmi_hdcp_shim); + &intel_hdmi_hdcp_shim, false); if (ret) DRM_DEBUG_KMS("HDCP init failed, skipping.\n"); } diff --git a/include/drm/i915_component.h b/include/drm/i915_component.h index 346b1f5cb180..9986174ee090 100644 --- a/include/drm/i915_component.h +++ b/include/drm/i915_component.h @@ -24,6 +24,10 @@ #ifndef _I915_COMPONENT_H_ #define _I915_COMPONENT_H_
+#include <linux/mei_cl_bus.h> +#include <linux/mei_hdcp.h> +#include <drm/drm_hdcp.h> + /* MAX_PORT is the number of port * It must be sync with I915_MAX_PORTS defined i915_drv.h */ @@ -121,4 +125,88 @@ struct i915_audio_component { const struct i915_audio_component_audio_ops *audio_ops; };
+struct i915_hdcp_component_ops { + /** + * @owner: mei_hdcp module + */ + struct module *owner; + int (*initiate_hdcp2_session)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_init *ake_data); + int + (*verify_receiver_cert_prepare_km)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km + *ek_pub_km, + size_t *msg_sz); + int (*verify_hprime)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_hprime *rx_hprime); + int (*store_pairing_info)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_pairing_info + *pairing_info); + int (*initiate_locality_check)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_lc_init *lc_init_data); + int (*verify_lprime)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_lc_send_lprime *rx_lprime); + int (*get_session_key)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ske_send_eks *ske_data); + int + (*repeater_check_flow_prepare_ack)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack + *rep_send_ack); + int (*verify_mprime)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_rep_stream_ready *stream_ready); + int (*enable_hdcp_authentication)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data); + int (*close_hdcp_session)(struct mei_cl_device *cldev, + struct mei_hdcp_data *data); +}; + +struct i915_hdcp_component_master_ops { + void (*pull_down_interface)(struct device *dev); +}; + +/** + * struct i915_mei_hdcp_component - Used for direct communication between i915 + * and mei_hdcp drivers + */ +struct i915_hdcp_component { + /** + * @dev: Kdev of Slave Component. Passed to bind calls. + */ + struct device *dev; + /** + * @i915_kdev: Kdev of I915. Used from the client component for + * removing the reference to mei_cldev. + */ + struct device *i915_kdev; + /** + * @mei_cldev: mei client device, used as parameter for ops + */ + struct mei_cl_device *mei_cldev; + /** + * @mutex: Mutex to protect the state of mei_cldev + */ + struct mutex mutex; + /** + * @ops: Ops implemented by mei_hdcp driver, used by i915 driver. + */ + const struct i915_hdcp_component_ops *ops; + /** + * @master_ops: Ops implemented by I915 driver, used by mei_hdcp driver. + */ + const struct i915_hdcp_component_master_ops *master_ops; +}; + #endif /* _I915_COMPONENT_H_ */
[ The bot has a bug where it doesn't copy the error messages so I just guess what the issue is. - dan ]
Hi Ramalingam,
Thank you for the patch! Perhaps something to improve:
url: https://github.com/0day-ci/linux/commits/Ramalingam-C/drm-i915-Implement-HDC... base: git://anongit.freedesktop.org/drm-intel for-linux-next
# https://github.com/0day-ci/linux/commit/86525c76cf90e793d6d915879e144924d152... git remote add linux-review https://github.com/0day-ci/linux git remote update linux-review git checkout 86525c76cf90e793d6d915879e144924d1520d60 vim +941 drivers/gpu/drm/i915/intel_hdcp.c
86525c76 Ramalingam C 2018-06-27 913 86525c76 Ramalingam C 2018-06-27 914 static int i915_hdcp_component_master_bind(struct device *dev) 86525c76 Ramalingam C 2018-06-27 915 { 86525c76 Ramalingam C 2018-06-27 916 struct drm_i915_private *dev_priv = kdev_to_i915(dev); 86525c76 Ramalingam C 2018-06-27 917 struct i915_hdcp_component *comp = dev_priv->hdcp_comp; 86525c76 Ramalingam C 2018-06-27 918 int ret; 86525c76 Ramalingam C 2018-06-27 919 86525c76 Ramalingam C 2018-06-27 920 mutex_lock(&comp->mutex); 86525c76 Ramalingam C 2018-06-27 921 ret = component_bind_all(dev, comp); 86525c76 Ramalingam C 2018-06-27 922 if (ret < 0) 86525c76 Ramalingam C 2018-06-27 923 return ret; ^^^^^^^^^^ We should unlock before returning. goto unlock. We probably don't want to unbind if the bind failed?
86525c76 Ramalingam C 2018-06-27 924 86525c76 Ramalingam C 2018-06-27 925 /* 86525c76 Ramalingam C 2018-06-27 926 * Atm, we don't support dynamic unbinding initiated by the child 86525c76 Ramalingam C 2018-06-27 927 * component, so pin its containing module until we unbind. 86525c76 Ramalingam C 2018-06-27 928 */ 86525c76 Ramalingam C 2018-06-27 929 if (!try_module_get(comp->ops->owner)) { 86525c76 Ramalingam C 2018-06-27 930 ret = -ENODEV; 86525c76 Ramalingam C 2018-06-27 931 goto out_unbind; 86525c76 Ramalingam C 2018-06-27 932 } 86525c76 Ramalingam C 2018-06-27 933 86525c76 Ramalingam C 2018-06-27 934 mutex_unlock(&comp->mutex); 86525c76 Ramalingam C 2018-06-27 935 return 0; 86525c76 Ramalingam C 2018-06-27 936 86525c76 Ramalingam C 2018-06-27 937 out_unbind: 86525c76 Ramalingam C 2018-06-27 938 component_unbind_all(dev, comp); 86525c76 Ramalingam C 2018-06-27 939 mutex_unlock(&comp->mutex); 86525c76 Ramalingam C 2018-06-27 940 86525c76 Ramalingam C 2018-06-27 @941 return ret; 86525c76 Ramalingam C 2018-06-27 942 } 86525c76 Ramalingam C 2018-06-27 943
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
As a preparation for making the intel_hdcp_enable as common function for both HDCP1.4 and HDCP2.2, HDCP1.4 check_link scheduling is moved into _intel_hdcp_enable() function.
v3: No Changes. v4: Style fix. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 769560591aa8..4bff74b3bed0 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -688,7 +688,7 @@ static int _intel_hdcp_enable(struct intel_connector *connector) ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->hdcp_shim); if (!ret) - return 0; + break;
DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
@@ -696,7 +696,13 @@ static int _intel_hdcp_enable(struct intel_connector *connector) _intel_hdcp_disable(connector); }
- DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret); + if (i != tries) + schedule_delayed_work(&hdcp->hdcp_check_work, + DRM_HDCP_CHECK_PERIOD_MS); + else + DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", + tries, ret); + return ret; }
@@ -790,8 +796,6 @@ int intel_hdcp_enable(struct intel_connector *connector)
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; schedule_work(&hdcp->hdcp_prop_work); - schedule_delayed_work(&hdcp->hdcp_check_work, - DRM_HDCP_CHECK_PERIOD_MS); out: mutex_unlock(&hdcp->hdcp_mutex); return ret;
On Wed, Jun 27, 2018 at 02:09:58PM +0530, Ramalingam C wrote:
As a preparation for making the intel_hdcp_enable as common function for both HDCP1.4 and HDCP2.2, HDCP1.4 check_link scheduling is moved into _intel_hdcp_enable() function.
v3: No Changes. v4: Style fix. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 769560591aa8..4bff74b3bed0 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -688,7 +688,7 @@ static int _intel_hdcp_enable(struct intel_connector *connector) ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->hdcp_shim); if (!ret)
return 0;
break;
DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
@@ -696,7 +696,13 @@ static int _intel_hdcp_enable(struct intel_connector *connector) _intel_hdcp_disable(connector); }
- DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
- if (i != tries)
schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
At best, this results in a duplicate scheduling when called from intel_hdcp_check_link(). At worst, it schedules a check when it's not supposed to (see the condition in intel_hdcp_check_work).
Sean
- else
DRM_ERROR("HDCP authentication failed (%d tries/%d)\n",
tries, ret);
- return ret;
}
@@ -790,8 +796,6 @@ int intel_hdcp_enable(struct intel_connector *connector)
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
out: mutex_unlock(&hdcp->hdcp_mutex); return ret; -- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 2:04 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [PATCH v5 09/40] drm/i915: Schedule hdcp_check_link in _intel_hdcp_enable
On Wed, Jun 27, 2018 at 02:09:58PM +0530, Ramalingam C wrote:
As a preparation for making the intel_hdcp_enable as common function for both HDCP1.4 and HDCP2.2, HDCP1.4 check_link scheduling is moved into _intel_hdcp_enable() function.
v3: No Changes. v4: Style fix. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 769560591aa8..4bff74b3bed0 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -688,7 +688,7 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->hdcp_shim); if (!ret)
return 0;
break;
DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
@@ -696,7 +696,13 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
_intel_hdcp_disable(connector);
}
- DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
- if (i != tries)
schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
At best, this results in a duplicate scheduling when called from intel_hdcp_check_link(). At worst, it schedules a check when it's not supposed to (see the condition in intel_hdcp_check_work).
In original HDCP1.4 implementation hdcp_check_work is scheduled at intel_hdcp_enable. To make the intel_hdcp_enable as a common function for 1.4 and 2.2, the same hdcp_check_work is scheduled at _intel_hdcp_enable which is enable function for HDCP1.4.
So no real functional change with this patch. If you are mentioning the check_work is getting scheduled before prop_work and/or hdcp_value update, check_link handles that. Means if the hdcp value is not UNDESIRED then shim's link_check will be invoked.
Hope I understood your concern right.
Thanks, Ram
Sean
- else
DRM_ERROR("HDCP authentication failed (%d tries/%d)\n",
tries, ret);
- return ret;
}
@@ -790,8 +796,6 @@ int intel_hdcp_enable(struct intel_connector *connector)
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
out: mutex_unlock(&hdcp->hdcp_mutex); return ret; -- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-- Sean Paul, Software Engineer, Google / Chromium OS
On Wed, Jul 11, 2018 at 07:07:10PM +0000, C, Ramalingam wrote:
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 2:04 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [PATCH v5 09/40] drm/i915: Schedule hdcp_check_link in _intel_hdcp_enable
On Wed, Jun 27, 2018 at 02:09:58PM +0530, Ramalingam C wrote:
As a preparation for making the intel_hdcp_enable as common function for both HDCP1.4 and HDCP2.2, HDCP1.4 check_link scheduling is moved into _intel_hdcp_enable() function.
v3: No Changes. v4: Style fix. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 769560591aa8..4bff74b3bed0 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -688,7 +688,7 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->hdcp_shim); if (!ret)
return 0;
break;
DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
@@ -696,7 +696,13 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
_intel_hdcp_disable(connector);
}
- DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
- if (i != tries)
schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
At best, this results in a duplicate scheduling when called from intel_hdcp_check_link(). At worst, it schedules a check when it's not supposed to (see the condition in intel_hdcp_check_work).
In original HDCP1.4 implementation hdcp_check_work is scheduled at intel_hdcp_enable. To make the intel_hdcp_enable as a common function for 1.4 and 2.2, the same hdcp_check_work is scheduled at _intel_hdcp_enable which is enable function for HDCP1.4.
So no real functional change with this patch. If you are mentioning the check_work is getting scheduled before prop_work and/or hdcp_value update, check_link handles that. Means if the hdcp value is not UNDESIRED then shim's link_check will be invoked.
Hope I understood your concern right.
I'm not sure. intel_hdcp_check_link() calls _intel_hdcp_enable(), which is now scheduling a check. So, in essence, intel_hdcp_check_work() is rescheduling itself through this call chain. Once intel_hdcp_check_link() returns in intel_hdcp_check_work(), the worker reschedules itself if the link is good, so you get a duplicate schedule.
Sean
Thanks, Ram
Sean
- else
DRM_ERROR("HDCP authentication failed (%d tries/%d)\n",
tries, ret);
- return ret;
}
@@ -790,8 +796,6 @@ int intel_hdcp_enable(struct intel_connector *connector)
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
out: mutex_unlock(&hdcp->hdcp_mutex); return ret; -- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-- Sean Paul, Software Engineer, Google / Chromium OS
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Thursday, July 12, 2018 2:36 AM To: C, Ramalingam ramalingam.c@intel.com Cc: Sean Paul seanpaul@chromium.org; intel-gfx@lists.freedesktop.org; dri- devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [PATCH v5 09/40] drm/i915: Schedule hdcp_check_link in _intel_hdcp_enable
On Wed, Jul 11, 2018 at 07:07:10PM +0000, C, Ramalingam wrote:
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 2:04 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Subject: Re: [PATCH v5 09/40] drm/i915: Schedule hdcp_check_link in _intel_hdcp_enable
On Wed, Jun 27, 2018 at 02:09:58PM +0530, Ramalingam C wrote:
As a preparation for making the intel_hdcp_enable as common function for both HDCP1.4 and HDCP2.2, HDCP1.4 check_link scheduling is moved into _intel_hdcp_enable() function.
v3: No Changes. v4: Style fix. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 769560591aa8..4bff74b3bed0 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -688,7 +688,7 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
ret = intel_hdcp_auth(conn_to_dig_port(connector), hdcp->hdcp_shim); if (!ret)
return 0;
break;
DRM_DEBUG_KMS("HDCP Auth failure (%d)\n", ret);
@@ -696,7 +696,13 @@ static int _intel_hdcp_enable(struct intel_connector
*connector)
_intel_hdcp_disable(connector);
}
- DRM_ERROR("HDCP authentication failed (%d tries/%d)\n", tries, ret);
- if (i != tries)
schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
At best, this results in a duplicate scheduling when called from intel_hdcp_check_link(). At worst, it schedules a check when it's not supposed to (see the condition in intel_hdcp_check_work).
In original HDCP1.4 implementation hdcp_check_work is scheduled at
intel_hdcp_enable.
To make the intel_hdcp_enable as a common function for 1.4 and 2.2, the same hdcp_check_work is scheduled at _intel_hdcp_enable which is
enable function for HDCP1.4.
So no real functional change with this patch. If you are mentioning the check_work is getting scheduled before prop_work and/or hdcp_value
update, check_link handles that.
Means if the hdcp value is not UNDESIRED then shim's link_check will be
invoked.
Hope I understood your concern right.
I'm not sure. intel_hdcp_check_link() calls _intel_hdcp_enable(), which is now scheduling a check. So, in essence, intel_hdcp_check_work() is rescheduling itself through this call chain. Once intel_hdcp_check_link() returns in intel_hdcp_check_work(), the worker reschedules itself if the link is good, so you get a duplicate schedule.
Oops! Thanks for catching me there. I missed to notice that _intel_hdcp_enable is called from check_link also. I will fix that within intel_hdcp_enable itself. In that case this patch is no more needed.
Thanks, Ram
Sean
Thanks, Ram
Sean
- else
DRM_ERROR("HDCP authentication failed (%d tries/%d)\n",
tries, ret);
- return ret;
}
@@ -790,8 +796,6 @@ int intel_hdcp_enable(struct intel_connector *connector)
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; schedule_work(&hdcp->hdcp_prop_work);
- schedule_delayed_work(&hdcp->hdcp_check_work,
DRM_HDCP_CHECK_PERIOD_MS);
out: mutex_unlock(&hdcp->hdcp_mutex); return ret; -- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
-- Sean Paul, Software Engineer, Google / Chromium OS
-- Sean Paul, Software Engineer, Google / Chromium OS
For reusability purpose, this patch implements the hdcp1.4 bksv's read and validation as a functions.
For detecting the HDMI panel's HDCP capability this fucntions will be used.
v2: Rebased. v3: No Changes. v4: inline tag is removed with modified error msg. v5: No Changes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 4bff74b3bed0..32a1a3f39b65 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -400,6 +400,28 @@ int intel_hdcp_validate_v_prime(struct intel_digital_port *intel_dig_port, return 0; }
+static +int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port, + const struct intel_hdcp_shim *shim, u8 *bksv) +{ + int ret, i, tries = 2; + + /* HDCP spec states that we must retry the bksv if it is invalid */ + for (i = 0; i < tries; i++) { + ret = shim->read_bksv(intel_dig_port, bksv); + if (ret) + return ret; + if (intel_hdcp_is_ksv_valid(bksv)) + break; + } + if (i == tries) { + DRM_ERROR("Bksv is invalid\n"); + return -ENODEV; + } + + return 0; +} + /* Implements Part 2 of the HDCP authorization procedure */ static int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, @@ -533,18 +555,9 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
memset(&bksv, 0, sizeof(bksv));
- /* HDCP spec states that we must retry the bksv if it is invalid */ - for (i = 0; i < tries; i++) { - ret = shim->read_bksv(intel_dig_port, bksv.shim); - if (ret) - return ret; - if (intel_hdcp_is_ksv_valid(bksv.shim)) - break; - } - if (i == tries) { - DRM_ERROR("HDCP failed, Bksv is invalid\n"); - return -ENODEV; - } + ret = intel_hdcp_read_valid_bksv(intel_dig_port, shim, bksv.shim); + if (ret < 0) + return ret;
I915_WRITE(PORT_HDCP_BKSVLO(port), bksv.reg[0]); I915_WRITE(PORT_HDCP_BKSVHI(port), bksv.reg[1]);
On Wed, Jun 27, 2018 at 02:09:59PM +0530, Ramalingam C wrote:
For reusability purpose, this patch implements the hdcp1.4 bksv's read and validation as a functions.
For detecting the HDMI panel's HDCP capability this fucntions will be used.
v2: Rebased. v3: No Changes. v4: inline tag is removed with modified error msg. v5: No Changes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
Reviewed-by: Sean Paul seanpaul@chromium.org
drivers/gpu/drm/i915/intel_hdcp.c | 37 +++++++++++++++++++++++++------------ 1 file changed, 25 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 4bff74b3bed0..32a1a3f39b65 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -400,6 +400,28 @@ int intel_hdcp_validate_v_prime(struct intel_digital_port *intel_dig_port, return 0; }
+static +int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port,
const struct intel_hdcp_shim *shim, u8 *bksv)
+{
- int ret, i, tries = 2;
- /* HDCP spec states that we must retry the bksv if it is invalid */
- for (i = 0; i < tries; i++) {
ret = shim->read_bksv(intel_dig_port, bksv);
if (ret)
return ret;
if (intel_hdcp_is_ksv_valid(bksv))
break;
- }
- if (i == tries) {
DRM_ERROR("Bksv is invalid\n");
return -ENODEV;
- }
- return 0;
+}
/* Implements Part 2 of the HDCP authorization procedure */ static int intel_hdcp_auth_downstream(struct intel_digital_port *intel_dig_port, @@ -533,18 +555,9 @@ static int intel_hdcp_auth(struct intel_digital_port *intel_dig_port,
memset(&bksv, 0, sizeof(bksv));
- /* HDCP spec states that we must retry the bksv if it is invalid */
- for (i = 0; i < tries; i++) {
ret = shim->read_bksv(intel_dig_port, bksv.shim);
if (ret)
return ret;
if (intel_hdcp_is_ksv_valid(bksv.shim))
break;
- }
- if (i == tries) {
DRM_ERROR("HDCP failed, Bksv is invalid\n");
return -ENODEV;
- }
ret = intel_hdcp_read_valid_bksv(intel_dig_port, shim, bksv.shim);
if (ret < 0)
return ret;
I915_WRITE(PORT_HDCP_BKSVLO(port), bksv.reg[0]); I915_WRITE(PORT_HDCP_BKSVHI(port), bksv.reg[1]);
-- 2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Considering that HDCP2.2 is more secure than HDCP1.4, When a setup supports HDCP2.2 and HDCP1.4, HDCP2.2 will be enabled.
v2: Included few optimization suggestions [Chris Wilson] Commit message is updated as per the rebased version. v3: No changes. v4: Extra comment added and Style issue fixed [Uma] v5: Rebased as part of patch reordering. Flag is added for tracking hdcp2.2 encryption status.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_hdcp.c | 90 +++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2eeb82b04953..7624388eecd5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -414,6 +414,7 @@ struct intel_hdcp {
/* HDCP2.2 related definitions */ bool hdcp2_supported; + bool hdcp2_in_use;
/* * Content Stream Type defined by content owner. TYPE0(0x0) content can diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 32a1a3f39b65..b34e3b1587d6 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -21,6 +21,60 @@ (enum hdcp_physical_port)(port))
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 +int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port, + const struct intel_hdcp_shim *shim, u8 *bksv); +static +struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector); + +static bool panel_supports_hdcp(struct intel_connector *connector) +{ + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + bool capable = false; + u8 bksv[5]; + + if (hdcp->hdcp_shim) { + 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; + } + } + + return capable; +} + +static inline +bool panel_supports_hdcp2(struct intel_connector *connector) +{ + struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); + struct intel_hdcp *hdcp = &connector->hdcp; + bool capable = false; + + /* Check the panel's hdcp2.2 compliance if platform supports it. */ + if (hdcp->hdcp2_supported) + hdcp->hdcp_shim->hdcp_2_2_capable(intel_dig_port, &capable); + + return capable; +} + +/* Is HDCP1.4 capable on Platform and Panel */ +static inline bool intel_hdcp_capable(struct intel_connector *connector) +{ + return (connector->hdcp.hdcp_shim && panel_supports_hdcp(connector)); +} + +/* Is HDCP2.2 capable on Platform and Panel */ +static inline bool intel_hdcp2_capable(struct intel_connector *connector) +{ + return (connector->hdcp.hdcp2_supported && + panel_supports_hdcp2(connector)); +}
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) @@ -796,20 +850,27 @@ int intel_hdcp_init(struct intel_connector *connector, int intel_hdcp_enable(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; - int ret; + int ret = -EINVAL;
if (!hdcp->hdcp_shim) return -ENOENT;
mutex_lock(&hdcp->hdcp_mutex);
- ret = _intel_hdcp_enable(connector); - if (ret) - goto out; + /* + * 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. + */ + if (intel_hdcp2_capable(connector)) + ret = _intel_hdcp2_enable(connector); + else if (intel_hdcp_capable(connector)) + ret = _intel_hdcp_enable(connector); + + if (!ret) { + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&hdcp->hdcp_prop_work); + }
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; - schedule_work(&hdcp->hdcp_prop_work); -out: mutex_unlock(&hdcp->hdcp_mutex); return ret; } @@ -826,7 +887,10 @@ int intel_hdcp_disable(struct intel_connector *connector)
if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED; - ret = _intel_hdcp_disable(connector); + if (hdcp->hdcp2_in_use) + ret = _intel_hdcp2_disable(connector); + else + ret = _intel_hdcp_disable(connector); }
mutex_unlock(&hdcp->hdcp_mutex); @@ -928,6 +992,16 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int _intel_hdcp2_enable(struct intel_connector *connector) +{ + return 0; +} + +static int _intel_hdcp2_disable(struct intel_connector *connector) +{ + return 0; +} + static int i915_hdcp_component_master_bind(struct device *dev) { struct drm_i915_private *dev_priv = kdev_to_i915(dev);
On Wed, Jun 27, 2018 at 02:10:00PM +0530, Ramalingam C wrote:
Considering that HDCP2.2 is more secure than HDCP1.4, When a setup supports HDCP2.2 and HDCP1.4, HDCP2.2 will be enabled.
v2: Included few optimization suggestions [Chris Wilson] Commit message is updated as per the rebased version. v3: No changes. v4: Extra comment added and Style issue fixed [Uma] v5: Rebased as part of patch reordering. Flag is added for tracking hdcp2.2 encryption status.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_hdcp.c | 90 +++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2eeb82b04953..7624388eecd5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -414,6 +414,7 @@ struct intel_hdcp {
/* HDCP2.2 related definitions */ bool hdcp2_supported;
bool hdcp2_in_use;
/*
- Content Stream Type defined by content owner. TYPE0(0x0) content can
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 32a1a3f39b65..b34e3b1587d6 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -21,6 +21,60 @@ (enum hdcp_physical_port)(port))
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 +int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port,
const struct intel_hdcp_shim *shim, u8 *bksv);
+static +struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector);
Please avoid forward declarations of static functions. Just place things appropriately in the file.
+static bool panel_supports_hdcp(struct intel_connector *connector) +{
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- bool capable = false;
- u8 bksv[5];
- if (hdcp->hdcp_shim) {
This function can only be called from intel_hdcp_enable() -> intel_hdcp_capable() -> panel_supports_hdcp()
Both of those preceding functions check if hdcp_shim is NULL.
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;
}
- }
- return capable;
+}
+static inline +bool panel_supports_hdcp2(struct intel_connector *connector) +{
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- bool capable = false;
- /* Check the panel's hdcp2.2 compliance if platform supports it. */
- if (hdcp->hdcp2_supported)
hdcp->hdcp_shim->hdcp_2_2_capable(intel_dig_port, &capable);
- return capable;
+}
+/* Is HDCP1.4 capable on Platform and Panel */ +static inline bool intel_hdcp_capable(struct intel_connector *connector) +{
- return (connector->hdcp.hdcp_shim && panel_supports_hdcp(connector));
As mentioned, the hdcp_shim check is already covered by the caller. The way things are setup, the shim checks only need to exist at the entry points (enable/disable/check_link).
+}
+/* Is HDCP2.2 capable on Platform and Panel */ +static inline bool intel_hdcp2_capable(struct intel_connector *connector) +{
- return (connector->hdcp.hdcp2_supported &&
panel_supports_hdcp2(connector));
+}
The panel_supports_* functions don't seem necessary, just do the work in the intel_hdcp*_capable functions.
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) @@ -796,20 +850,27 @@ int intel_hdcp_init(struct intel_connector *connector, int intel_hdcp_enable(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp;
- int ret;
int ret = -EINVAL;
if (!hdcp->hdcp_shim) return -ENOENT;
mutex_lock(&hdcp->hdcp_mutex);
- ret = _intel_hdcp_enable(connector);
- if (ret)
goto out;
- /*
* 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.
*/
- if (intel_hdcp2_capable(connector))
ret = _intel_hdcp2_enable(connector);
- else if (intel_hdcp_capable(connector))
ret = _intel_hdcp_enable(connector);
- if (!ret) {
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
schedule_work(&hdcp->hdcp_prop_work);
- }
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&hdcp->hdcp_prop_work);
-out: mutex_unlock(&hdcp->hdcp_mutex); return ret; } @@ -826,7 +887,10 @@ int intel_hdcp_disable(struct intel_connector *connector)
if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ret = _intel_hdcp_disable(connector);
if (hdcp->hdcp2_in_use)
ret = _intel_hdcp2_disable(connector);
else
ret = _intel_hdcp_disable(connector);
}
mutex_unlock(&hdcp->hdcp_mutex);
@@ -928,6 +992,16 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int _intel_hdcp2_enable(struct intel_connector *connector) +{
- return 0;
+}
+static int _intel_hdcp2_disable(struct intel_connector *connector) +{
- return 0;
+}
nit: It'd probably be better to introduce the stubs with an error message, since as you have it, you'll be able to "enable" HDCP2 without doing anything.
Sean
static int i915_hdcp_component_master_bind(struct device *dev) { struct drm_i915_private *dev_priv = kdev_to_i915(dev); -- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
On Tuesday 10 July 2018 02:14 AM, Sean Paul wrote:
On Wed, Jun 27, 2018 at 02:10:00PM +0530, Ramalingam C wrote:
Considering that HDCP2.2 is more secure than HDCP1.4, When a setup supports HDCP2.2 and HDCP1.4, HDCP2.2 will be enabled.
v2: Included few optimization suggestions [Chris Wilson] Commit message is updated as per the rebased version. v3: No changes. v4: Extra comment added and Style issue fixed [Uma] v5: Rebased as part of patch reordering. Flag is added for tracking hdcp2.2 encryption status.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_drv.h | 1 + drivers/gpu/drm/i915/intel_hdcp.c | 90 +++++++++++++++++++++++++++++++++++---- 2 files changed, 83 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 2eeb82b04953..7624388eecd5 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -414,6 +414,7 @@ struct intel_hdcp {
/* HDCP2.2 related definitions */ bool hdcp2_supported;
bool hdcp2_in_use;
/*
- Content Stream Type defined by content owner. TYPE0(0x0) content can
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 32a1a3f39b65..b34e3b1587d6 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -21,6 +21,60 @@ (enum hdcp_physical_port)(port))
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 +int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port,
const struct intel_hdcp_shim *shim, u8 *bksv);
+static +struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector);
Please avoid forward declarations of static functions. Just place things appropriately in the file.
+static bool panel_supports_hdcp(struct intel_connector *connector) +{
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- bool capable = false;
- u8 bksv[5];
- if (hdcp->hdcp_shim) {
This function can only be called from intel_hdcp_enable() -> intel_hdcp_capable() -> panel_supports_hdcp()
Both of those preceding functions check if hdcp_shim is NULL.
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;
}
- }
- return capable;
+}
+static inline +bool panel_supports_hdcp2(struct intel_connector *connector) +{
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- bool capable = false;
- /* Check the panel's hdcp2.2 compliance if platform supports it. */
- if (hdcp->hdcp2_supported)
hdcp->hdcp_shim->hdcp_2_2_capable(intel_dig_port, &capable);
- return capable;
+}
+/* Is HDCP1.4 capable on Platform and Panel */ +static inline bool intel_hdcp_capable(struct intel_connector *connector) +{
- return (connector->hdcp.hdcp_shim && panel_supports_hdcp(connector));
As mentioned, the hdcp_shim check is already covered by the caller. The way things are setup, the shim checks only need to exist at the entry points (enable/disable/check_link).
+}
+/* Is HDCP2.2 capable on Platform and Panel */ +static inline bool intel_hdcp2_capable(struct intel_connector *connector) +{
- return (connector->hdcp.hdcp2_supported &&
panel_supports_hdcp2(connector));
+}
The panel_supports_* functions don't seem necessary, just do the work in the intel_hdcp*_capable functions.
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) @@ -796,20 +850,27 @@ int intel_hdcp_init(struct intel_connector *connector, int intel_hdcp_enable(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp;
- int ret;
int ret = -EINVAL;
if (!hdcp->hdcp_shim) return -ENOENT;
mutex_lock(&hdcp->hdcp_mutex);
- ret = _intel_hdcp_enable(connector);
- if (ret)
goto out;
- /*
* 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.
*/
- if (intel_hdcp2_capable(connector))
ret = _intel_hdcp2_enable(connector);
- else if (intel_hdcp_capable(connector))
ret = _intel_hdcp_enable(connector);
- if (!ret) {
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
schedule_work(&hdcp->hdcp_prop_work);
- }
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&hdcp->hdcp_prop_work);
-out: mutex_unlock(&hdcp->hdcp_mutex); return ret; } @@ -826,7 +887,10 @@ int intel_hdcp_disable(struct intel_connector *connector)
if (hdcp->hdcp_value != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) { hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_UNDESIRED;
ret = _intel_hdcp_disable(connector);
if (hdcp->hdcp2_in_use)
ret = _intel_hdcp2_disable(connector);
else
ret = _intel_hdcp_disable(connector);
}
mutex_unlock(&hdcp->hdcp_mutex);
@@ -928,6 +992,16 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int _intel_hdcp2_enable(struct intel_connector *connector) +{
- return 0;
+}
+static int _intel_hdcp2_disable(struct intel_connector *connector) +{
- return 0;
+}
nit: It'd probably be better to introduce the stubs with an error message, since as you have it, you'll be able to "enable" HDCP2 without doing anything.
Thanks Sean. Taken care of all above suggestions in next version. And I have squashed patches 11, 12, 13 and 14.
Ram.
Sean
- static int i915_hdcp_component_master_bind(struct device *dev) { struct drm_i915_private *dev_priv = kdev_to_i915(dev);
-- 2.7.4
dri-devel mailing list dri-devel@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/dri-devel
When HDCP2.2 enabling fails and HDCP1.4 is supported, HDCP1.4 is enabled.
v2: Rebased. v3: No Changes. v4: Reviewed-by is collected. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index b34e3b1587d6..34bafc2025f7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -863,7 +863,9 @@ int intel_hdcp_enable(struct intel_connector *connector) */ if (intel_hdcp2_capable(connector)) ret = _intel_hdcp2_enable(connector); - else if (intel_hdcp_capable(connector)) + + /* When HDCP2.2 fails, HDCP1.4 will be attempted */ + if (ret && intel_hdcp_capable(connector)) ret = _intel_hdcp_enable(connector);
if (!ret) {
On Wed, Jun 27, 2018 at 02:10:01PM +0530, Ramalingam C wrote:
When HDCP2.2 enabling fails and HDCP1.4 is supported, HDCP1.4 is enabled.
Just squash this into patch 11, no need for a separate patch.
v2: Rebased. v3: No Changes. v4: Reviewed-by is collected. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index b34e3b1587d6..34bafc2025f7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -863,7 +863,9 @@ int intel_hdcp_enable(struct intel_connector *connector) */ if (intel_hdcp2_capable(connector)) ret = _intel_hdcp2_enable(connector);
- else if (intel_hdcp_capable(connector))
/* When HDCP2.2 fails, HDCP1.4 will be attempted */
if (ret && intel_hdcp_capable(connector)) ret = _intel_hdcp_enable(connector);
if (!ret) {
-- 2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Tuesday 10 July 2018 02:14 AM, Sean Paul wrote:
On Wed, Jun 27, 2018 at 02:10:01PM +0530, Ramalingam C wrote:
When HDCP2.2 enabling fails and HDCP1.4 is supported, HDCP1.4 is enabled.
Just squash this into patch 11, no need for a separate patch.
Doing it in the next version of the series.
Ram.
v2: Rebased. v3: No Changes. v4: Reviewed-by is collected. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index b34e3b1587d6..34bafc2025f7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -863,7 +863,9 @@ int intel_hdcp_enable(struct intel_connector *connector) */ if (intel_hdcp2_capable(connector)) ret = _intel_hdcp2_enable(connector);
- else if (intel_hdcp_capable(connector))
/* When HDCP2.2 fails, HDCP1.4 will be attempted */
if (ret && intel_hdcp_capable(connector)) ret = _intel_hdcp_enable(connector);
if (!ret) {
-- 2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Implements a sequence of enabling and disabling the HDCP2.2 (auth and encryption).
v2: Rebased. v3: No Changes. v4: No Changes. v5: Rebased as part of the patch reordering. HDCP2 encryption status is tracked.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 105 +++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 34bafc2025f7..f72684488bc7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -994,14 +994,117 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int hdcp2_close_mei_session(struct intel_connector *connector) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + ret = comp->ops->close_hdcp_session(comp->mei_cldev, data); + mutex_unlock(&comp->mutex); + + return ret; +} + +static int hdcp2_deauthenticate_port(struct intel_connector *connector) +{ + return hdcp2_close_mei_session(connector); +} + +static int hdcp2_authenticate_sink(struct intel_connector *connector) +{ + return 0; +} + +static int hdcp2_enable_encryption(struct intel_connector *connector) +{ + return 0; +} + +static int hdcp2_disable_encryption(struct intel_connector *connector) +{ + return 0; +} + +static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector) +{ + int ret, i, tries = 3; + + for (i = 0; i < tries; i++) { + ret = hdcp2_authenticate_sink(connector); + if (!ret) + break; + + /* Clearing the mei hdcp session */ + hdcp2_deauthenticate_port(connector); + DRM_DEBUG_KMS("HDCP2.2 Auth %d of %d Failed.(%d)\n", + i + 1, tries, ret); + } + + if (i != tries) { + /* + * Ensuring the required 200mSec min time interval between + * Session Key Exchange and encryption. + */ + msleep(HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN); + ret = hdcp2_enable_encryption(connector); + if (ret < 0) { + DRM_DEBUG_KMS("Encryption Enable Failed.(%d)\n", ret); + hdcp2_deauthenticate_port(connector); + } + } + + return ret; +} + static int _intel_hdcp2_enable(struct intel_connector *connector) { + struct intel_hdcp *hdcp = &connector->hdcp; + int ret; + + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being enabled. Type: %d\n", + connector->base.name, connector->base.base.id, + hdcp->content_type); + + ret = hdcp2_authenticate_and_encrypt(connector); + if (ret) { + DRM_ERROR("HDCP2 Type%d Enabling Failed. (%d)\n", + hdcp->content_type, ret); + return ret; + } + + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is enabled. Type %d\n", + connector->base.name, connector->base.base.id, + hdcp->content_type); + + hdcp->hdcp2_in_use = true; + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&hdcp->hdcp_prop_work); return 0; }
static int _intel_hdcp2_disable(struct intel_connector *connector) { - return 0; + int ret; + + DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being Disabled\n", + connector->base.name, connector->base.base.id); + + ret = hdcp2_disable_encryption(connector); + + hdcp2_deauthenticate_port(connector); + connector->hdcp.hdcp2_in_use = false; + + return ret; }
static int i915_hdcp_component_master_bind(struct device *dev)
On Wed, Jun 27, 2018 at 02:10:02PM +0530, Ramalingam C wrote:
Implements a sequence of enabling and disabling the HDCP2.2 (auth and encryption).
This is really hard to review, since all I see are stubs. I'd much rather have each patch do something useful, instead of just call stubs. That said, I don't have a vested interest in HDCP2.2 on intel, so if others are fine with it, I am too.
Sean
v2: Rebased. v3: No Changes. v4: No Changes. v5: Rebased as part of the patch reordering. HDCP2 encryption status is tracked.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 105 +++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 34bafc2025f7..f72684488bc7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -994,14 +994,117 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int hdcp2_close_mei_session(struct intel_connector *connector) +{
- struct mei_hdcp_data *data = &connector->hdcp.mei_data;
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct i915_hdcp_component *comp = dev_priv->hdcp_comp;
- int ret;
- if (!comp)
return -EINVAL;
- mutex_lock(&comp->mutex);
- if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) {
mutex_unlock(&comp->mutex);
return -EINVAL;
- }
- ret = comp->ops->close_hdcp_session(comp->mei_cldev, data);
- mutex_unlock(&comp->mutex);
- return ret;
+}
+static int hdcp2_deauthenticate_port(struct intel_connector *connector) +{
- return hdcp2_close_mei_session(connector);
+}
+static int hdcp2_authenticate_sink(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_enable_encryption(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_disable_encryption(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector) +{
- int ret, i, tries = 3;
- for (i = 0; i < tries; i++) {
ret = hdcp2_authenticate_sink(connector);
if (!ret)
break;
/* Clearing the mei hdcp session */
hdcp2_deauthenticate_port(connector);
DRM_DEBUG_KMS("HDCP2.2 Auth %d of %d Failed.(%d)\n",
i + 1, tries, ret);
- }
- if (i != tries) {
/*
* Ensuring the required 200mSec min time interval between
* Session Key Exchange and encryption.
*/
msleep(HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN);
ret = hdcp2_enable_encryption(connector);
if (ret < 0) {
DRM_DEBUG_KMS("Encryption Enable Failed.(%d)\n", ret);
hdcp2_deauthenticate_port(connector);
}
- }
- return ret;
+}
static int _intel_hdcp2_enable(struct intel_connector *connector) {
- struct intel_hdcp *hdcp = &connector->hdcp;
- int ret;
- DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being enabled. Type: %d\n",
connector->base.name, connector->base.base.id,
hdcp->content_type);
- ret = hdcp2_authenticate_and_encrypt(connector);
- if (ret) {
DRM_ERROR("HDCP2 Type%d Enabling Failed. (%d)\n",
hdcp->content_type, ret);
return ret;
- }
- DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is enabled. Type %d\n",
connector->base.name, connector->base.base.id,
hdcp->content_type);
- hdcp->hdcp2_in_use = true;
- hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
- schedule_work(&hdcp->hdcp_prop_work); return 0;
}
static int _intel_hdcp2_disable(struct intel_connector *connector) {
- return 0;
- int ret;
- DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being Disabled\n",
connector->base.name, connector->base.base.id);
- ret = hdcp2_disable_encryption(connector);
- hdcp2_deauthenticate_port(connector);
- connector->hdcp.hdcp2_in_use = false;
- return ret;
}
static int i915_hdcp_component_master_bind(struct device *dev)
2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Tuesday 10 July 2018 02:18 AM, Sean Paul wrote:
On Wed, Jun 27, 2018 at 02:10:02PM +0530, Ramalingam C wrote:
Implements a sequence of enabling and disabling the HDCP2.2 (auth and encryption).
This is really hard to review, since all I see are stubs. I'd much rather have each patch do something useful, instead of just call stubs. That said, I don't have a vested interest in HDCP2.2 on intel, so if others are fine with it, I am too.
Sean,
Just to avoid the so lengthy patches, I have split the changes in logical patches. Looks like patches 11, 12, 13 and 14 are not so appealing. Merged these patches together. Hope now the series looks more appealing.
Please have a look at the upcoming series version too. Thanks a lot again.
-Ram
Sean
v2: Rebased. v3: No Changes. v4: No Changes. v5: Rebased as part of the patch reordering. HDCP2 encryption status is tracked.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 105 +++++++++++++++++++++++++++++++++++++- 1 file changed, 104 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 34bafc2025f7..f72684488bc7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -994,14 +994,117 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int hdcp2_close_mei_session(struct intel_connector *connector) +{
- struct mei_hdcp_data *data = &connector->hdcp.mei_data;
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct i915_hdcp_component *comp = dev_priv->hdcp_comp;
- int ret;
- if (!comp)
return -EINVAL;
- mutex_lock(&comp->mutex);
- if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) {
mutex_unlock(&comp->mutex);
return -EINVAL;
- }
- ret = comp->ops->close_hdcp_session(comp->mei_cldev, data);
- mutex_unlock(&comp->mutex);
- return ret;
+}
+static int hdcp2_deauthenticate_port(struct intel_connector *connector) +{
- return hdcp2_close_mei_session(connector);
+}
+static int hdcp2_authenticate_sink(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_enable_encryption(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_disable_encryption(struct intel_connector *connector) +{
- return 0;
+}
+static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector) +{
- int ret, i, tries = 3;
- for (i = 0; i < tries; i++) {
ret = hdcp2_authenticate_sink(connector);
if (!ret)
break;
/* Clearing the mei hdcp session */
hdcp2_deauthenticate_port(connector);
DRM_DEBUG_KMS("HDCP2.2 Auth %d of %d Failed.(%d)\n",
i + 1, tries, ret);
- }
- if (i != tries) {
/*
* Ensuring the required 200mSec min time interval between
* Session Key Exchange and encryption.
*/
msleep(HDCP_2_2_DELAY_BEFORE_ENCRYPTION_EN);
ret = hdcp2_enable_encryption(connector);
if (ret < 0) {
DRM_DEBUG_KMS("Encryption Enable Failed.(%d)\n", ret);
hdcp2_deauthenticate_port(connector);
}
- }
- return ret;
+}
static int _intel_hdcp2_enable(struct intel_connector *connector) {
struct intel_hdcp *hdcp = &connector->hdcp;
int ret;
DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being enabled. Type: %d\n",
connector->base.name, connector->base.base.id,
hdcp->content_type);
ret = hdcp2_authenticate_and_encrypt(connector);
if (ret) {
DRM_ERROR("HDCP2 Type%d Enabling Failed. (%d)\n",
hdcp->content_type, ret);
return ret;
}
DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is enabled. Type %d\n",
connector->base.name, connector->base.base.id,
hdcp->content_type);
hdcp->hdcp2_in_use = true;
hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED;
schedule_work(&hdcp->hdcp_prop_work); return 0; }
static int _intel_hdcp2_disable(struct intel_connector *connector) {
- return 0;
int ret;
DRM_DEBUG_KMS("[%s:%d] HDCP2.2 is being Disabled\n",
connector->base.name, connector->base.base.id);
ret = hdcp2_disable_encryption(connector);
hdcp2_deauthenticate_port(connector);
connector->hdcp.hdcp2_in_use = false;
return ret; }
static int i915_hdcp_component_master_bind(struct device *dev)
-- 2.7.4
Intel-gfx mailing list Intel-gfx@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/intel-gfx
Implements the enable and disable functions for HDCP2.2 encryption of the PORT.
v2: intel_wait_for_register is used instead of wait_for. [Chris Wilson] v3: No Changes. v4: Debug msg is added for timeout at Disable of Encryption [Uma] %s/HDCP2_CTL/HDCP2_CTL v5: Rebased as part of patch reordering. HW state check is moved into WARN_ON [Daniel]
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 48 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index f72684488bc7..1e75b4fc978a 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -17,6 +17,7 @@ #include "i915_reg.h"
#define KEY_LOAD_TRIES 5 +#define TIME_FOR_ENCRYPT_STATUS_CHANGE 32 #define GET_MEI_DDI_INDEX(port) (((port) == PORT_A) ? DDI_A : \ (enum hdcp_physical_port)(port))
@@ -1027,12 +1028,55 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector)
static int hdcp2_enable_encryption(struct intel_connector *connector) { - return 0; + 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; + + WARN_ON(I915_READ(HDCP2_STATUS_DDI(port)) & LINK_ENCRYPTION_STATUS); + + if (hdcp->hdcp_shim->toggle_signalling) + hdcp->hdcp_shim->toggle_signalling(intel_dig_port, true); + + if (I915_READ(HDCP2_STATUS_DDI(port)) & LINK_AUTH_STATUS) { + /* Link is Authenticated. Now set for Encryption */ + I915_WRITE(HDCP2_CTL_DDI(port), + I915_READ(HDCP2_CTL_DDI(port)) | + CTL_LINK_ENCRYPTION_REQ); + } + + ret = intel_wait_for_register(dev_priv, HDCP2_STATUS_DDI(port), + LINK_ENCRYPTION_STATUS, + LINK_ENCRYPTION_STATUS, + TIME_FOR_ENCRYPT_STATUS_CHANGE); + + return ret; }
static int hdcp2_disable_encryption(struct intel_connector *connector) { - return 0; + 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; + + WARN_ON(!(I915_READ(HDCP2_STATUS_DDI(port)) & LINK_ENCRYPTION_STATUS)); + + I915_WRITE(HDCP2_CTL_DDI(port), + I915_READ(HDCP2_CTL_DDI(port)) & ~CTL_LINK_ENCRYPTION_REQ); + + ret = intel_wait_for_register(dev_priv, HDCP2_STATUS_DDI(port), + LINK_ENCRYPTION_STATUS, 0x0, + TIME_FOR_ENCRYPT_STATUS_CHANGE); + if (ret == -ETIMEDOUT) + DRM_DEBUG_KMS("Disable Encryption Timedout"); + + if (hdcp->hdcp_shim->toggle_signalling) + hdcp->hdcp_shim->toggle_signalling(intel_dig_port, false); + + return ret; }
static int hdcp2_authenticate_and_encrypt(struct intel_connector *connector)
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_shim defined.
v2: Rebased. v3: No Changes. v4: %s/PARING/PAIRING Coding style fixing [Uma] v5: Rebased as part of patch reordering. Defined the functions for mei services. [Daniel]
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 400 +++++++++++++++++++++++++++++++++++++- 1 file changed, 399 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 1e75b4fc978a..bb6e72807060 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -18,6 +18,7 @@
#define KEY_LOAD_TRIES 5 #define TIME_FOR_ENCRYPT_STATUS_CHANGE 32 +#define HDCP2_LC_RETRY_CNT 3 #define GET_MEI_DDI_INDEX(port) (((port) == PORT_A) ? DDI_A : \ (enum hdcp_physical_port)(port))
@@ -995,6 +996,222 @@ int intel_hdcp_check_link(struct intel_connector *connector) return ret; }
+static int +hdcp2_prepare_ake_init(struct intel_connector *connector, + struct hdcp2_ake_init *ake_data) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + if (data->port == INVALID_PORT && connector->encoder) + data->port = GET_MEI_DDI_INDEX(connector->encoder->port); + + /* Clear ME FW instance for the port, just incase */ + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + ret = comp->ops->initiate_hdcp2_session(comp->mei_cldev, + data, ake_data); + mutex_unlock(&comp->mutex); + + return ret; +} + +static int +hdcp2_verify_rx_cert_prepare_km(struct intel_connector *connector, + struct hdcp2_ake_send_cert *rx_cert, + bool *paired, + struct hdcp2_ake_no_stored_km *ek_pub_km, + size_t *msg_sz) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->verify_receiver_cert_prepare_km(comp->mei_cldev, data, + rx_cert, paired, + ek_pub_km, msg_sz); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int hdcp2_verify_hprime(struct intel_connector *connector, + struct hdcp2_ake_send_hprime *rx_hprime) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->verify_hprime(comp->mei_cldev, data, rx_hprime); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int +hdcp2_store_pairing_info(struct intel_connector *connector, + struct hdcp2_ake_send_pairing_info *pairing_info) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->store_pairing_info(comp->mei_cldev, + data, pairing_info); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int +hdcp2_prepare_lc_init(struct intel_connector *connector, + struct hdcp2_lc_init *lc_init) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->initiate_locality_check(comp->mei_cldev, + data, lc_init); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int +hdcp2_verify_lprime(struct intel_connector *connector, + struct hdcp2_lc_send_lprime *rx_lprime) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->verify_lprime(comp->mei_cldev, data, rx_lprime); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int hdcp2_prepare_skey(struct intel_connector *connector, + struct hdcp2_ske_send_eks *ske_data) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->get_session_key(comp->mei_cldev, data, ske_data); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + +static int hdcp2_authenticate_port(struct intel_connector *connector) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->enable_hdcp_authentication(comp->mei_cldev, data); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + return ret; +} + static int hdcp2_close_mei_session(struct intel_connector *connector) { struct mei_hdcp_data *data = &connector->hdcp.mei_data; @@ -1021,11 +1238,192 @@ static int hdcp2_deauthenticate_port(struct intel_connector *connector) return hdcp2_close_mei_session(connector); }
-static int hdcp2_authenticate_sink(struct intel_connector *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->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->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->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) +{ + 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->hdcp_shim; + struct hdcp2_dp_errata_stream_type stream_type_msg; + int ret; + + 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 (!hdcp->is_repeater && shim->config_stream_type) { + /* + * Errata for DP: As Stream type is used for encryption, + * Receiver should be communicated with stream type for the + * decryption of the content. + * Repeater will be communicated with stream type as a + * part of it's auth later in time. + */ + stream_type_msg.msg_id = HDCP_2_2_ERRATA_DP_STREAM_TYPE; + stream_type_msg.stream_type = hdcp->content_type; + + ret = shim->config_stream_type(intel_dig_port, &stream_type_msg, + sizeof(stream_type_msg)); + if (ret < 0) + return ret; + } + + hdcp->mei_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) { struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
Implements the HDCP2.2 repeaters authentication steps such as verifying the downstream topology and sending stream management information.
v2: Rebased. v3: No Changes. v4: -EINVAL is returned for topology error and rollover scenario. Endianness conversion func from drm_hdcp.h is used [Uma] v5: Rebased as part of patches reordering. Defined the mei service functions [Daniel]
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 178 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_hdcp.h | 15 ++++ 2 files changed, 193 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index bb6e72807060..cf1c5f20b62e 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -1188,6 +1188,63 @@ static int hdcp2_prepare_skey(struct intel_connector *connector, return ret; }
+static int +hdcp2_verify_rep_topology_prepare_ack( + struct intel_connector *connector, + struct hdcp2_rep_send_receiverid_list *rep_topology, + struct hdcp2_rep_send_ack *rep_send_ack) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->repeater_check_flow_prepare_ack(comp->mei_cldev, data, + rep_topology, rep_send_ack); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + + return ret; +} + +static int +hdcp2_verify_mprime(struct intel_connector *connector, + struct hdcp2_rep_stream_ready *stream_ready) +{ + struct mei_hdcp_data *data = &connector->hdcp.mei_data; + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + struct i915_hdcp_component *comp = dev_priv->hdcp_comp; + int ret; + + if (!comp) + return -EINVAL; + + mutex_lock(&comp->mutex); + if (!comp->ops || !comp->mei_cldev || data->port == INVALID_PORT) { + mutex_unlock(&comp->mutex); + return -EINVAL; + } + + ret = comp->ops->verify_mprime(comp->mei_cldev, data, stream_ready); + if (ret < 0) + comp->ops->close_hdcp_session(comp->mei_cldev, data); + + mutex_unlock(&comp->mutex); + + return ret; +} + static int hdcp2_authenticate_port(struct intel_connector *connector) { struct mei_hdcp_data *data = &connector->hdcp.mei_data; @@ -1373,6 +1430,121 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector) return 0; }
+static +int hdcp2_propagate_stream_management_info(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_rep_stream_manage stream_manage; + struct hdcp2_rep_stream_ready stream_ready; + } msgs; + const struct intel_hdcp_shim *shim = hdcp->hdcp_shim; + int ret; + + /* Prepare RepeaterAuth_Stream_Manage msg */ + msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE; + reverse_endianness(msgs.stream_manage.seq_num_m, HDCP_2_2_SEQ_NUM_LEN, + (u8 *)&hdcp->seq_num_m); + + /* K no of streams is fixed as 1. Stored as big-endian. */ + msgs.stream_manage.k = __swab16(1); + + /* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */ + msgs.stream_manage.streams[0].stream_id = 0; + msgs.stream_manage.streams[0].stream_type = hdcp->content_type; + + /* Send it to Repeater */ + ret = shim->write_2_2_msg(intel_dig_port, &msgs.stream_manage, + sizeof(msgs.stream_manage)); + if (ret < 0) + return ret; + + ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_REP_STREAM_READY, + &msgs.stream_ready, sizeof(msgs.stream_ready)); + if (ret < 0) + return ret; + + hdcp->mei_data.seq_num_m = hdcp->seq_num_m; + hdcp->mei_data.streams[0].stream_type = hdcp->content_type; + + ret = hdcp2_verify_mprime(connector, &msgs.stream_ready); + if (ret < 0) + return ret; + + hdcp->seq_num_m++; + + if (hdcp->seq_num_m > HDCP_2_2_SEQ_NUM_MAX) { + DRM_DEBUG_KMS("seq_num_m roll over.\n"); + return -1; + } + + return 0; +} + +static +int hdcp2_authenticate_repeater_topology(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_rep_send_receiverid_list recvid_list; + struct hdcp2_rep_send_ack rep_ack; + } msgs; + const struct intel_hdcp_shim *shim = hdcp->hdcp_shim; + uint8_t *rx_info; + uint32_t seq_num_v; + int ret; + + ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_REP_SEND_RECVID_LIST, + &msgs.recvid_list, sizeof(msgs.recvid_list)); + if (ret < 0) + return ret; + + rx_info = msgs.recvid_list.rx_info; + + if (HDCP_2_2_MAX_CASCADE_EXCEEDED(rx_info[1]) || + HDCP_2_2_MAX_DEVS_EXCEEDED(rx_info[1])) { + DRM_DEBUG_KMS("Topology Max Size Exceeded\n"); + return -EINVAL; + } + + /* Converting and Storing the seq_num_v to local variable as DWORD */ + reverse_endianness((u8 *)&seq_num_v, HDCP_2_2_SEQ_NUM_LEN, + msgs.recvid_list.seq_num_v); + + if (seq_num_v < hdcp->seq_num_v) { + /* Roll over of the seq_num_v from repeater. Reauthenticate. */ + DRM_DEBUG_KMS("Seq_num_v roll over.\n"); + return -EINVAL; + } + + ret = hdcp2_verify_rep_topology_prepare_ack(connector, + &msgs.recvid_list, + &msgs.rep_ack); + if (ret < 0) + return ret; + + hdcp->seq_num_v = seq_num_v; + ret = shim->write_2_2_msg(intel_dig_port, &msgs.rep_ack, + sizeof(msgs.rep_ack)); + if (ret < 0) + return ret; + + return 0; +} + +static int hdcp2_authenticate_repeater(struct intel_connector *connector) +{ + int ret; + + ret = hdcp2_authenticate_repeater_topology(connector); + if (ret < 0) + return ret; + + return hdcp2_propagate_stream_management_info(connector); +} + static int hdcp2_authenticate_sink(struct intel_connector *connector) { struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); @@ -1414,6 +1586,12 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector) sizeof(stream_type_msg)); if (ret < 0) return ret; + } else if (hdcp->is_repeater) { + ret = hdcp2_authenticate_repeater(connector); + if (ret < 0) { + DRM_DEBUG_KMS("Repeater Auth Failed. Err: %d\n", ret); + return ret; + } }
hdcp->mei_data.streams[0].stream_type = hdcp->content_type; diff --git a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 2fc6311dc060..0c222b5b685c 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -247,4 +247,19 @@ struct hdcp2_dp_errata_stream_type { #define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) #define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3))
+/* + * Library functions for endianness are aligned for 16/32/64 bits. + * But hdcp sequence numbers are 24bits. So for their Byte swapping, + * a conversion function is developed. + */ +static inline void reverse_endianness(u8 *dest, size_t sz, u8 *src) +{ + u32 index; + + if (!sz || sz > sizeof(u32)) + return; + for (index = 0; index < sz; index++) + dest[sz - index - 1] = src[index]; +} + #endif
Hi Ramalingam,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on v4.18-rc2 next-20180627] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ramalingam-C/drm-i915-Implement-HDC... base: git://anongit.freedesktop.org/drm-intel for-linux-next reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
drivers/gpu/drm/i915/i915_drv.h:3674:16: sparse: expression using sizeof(void)
drivers/gpu/drm/i915/intel_hdcp.c:1451:30: sparse: incorrect type in assignment (different base types) @@ expected restricted __be16 [assigned] [usertype] k @@ got e] k @@
drivers/gpu/drm/i915/intel_hdcp.c:1451:30: expected restricted __be16 [assigned] [usertype] k drivers/gpu/drm/i915/intel_hdcp.c:1451:30: got int drivers/gpu/drm/i915/intel_hdcp.c:1890:6: sparse: symbol 'is_hdcp2_supported' was not declared. Should it be static?
vim +1451 drivers/gpu/drm/i915/intel_hdcp.c
1432 1433 static 1434 int hdcp2_propagate_stream_management_info(struct intel_connector *connector) 1435 { 1436 struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); 1437 struct intel_hdcp *hdcp = &connector->hdcp; 1438 union { 1439 struct hdcp2_rep_stream_manage stream_manage; 1440 struct hdcp2_rep_stream_ready stream_ready; 1441 } msgs; 1442 const struct intel_hdcp_shim *shim = hdcp->hdcp_shim; 1443 int ret; 1444 1445 /* Prepare RepeaterAuth_Stream_Manage msg */ 1446 msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE; 1447 reverse_endianness(msgs.stream_manage.seq_num_m, HDCP_2_2_SEQ_NUM_LEN, 1448 (u8 *)&hdcp->seq_num_m); 1449 1450 /* K no of streams is fixed as 1. Stored as big-endian. */
1451 msgs.stream_manage.k = __swab16(1);
1452 1453 /* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */ 1454 msgs.stream_manage.streams[0].stream_id = 0; 1455 msgs.stream_manage.streams[0].stream_type = hdcp->content_type; 1456 1457 /* Send it to Repeater */ 1458 ret = shim->write_2_2_msg(intel_dig_port, &msgs.stream_manage, 1459 sizeof(msgs.stream_manage)); 1460 if (ret < 0) 1461 return ret; 1462 1463 ret = shim->read_2_2_msg(intel_dig_port, HDCP_2_2_REP_STREAM_READY, 1464 &msgs.stream_ready, sizeof(msgs.stream_ready)); 1465 if (ret < 0) 1466 return ret; 1467 1468 hdcp->mei_data.seq_num_m = hdcp->seq_num_m; 1469 hdcp->mei_data.streams[0].stream_type = hdcp->content_type; 1470 1471 ret = hdcp2_verify_mprime(connector, &msgs.stream_ready); 1472 if (ret < 0) 1473 return ret; 1474 1475 hdcp->seq_num_m++; 1476 1477 if (hdcp->seq_num_m > HDCP_2_2_SEQ_NUM_MAX) { 1478 DRM_DEBUG_KMS("seq_num_m roll over.\n"); 1479 return -1; 1480 } 1481 1482 return 0; 1483 } 1484
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Implements the link integrity check once in 500mSec.
Once encryption is enabled, an ongoing Link Integrity Check is performed by the HDCP Receiver to check that cipher synchronization is maintained between the HDCP Transmitter and the HDCP Receiver.
On the detection of synchronization lost, the HDCP Receiver must assert the corresponding bits of the RxStatus register. The Transmitter polls the RxStatus register and it may initiate re-authentication.
v2: Rebased. v3: No Changes. v4: enum check_link_response is used check the link status [Uma] v5: Rebased as part of patch reordering.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 82 +++++++++++++++++++++++++++++++++++++++ include/drm/drm_hdcp.h | 8 ++++ 2 files changed, 90 insertions(+)
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
When repeater notifies a downstream topology change, this patch reauthenticate the repeater alone without disabling the hdcp encryption. If that fails then complete reauthentication is executed.
v2: Rebased. v3: No Changes. v4: Typo in commit msg is fixed [Uma] v5: Rebased as part of patch reordering. Minor style fixes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_hdcp.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index ec840c1178bb..790f4a9f4793 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -1954,8 +1954,23 @@ static int intel_hdcp2_check_link(struct intel_connector *connector) goto out; }
- DRM_ERROR("[%s:%d] HDCP2.2 link failed, retrying auth\n", - connector->base.name, connector->base.base.id); + if (ret == DRM_HDCP_TOPOLOGY_CHANGE) { + if (hdcp->hdcp_value == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) + goto out; + + DRM_DEBUG_KMS("HDCP2.2 Downstream topology change\n"); + ret = hdcp2_authenticate_repeater_topology(connector); + if (!ret) { + hdcp->hdcp_value = DRM_MODE_CONTENT_PROTECTION_ENABLED; + schedule_work(&hdcp->hdcp_prop_work); + goto out; + } + DRM_ERROR("[%s:%d] Repeater topology auth failed.(%d)\n", + connector->base.name, connector->base.base.id, ret); + } else { + 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) {
HDCP check link is invoked only on CP_IRQ detection, instead of all short pulses.
v3: No Changes. v4: Added sean in cc and collected the reviewed-by received. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com cc: Sean Paul seanpaul@chromium.org Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6bcc52766ea3..7467e7b3f2df 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4483,8 +4483,10 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp); - if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ)) - DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); + if (sink_irq_vector & DP_CP_IRQ) + intel_hdcp_check_link(intel_dp->attached_connector); + if (sink_irq_vector & DP_SINK_SPECIFIC_IRQ) + DRM_DEBUG_DRIVER("Sink specific irq unhandled\n"); }
/* defer to the hotplug work for link retraining if needed */ @@ -5454,9 +5456,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
handled = intel_dp_short_pulse(intel_dp);
- /* Short pulse can signify loss of hdcp authentication */ - intel_hdcp_check_link(intel_dp->attached_connector); - if (!handled) { intel_dp->detect_done = false; goto put_power;
On Wed, Jun 27, 2018 at 02:10:08PM +0530, Ramalingam C wrote:
HDCP check link is invoked only on CP_IRQ detection, instead of all short pulses.
v3: No Changes. v4: Added sean in cc and collected the reviewed-by received. v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
Reviewed-by: Sean Paul seanpaul@chromium.org
cc: Sean Paul seanpaul@chromium.org Reviewed-by: Uma Shankar uma.shankar@intel.com
drivers/gpu/drm/i915/intel_dp.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 6bcc52766ea3..7467e7b3f2df 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4483,8 +4483,10 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp);
if (sink_irq_vector & (DP_CP_IRQ | DP_SINK_SPECIFIC_IRQ))
DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
if (sink_irq_vector & DP_CP_IRQ)
intel_hdcp_check_link(intel_dp->attached_connector);
if (sink_irq_vector & DP_SINK_SPECIFIC_IRQ)
DRM_DEBUG_DRIVER("Sink specific irq unhandled\n");
}
/* defer to the hotplug work for link retraining if needed */
@@ -5454,9 +5456,6 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
handled = intel_dp_short_pulse(intel_dp);
/* Short pulse can signify loss of hdcp authentication */
intel_hdcp_check_link(intel_dp->attached_connector);
- if (!handled) { intel_dp->detect_done = false; goto put_power;
-- 2.7.4
On DP HDCP1.4 and 2.2, when CP_IRQ is received, start the link integrity check for the HDCP version that is enabled.
v2: Rebased. Function name is changed. v3: No Changes. v4: No Changes. v5: No Changes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com cc: Sean Paul seanpaul@chromium.org --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_hdcp.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7467e7b3f2df..a6ba27ef20ae 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4484,7 +4484,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp); if (sink_irq_vector & DP_CP_IRQ) - intel_hdcp_check_link(intel_dp->attached_connector); + intel_hdcp_handle_cp_irq(intel_dp->attached_connector); if (sink_irq_vector & DP_SINK_SPECIFIC_IRQ) DRM_DEBUG_DRIVER("Sink specific irq unhandled\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7624388eecd5..875657fd7d3c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1965,8 +1965,8 @@ int intel_hdcp_init(struct intel_connector *connector, bool hdcp2_supported); int intel_hdcp_enable(struct intel_connector *connector); int intel_hdcp_disable(struct intel_connector *connector); -int intel_hdcp_check_link(struct intel_connector *connector); bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port); +void intel_hdcp_handle_cp_irq(struct intel_connector *connector);
/* intel_psr.c */ #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 790f4a9f4793..b035274785c8 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -32,6 +32,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim, u8 *bksv); static struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector); +static int intel_hdcp_check_link(struct intel_connector *connector);
static bool panel_supports_hdcp(struct intel_connector *connector) { @@ -80,6 +81,26 @@ static inline bool intel_hdcp2_capable(struct intel_connector *connector) panel_supports_hdcp2(connector)); }
+static inline bool intel_hdcp_in_force(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum port port = connector->encoder->port; + u32 reg; + + reg = I915_READ(PORT_HDCP_STATUS(port)); + return reg & (HDCP_STATUS_AUTH | HDCP_STATUS_ENC); +} + +static inline bool intel_hdcp2_in_force(struct intel_connector *connector) +{ + struct drm_i915_private *dev_priv = to_i915(connector->base.dev); + enum port port = connector->encoder->port; + u32 reg; + + reg = I915_READ(HDCP2_STATUS_DDI(port)); + return reg & (LINK_ENCRYPTION_STATUS | LINK_AUTH_STATUS); +} + static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) { @@ -939,7 +960,7 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, }
/* Implements Part 3 of the HDCP authorization procedure */ -int intel_hdcp_check_link(struct intel_connector *connector) +static int intel_hdcp_check_link(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; @@ -2011,3 +2032,11 @@ static void intel_hdcp2_check_work(struct work_struct *work) schedule_delayed_work(&hdcp->hdcp2_check_work, DRM_HDCP2_CHECK_PERIOD_MS); } + +void intel_hdcp_handle_cp_irq(struct intel_connector *connector) +{ + if (intel_hdcp_in_force(connector)) + intel_hdcp_check_link(connector); + else if (intel_hdcp2_in_force(connector)) + intel_hdcp2_check_link(connector); +}
On Wed, Jun 27, 2018 at 02:10:09PM +0530, Ramalingam C wrote:
On DP HDCP1.4 and 2.2, when CP_IRQ is received, start the link integrity check for the HDCP version that is enabled.
v2: Rebased. Function name is changed. v3: No Changes. v4: No Changes. v5: No Changes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com cc: Sean Paul seanpaul@chromium.org
drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_hdcp.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7467e7b3f2df..a6ba27ef20ae 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4484,7 +4484,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp); if (sink_irq_vector & DP_CP_IRQ)
intel_hdcp_check_link(intel_dp->attached_connector);
if (sink_irq_vector & DP_SINK_SPECIFIC_IRQ) DRM_DEBUG_DRIVER("Sink specific irq unhandled\n"); }intel_hdcp_handle_cp_irq(intel_dp->attached_connector);
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7624388eecd5..875657fd7d3c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1965,8 +1965,8 @@ int intel_hdcp_init(struct intel_connector *connector, bool hdcp2_supported); int intel_hdcp_enable(struct intel_connector *connector); int intel_hdcp_disable(struct intel_connector *connector); -int intel_hdcp_check_link(struct intel_connector *connector); bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port); +void intel_hdcp_handle_cp_irq(struct intel_connector *connector);
/* intel_psr.c */ #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 790f4a9f4793..b035274785c8 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -32,6 +32,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim, u8 *bksv); static struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector); +static int intel_hdcp_check_link(struct intel_connector *connector);
static bool panel_supports_hdcp(struct intel_connector *connector) { @@ -80,6 +81,26 @@ static inline bool intel_hdcp2_capable(struct intel_connector *connector) panel_supports_hdcp2(connector)); }
+static inline bool intel_hdcp_in_force(struct intel_connector *connector)
nit: I'd use _in_use instead of in_force
With that fixed,
Reviewed-by: Sean Paul seanpaul@chromium.org
+{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- enum port port = connector->encoder->port;
- u32 reg;
- reg = I915_READ(PORT_HDCP_STATUS(port));
- return reg & (HDCP_STATUS_AUTH | HDCP_STATUS_ENC);
+}
+static inline bool intel_hdcp2_in_force(struct intel_connector *connector) +{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- enum port port = connector->encoder->port;
- u32 reg;
- reg = I915_READ(HDCP2_STATUS_DDI(port));
- return reg & (LINK_ENCRYPTION_STATUS | LINK_AUTH_STATUS);
+}
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) { @@ -939,7 +960,7 @@ void intel_hdcp_atomic_check(struct drm_connector *connector, }
/* Implements Part 3 of the HDCP authorization procedure */ -int intel_hdcp_check_link(struct intel_connector *connector) +static int intel_hdcp_check_link(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; @@ -2011,3 +2032,11 @@ static void intel_hdcp2_check_work(struct work_struct *work) schedule_delayed_work(&hdcp->hdcp2_check_work, DRM_HDCP2_CHECK_PERIOD_MS); }
+void intel_hdcp_handle_cp_irq(struct intel_connector *connector) +{
- if (intel_hdcp_in_force(connector))
intel_hdcp_check_link(connector);
- else if (intel_hdcp2_in_force(connector))
intel_hdcp2_check_link(connector);
+}
2.7.4
-----Original Message----- From: Sean Paul [mailto:seanpaul@chromium.org] Sent: Tuesday, July 10, 2018 2:21 AM To: C, Ramalingam ramalingam.c@intel.com Cc: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com; chris@chris-wilson.co.uk; jani.nikula@linux.intel.com; Sharma, Shashank shashank.sharma@intel.com; Sean Paul seanpaul@chromium.org Subject: Re: [PATCH v5 20/40] drm/i915: Check HDCP 1.4 and 2.2 link on CP_IRQ
On Wed, Jun 27, 2018 at 02:10:09PM +0530, Ramalingam C wrote:
On DP HDCP1.4 and 2.2, when CP_IRQ is received, start the link integrity check for the HDCP version that is enabled.
v2: Rebased. Function name is changed. v3: No Changes. v4: No Changes. v5: No Changes.
Signed-off-by: Ramalingam C ramalingam.c@intel.com cc: Sean Paul seanpaul@chromium.org
drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 2 +- drivers/gpu/drm/i915/intel_hdcp.c | 31 ++++++++++++++++++++++++++++++- 3 files changed, 32 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index 7467e7b3f2df..a6ba27ef20ae 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -4484,7 +4484,7 @@ intel_dp_short_pulse(struct intel_dp *intel_dp) if (sink_irq_vector & DP_AUTOMATED_TEST_REQUEST) intel_dp_handle_test_request(intel_dp); if (sink_irq_vector & DP_CP_IRQ)
intel_hdcp_check_link(intel_dp->attached_connector);
intel_hdcp_handle_cp_irq(intel_dp-
attached_connector); if (sink_irq_vector & DP_SINK_SPECIFIC_IRQ) DRM_DEBUG_DRIVER("Sink specific irq unhandled\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 7624388eecd5..875657fd7d3c 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1965,8 +1965,8 @@ int intel_hdcp_init(struct intel_connector
*connector,
bool hdcp2_supported);
int intel_hdcp_enable(struct intel_connector *connector); int intel_hdcp_disable(struct intel_connector *connector); -int intel_hdcp_check_link(struct intel_connector *connector); bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port); +void intel_hdcp_handle_cp_irq(struct intel_connector *connector);
/* intel_psr.c */ #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support) diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 790f4a9f4793..b035274785c8 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -32,6 +32,7 @@ int intel_hdcp_read_valid_bksv(struct intel_digital_port
*intel_dig_port,
const struct intel_hdcp_shim *shim, u8 *bksv);
static
struct intel_digital_port *conn_to_dig_port(struct intel_connector *connector); +static int intel_hdcp_check_link(struct intel_connector *connector);
static bool panel_supports_hdcp(struct intel_connector *connector) { @@ -80,6 +81,26 @@ static inline bool intel_hdcp2_capable(struct
intel_connector *connector)
panel_supports_hdcp2(connector));
}
+static inline bool intel_hdcp_in_force(struct intel_connector +*connector)
nit: I'd use _in_use instead of in_force
Sure I will rename it.
With that fixed,
Reviewed-by: Sean Paul seanpaul@chromium.org
Thanks, Ram.
+{
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- enum port port = connector->encoder->port;
- u32 reg;
- reg = I915_READ(PORT_HDCP_STATUS(port));
- return reg & (HDCP_STATUS_AUTH | HDCP_STATUS_ENC); }
+static inline bool intel_hdcp2_in_force(struct intel_connector +*connector) {
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- enum port port = connector->encoder->port;
- u32 reg;
- reg = I915_READ(HDCP2_STATUS_DDI(port));
- return reg & (LINK_ENCRYPTION_STATUS | LINK_AUTH_STATUS); }
static int intel_hdcp_poll_ksv_fifo(struct intel_digital_port *intel_dig_port, const struct intel_hdcp_shim *shim) { @@ -
939,7 +960,7 @@
void intel_hdcp_atomic_check(struct drm_connector *connector, }
/* Implements Part 3 of the HDCP authorization procedure */ -int intel_hdcp_check_link(struct intel_connector *connector) +static int intel_hdcp_check_link(struct intel_connector *connector) { struct intel_hdcp *hdcp = &connector->hdcp; struct drm_i915_private *dev_priv = connector->base.dev->dev_private; @@ -2011,3 +2032,11 @@ static void
intel_hdcp2_check_work(struct work_struct *work)
schedule_delayed_work(&hdcp->hdcp2_check_work, DRM_HDCP2_CHECK_PERIOD_MS); }
+void intel_hdcp_handle_cp_irq(struct intel_connector *connector) {
- if (intel_hdcp_in_force(connector))
intel_hdcp_check_link(connector);
- else if (intel_hdcp2_in_force(connector))
intel_hdcp2_check_link(connector);
+}
2.7.4
-- Sean Paul, Software Engineer, Google / Chromium OS
GMBUS HW supports 511Bytes as Max Bytes per single RD/WR op. Instead of enabling the 511Bytes per RD/WR cycle on legacy platforms for no absolute ROIs, this change allows the max bytes per op upto 511Bytes from Gen9 onwards.
v2: No Change. v3: Inline function for max_xfer_size and renaming of the macro.[Jani] v4: Extra brackets removed [ville] Commit msg is modified. v5: Adding the Reviewed-By received. v6: No Change.
Cc: Jani Nikula jani.nikula@intel.com Cc: Chris Wilson chris@chris-wilson.co.uk Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Jani Nikula jani.nikula@intel.com --- drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_i2c.c | 11 +++++++++-- 2 files changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 822fee56931e..91d42b3e39ad 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3049,6 +3049,7 @@ enum i915_power_well_id { #define GMBUS_CYCLE_STOP (4 << 25) #define GMBUS_BYTE_COUNT_SHIFT 16 #define GMBUS_BYTE_COUNT_MAX 256U +#define GEN9_GMBUS_BYTE_COUNT_MAX 511U #define GMBUS_SLAVE_INDEX_SHIFT 8 #define GMBUS_SLAVE_ADDR_SHIFT 1 #define GMBUS_SLAVE_READ (1 << 0) diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 97606c1be70d..82bb9c33ab1c 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -361,6 +361,13 @@ gmbus_wait_idle(struct drm_i915_private *dev_priv) return ret; }
+static inline +unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv) +{ + return INTEL_GEN(dev_priv) >= 9 ? GEN9_GMBUS_BYTE_COUNT_MAX : + GMBUS_BYTE_COUNT_MAX; +} + static int gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, unsigned short addr, u8 *buf, unsigned int len, @@ -400,7 +407,7 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret;
do { - len = min(rx_size, GMBUS_BYTE_COUNT_MAX); + len = min(rx_size, gmbus_max_xfer_size(dev_priv));
ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len, gmbus1_index); @@ -462,7 +469,7 @@ gmbus_xfer_write(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret;
do { - len = min(tx_size, GMBUS_BYTE_COUNT_MAX); + len = min(tx_size, gmbus_max_xfer_size(dev_priv));
ret = gmbus_xfer_write_chunk(dev_priv, msg->addr, buf, len, gmbus1_index);
Support for Burst read in HW is added for HDCP2.2 compliance requirement.
This patch enables the burst read for all the gmbus read of more than 511Bytes, on capable platforms.
v2: Extra line is removed. v3: Macro is added for detecting the BURST_READ Support [Jani] Runtime detection of the need for burst_read [Jani] Calculation enhancement. v4: GMBUS0 reg val is passed from caller [ville] Removed a extra var [ville] Extra brackets are removed [ville] Implemented the handling of 512Bytes Burst Read. v5: Burst read max length is fixed at 767Bytes [Ville] v6: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/i915_drv.h | 3 ++ drivers/gpu/drm/i915/i915_reg.h | 1 + drivers/gpu/drm/i915/intel_i2c.c | 62 +++++++++++++++++++++++++++++++++------- 3 files changed, 56 insertions(+), 10 deletions(-)
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 0e6fe140dc63..65323f61e590 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2584,6 +2584,9 @@ intel_info(const struct drm_i915_private *dev_priv) IS_SKL_GT3(dev_priv) || IS_SKL_GT4(dev_priv))
#define HAS_GMBUS_IRQ(dev_priv) (INTEL_GEN(dev_priv) >= 4) +#define HAS_GMBUS_BURST_READ(dev_priv) (INTEL_GEN(dev_priv) >= 10 || \ + IS_GEMINILAKE(dev_priv) || \ + IS_KABYLAKE(dev_priv))
/* With the 945 and later, Y tiling got adjusted so that it was 32 128-byte * rows, which changed the alignment requirements and fence programming. diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 91d42b3e39ad..1386356bcfc4 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h @@ -3020,6 +3020,7 @@ enum i915_power_well_id { #define GMBUS_RATE_400KHZ (2 << 8) /* reserved on Pineview */ #define GMBUS_RATE_1MHZ (3 << 8) /* reserved on Pineview */ #define GMBUS_HOLD_EXT (1 << 7) /* 300ns hold time, rsvd on Pineview */ +#define GMBUS_BYTE_CNT_OVERRIDE (1 << 6) #define GMBUS_PIN_DISABLED 0 #define GMBUS_PIN_SSC 1 #define GMBUS_PIN_VGADDC 2 diff --git a/drivers/gpu/drm/i915/intel_i2c.c b/drivers/gpu/drm/i915/intel_i2c.c index 82bb9c33ab1c..3957988e46d1 100644 --- a/drivers/gpu/drm/i915/intel_i2c.c +++ b/drivers/gpu/drm/i915/intel_i2c.c @@ -371,12 +371,30 @@ unsigned int gmbus_max_xfer_size(struct drm_i915_private *dev_priv) static int gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv, unsigned short addr, u8 *buf, unsigned int len, - u32 gmbus1_index) + u32 gmbus0_reg, u32 gmbus1_index) { + unsigned int size = len; + bool burst_read = len > gmbus_max_xfer_size(dev_priv); + bool extra_byte_added = false; + + if (burst_read) { + + /* + * As per HW Spec, for 512Bytes need to read extra Byte and + * Ignore the extra byte read. + */ + if (len == 512) { + extra_byte_added = true; + len++; + } + size = len % 256 + 256; + I915_WRITE_FW(GMBUS0, gmbus0_reg | GMBUS_BYTE_CNT_OVERRIDE); + } + I915_WRITE_FW(GMBUS1, gmbus1_index | GMBUS_CYCLE_WAIT | - (len << GMBUS_BYTE_COUNT_SHIFT) | + (size << GMBUS_BYTE_COUNT_SHIFT) | (addr << GMBUS_SLAVE_ADDR_SHIFT) | GMBUS_SLAVE_READ | GMBUS_SW_RDY); while (len) { @@ -389,17 +407,34 @@ gmbus_xfer_read_chunk(struct drm_i915_private *dev_priv,
val = I915_READ_FW(GMBUS3); do { + if (extra_byte_added && len == 1) + break; + *buf++ = val & 0xff; val >>= 8; } while (--len && ++loop < 4); + + if (burst_read && len == size - 4) + /* Reset the override bit */ + I915_WRITE_FW(GMBUS0, gmbus0_reg); }
return 0; }
+/* + * HW spec says that 512Bytes in Burst read need special treatment. + * But it doesn't talk about other multiple of 256Bytes. And couldn't locate + * an I2C slave, which supports such a lengthy burst read too for experiments. + * + * So until things get clarified on HW support, to avoid the burst read length + * in fold of 256Bytes except 512, max burst read length is fixed at 767Bytes. + */ +#define INTEL_GMBUS_BURST_READ_MAX_LEN 767U + static int gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, - u32 gmbus1_index) + u32 gmbus0_reg, u32 gmbus1_index) { u8 *buf = msg->buf; unsigned int rx_size = msg->len; @@ -407,10 +442,13 @@ gmbus_xfer_read(struct drm_i915_private *dev_priv, struct i2c_msg *msg, int ret;
do { - len = min(rx_size, gmbus_max_xfer_size(dev_priv)); + if (HAS_GMBUS_BURST_READ(dev_priv)) + len = min(rx_size, INTEL_GMBUS_BURST_READ_MAX_LEN); + else + len = min(rx_size, gmbus_max_xfer_size(dev_priv));
- ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, - buf, len, gmbus1_index); + ret = gmbus_xfer_read_chunk(dev_priv, msg->addr, buf, len, + gmbus0_reg, gmbus1_index); if (ret) return ret;
@@ -498,7 +536,8 @@ gmbus_is_index_xfer(struct i2c_msg *msgs, int i, int num) }
static int -gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) +gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs, + u32 gmbus0_reg) { u32 gmbus1_index = 0; u32 gmbus5 = 0; @@ -516,7 +555,8 @@ gmbus_index_xfer(struct drm_i915_private *dev_priv, struct i2c_msg *msgs) I915_WRITE_FW(GMBUS5, gmbus5);
if (msgs[1].flags & I2C_M_RD) - ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus1_index); + ret = gmbus_xfer_read(dev_priv, &msgs[1], gmbus0_reg, + gmbus1_index); else ret = gmbus_xfer_write(dev_priv, &msgs[1], gmbus1_index);
@@ -551,10 +591,12 @@ do_gmbus_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int num, for (; i < num; i += inc) { inc = 1; if (gmbus_is_index_xfer(msgs, i, num)) { - ret = gmbus_index_xfer(dev_priv, &msgs[i]); + ret = gmbus_index_xfer(dev_priv, &msgs[i], + gmbus0_source | bus->reg0); inc = 2; /* an index transmission is two msgs */ } else if (msgs[i].flags & I2C_M_RD) { - ret = gmbus_xfer_read(dev_priv, &msgs[i], 0); + ret = gmbus_xfer_read(dev_priv, &msgs[i], + gmbus0_source | bus->reg0, 0); } else { ret = gmbus_xfer_write(dev_priv, &msgs[i], 0); }
Implements the DP adaptation specific HDCP2.2 functions.
These functions perform the DPCD read and write for communicating the HDCP2.2 auth message back and forth.
Note: Chris Wilson suggested alternate method for waiting for CP_IRQ, than completions concept. WIP to understand and implement that, if needed. Just to unblock the review of other changes, v2 still continues with completions.
v2: wait for cp_irq is merged with this patch. Rebased. v3: wait_queue is used for wait for cp_irq [Chris Wilson] v4: Style fixed. %s/PARING/PAIRING Few style fixes [Uma] v5: Lookup table for DP HDCP2.2 msg details [Daniel]. Extra lines are removed.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 333 ++++++++++++++++++++++++++++++++++++++ drivers/gpu/drm/i915/intel_drv.h | 7 + drivers/gpu/drm/i915/intel_hdcp.c | 5 + 3 files changed, 345 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index a6ba27ef20ae..c8974a7d2d37 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -31,6 +31,7 @@ #include <linux/types.h> #include <linux/notifier.h> #include <linux/reboot.h> +#include <linux/mei_hdcp.h> #include <asm/byteorder.h> #include <drm/drmP.h> #include <drm/drm_atomic_helper.h> @@ -5086,6 +5087,27 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) pps_unlock(intel_dp); }
+static int intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, + int timeout) +{ + long ret; + + /* Reinit */ + atomic_set(&hdcp->cp_irq_recved, 0); + +#define C (atomic_read(&hdcp->cp_irq_recved) > 0) + ret = wait_event_interruptible_timeout(hdcp->cp_irq_queue, C, + msecs_to_jiffies(timeout)); + + if (ret > 0) { + atomic_set(&hdcp->cp_irq_recved, 0); + return 0; + } else if (!ret) { + return -ETIMEDOUT; + } + return (int)ret; +} + static int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port, u8 *an) @@ -5304,6 +5326,311 @@ int intel_dp_hdcp_capable(struct intel_digital_port *intel_dig_port, return 0; }
+static struct hdcp2_dp_msg_data { + uint8_t msg_id; + uint32_t offset; + bool msg_detectable; + uint32_t timeout; + uint32_t timeout2; /* Added for non_paired situation */ + } hdcp2_msg_data[] = { + {HDCP_2_2_AKE_INIT, DP_HDCP_2_2_AKE_INIT_OFFSET, false, 0, 0}, + {HDCP_2_2_AKE_SEND_CERT, DP_HDCP_2_2_AKE_SEND_CERT_OFFSET, + false, HDCP_2_2_CERT_TIMEOUT, 0}, + {HDCP_2_2_AKE_NO_STORED_KM, DP_HDCP_2_2_AKE_NO_STORED_KM_OFFSET, + false, 0, 0}, + {HDCP_2_2_AKE_STORED_KM, DP_HDCP_2_2_AKE_STORED_KM_OFFSET, + false, 0, 0}, + {HDCP_2_2_AKE_SEND_HPRIME, DP_HDCP_2_2_AKE_SEND_HPRIME_OFFSET, + true, HDCP_2_2_HPRIME_PAIRED_TIMEOUT, + HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT}, + {HDCP_2_2_AKE_SEND_PAIRING_INFO, + DP_HDCP_2_2_AKE_SEND_PAIRING_INFO_OFFSET, true, + HDCP_2_2_PAIRING_TIMEOUT, 0}, + {HDCP_2_2_LC_INIT, DP_HDCP_2_2_LC_INIT_OFFSET, false, 0, 0}, + {HDCP_2_2_LC_SEND_LPRIME, DP_HDCP_2_2_LC_SEND_LPRIME_OFFSET, + false, HDCP_2_2_DP_LPRIME_TIMEOUT, 0}, + {HDCP_2_2_SKE_SEND_EKS, DP_HDCP_2_2_SKE_SEND_EKS_OFFSET, false, + 0, 0}, + {HDCP_2_2_REP_SEND_RECVID_LIST, + DP_HDCP_2_2_REP_SEND_RECVID_LIST_OFFSET, true, + HDCP_2_2_RECVID_LIST_TIMEOUT, 0}, + {HDCP_2_2_REP_SEND_ACK, DP_HDCP_2_2_REP_SEND_ACK_OFFSET, false, + 0, 0}, + {HDCP_2_2_REP_STREAM_MANAGE, + DP_HDCP_2_2_REP_STREAM_MANAGE_OFFSET, false, + 0, 0}, + {HDCP_2_2_REP_STREAM_READY, DP_HDCP_2_2_REP_STREAM_READY_OFFSET, + false, HDCP_2_2_STREAM_READY_TIMEOUT, 0}, + {HDCP_2_2_ERRATA_DP_STREAM_TYPE, + DP_HDCP_2_2_REG_STREAM_TYPE_OFFSET, false, + 0, 0}, + }; + +static inline +int intel_dp_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port, + uint8_t *rx_status) +{ + ssize_t ret; + + ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, + DP_HDCP_2_2_REG_RXSTATUS_OFFSET, rx_status, + HDCP_2_2_DP_RXSTATUS_LEN); + if (ret != HDCP_2_2_DP_RXSTATUS_LEN) { + DRM_ERROR("Read bstatus from DP/AUX failed (%zd)\n", ret); + return ret >= 0 ? -EIO : ret; + } + + return 0; +} + +static +int hdcp2_detect_msg_availability(struct intel_digital_port *intel_dig_port, + uint8_t msg_id, bool *msg_ready) +{ + uint8_t rx_status; + int ret; + + *msg_ready = false; + ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status); + if (ret < 0) + return ret; + + switch (msg_id) { + case HDCP_2_2_AKE_SEND_HPRIME: + if (HDCP_2_2_DP_RXSTATUS_H_PRIME(rx_status)) + *msg_ready = true; + break; + case HDCP_2_2_AKE_SEND_PAIRING_INFO: + if (HDCP_2_2_DP_RXSTATUS_PAIRING(rx_status)) + *msg_ready = true; + break; + case HDCP_2_2_REP_SEND_RECVID_LIST: + if (HDCP_2_2_DP_RXSTATUS_READY(rx_status)) + *msg_ready = true; + break; + default: + DRM_DEBUG_KMS("Unidentified msg_id: %d\n", msg_id); + return -EINVAL; + } + + return 0; +} + +static ssize_t +intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port, + struct hdcp2_dp_msg_data *hdcp2_msg_data) +{ + struct intel_dp *dp = &intel_dig_port->dp; + struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; + int ret, timeout; + bool msg_ready = false; + + if (hdcp2_msg_data->msg_id == HDCP_2_2_AKE_SEND_HPRIME && + !hdcp->is_paired) + timeout = hdcp2_msg_data->timeout2; + else + timeout = hdcp2_msg_data->timeout; + + /* + * There is no way to detect the CERT, LPRIME and STREAM_READY + * availability. So Wait for timeout and read the msg. + */ + if (!hdcp2_msg_data->msg_detectable) { + mdelay(timeout); + ret = 0; + } else { + intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout); + ret = hdcp2_detect_msg_availability(intel_dig_port, + hdcp2_msg_data->msg_id, + &msg_ready); + if (!msg_ready) + ret = -ETIMEDOUT; + } + + if (ret) + DRM_ERROR("msg_id %d, ret %d, timeout(mSec): %d\n", + hdcp2_msg_data->msg_id, ret, timeout); + + return ret; +} + +static struct hdcp2_dp_msg_data *get_hdcp2_dp_msg_data(uint8_t msg_id) +{ + int i; + + for (i = 0; i < sizeof(hdcp2_msg_data); i++) + if (hdcp2_msg_data[i].msg_id == msg_id) + return &hdcp2_msg_data[i]; + + return NULL; +} + +static +int intel_dp_hdcp2_write_msg(struct intel_digital_port *intel_dig_port, + void *buf, size_t size) +{ + unsigned int offset; + uint8_t *byte = buf; + ssize_t ret, bytes_to_write, len; + struct hdcp2_dp_msg_data *hdcp2_msg_data; + + hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte); + if (!hdcp2_msg_data) + return -EINVAL; + + /* No msg_id in DP HDCP2.2 msgs */ + bytes_to_write = size - 1; + byte++; + + while (bytes_to_write) { + len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ? + DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write; + + ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, + hdcp2_msg_data->offset, + (void *)byte, len); + if (ret < 0) + return ret; + + bytes_to_write -= ret; + byte += ret; + offset += ret; + } + + return size; +} + +static +ssize_t get_receiver_id_list_size(struct intel_digital_port *intel_dig_port) +{ + uint8_t rx_info[HDCP_2_2_RXINFO_LEN]; + uint32_t dev_cnt; + ssize_t ret; + + ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, + DP_HDCP_2_2_REG_RXINFO_OFFSET, + (void *)rx_info, HDCP_2_2_RXINFO_LEN); + if (ret != HDCP_2_2_RXINFO_LEN) + return ret >= 0 ? -EIO : ret; + + dev_cnt = (HDCP_2_2_DEV_COUNT_HI(rx_info[0]) << 4 | + HDCP_2_2_DEV_COUNT_LO(rx_info[1])); + + if (dev_cnt > HDCP_2_2_MAX_DEVICE_COUNT) + dev_cnt = HDCP_2_2_MAX_DEVICE_COUNT; + + ret = sizeof(struct hdcp2_rep_send_receiverid_list) - + HDCP_2_2_RECEIVER_IDS_MAX_LEN + + (dev_cnt * HDCP_2_2_RECEIVER_ID_LEN); + + return ret; +} + +static +int intel_dp_hdcp2_read_msg(struct intel_digital_port *intel_dig_port, + uint8_t msg_id, void *buf, size_t size) +{ + unsigned int offset; + uint8_t *byte = buf; + ssize_t ret, bytes_to_recv, len; + struct hdcp2_dp_msg_data *hdcp2_msg_data; + + hdcp2_msg_data = get_hdcp2_dp_msg_data(*byte); + if (!hdcp2_msg_data) + return -EINVAL; + offset = hdcp2_msg_data->offset; + + ret = intel_dp_hdcp2_wait_for_msg(intel_dig_port, hdcp2_msg_data); + if (ret < 0) + return ret; + + if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) { + ret = get_receiver_id_list_size(intel_dig_port); + if (ret < 0) + return ret; + + size = ret; + } + bytes_to_recv = size - 1; + + /* DP adaptation msgs has no msg_id */ + byte++; + + while (bytes_to_recv) { + len = bytes_to_recv > DP_AUX_MAX_PAYLOAD_BYTES ? + DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_recv; + + ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, offset, + (void *)byte, len); + if (ret < 0) { + DRM_DEBUG_KMS("msg_id %d, ret %zd\n", msg_id, ret); + return ret; + } + + bytes_to_recv -= ret; + byte += ret; + offset += ret; + } + byte = buf; + *byte = msg_id; + + return size; +} + +static +int intel_dp_hdcp2_config_stream_type(struct intel_digital_port *intel_dig_port, + void *buf, size_t size) +{ + return intel_dp_hdcp2_write_msg(intel_dig_port, buf, size); +} + +static +int intel_dp_hdcp2_check_link(struct intel_digital_port *intel_dig_port) +{ + uint8_t rx_status; + int ret; + + ret = intel_dp_hdcp2_read_rx_status(intel_dig_port, &rx_status); + if (ret) + return ret; + + if (HDCP_2_2_DP_RXSTATUS_REAUTH_REQ(rx_status)) + ret = DRM_HDCP_REAUTH_REQUEST; + else if (HDCP_2_2_DP_RXSTATUS_LINK_FAILED(rx_status)) + ret = DRM_HDCP_LINK_INTEGRITY_FAILURE; + else if (HDCP_2_2_DP_RXSTATUS_READY(rx_status)) + ret = DRM_HDCP_TOPOLOGY_CHANGE; + + return ret; +} + +static +int intel_dp_hdcp2_capable(struct intel_digital_port *intel_dig_port, + bool *capable) +{ + uint8_t rx_caps[3]; + int ret; + + *capable = false; + ret = drm_dp_dpcd_read(&intel_dig_port->dp.aux, + DP_HDCP_2_2_REG_RX_CAPS_OFFSET, + rx_caps, HDCP_2_2_RXCAPS_LEN); + if (ret != HDCP_2_2_RXCAPS_LEN) + return ret >= 0 ? -EIO : ret; + + if (rx_caps[0] == HDCP_2_2_RXCAPS_VERSION_VAL && + HDCP_2_2_DP_HDCP_CAPABLE(rx_caps[2])) + *capable = true; + + return 0; +} + +static +enum hdcp_protocol intel_dp_hdcp2_protocol(void) +{ + return HDCP_PROTOCOL_DP; +} + static const struct intel_hdcp_shim intel_dp_hdcp_shim = { .write_an_aksv = intel_dp_hdcp_write_an_aksv, .read_bksv = intel_dp_hdcp_read_bksv, @@ -5316,6 +5643,12 @@ static const struct intel_hdcp_shim intel_dp_hdcp_shim = { .toggle_signalling = intel_dp_hdcp_toggle_signalling, .check_link = intel_dp_hdcp_check_link, .hdcp_capable = intel_dp_hdcp_capable, + .write_2_2_msg = intel_dp_hdcp2_write_msg, + .read_2_2_msg = intel_dp_hdcp2_read_msg, + .config_stream_type = intel_dp_hdcp2_config_stream_type, + .check_2_2_link = intel_dp_hdcp2_check_link, + .hdcp_2_2_capable = intel_dp_hdcp2_capable, + .hdcp_protocol = intel_dp_hdcp2_protocol, };
static void intel_edp_panel_vdd_sanitize(struct intel_dp *intel_dp) diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 875657fd7d3c..074dc5b53488 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -444,6 +444,13 @@ struct intel_hdcp { /* mei interface related information */ struct mei_hdcp_data mei_data; struct delayed_work hdcp2_check_work; + + /* + * Work queue to signal the CP_IRQ. Used for the waiters to read the + * available information from HDCP DP sink. + */ + wait_queue_head_t cp_irq_queue; + atomic_t cp_irq_recved; };
struct intel_connector { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index b035274785c8..edc413ecf17f 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -870,6 +870,8 @@ int intel_hdcp_init(struct intel_connector *connector, if (hdcp2_supported) intel_hdcp2_init(connector);
+ init_waitqueue_head(&hdcp->cp_irq_queue); + atomic_set(&hdcp->cp_irq_recved, 0); return 0; }
@@ -2039,4 +2041,7 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector) intel_hdcp_check_link(connector); else if (intel_hdcp2_in_force(connector)) intel_hdcp2_check_link(connector); + + atomic_set(&connector->hdcp.cp_irq_recved, 1); + wake_up_all(&connector->hdcp.cp_irq_queue); }
Implements the HDMI adaptation specific HDCP2.2 operations.
Basically these are DDC read and write for authenticating through HDCP2.2 messages.
v2: Rebased. v3: No Changes. v4: No more special handling of Gmbus burst read for AKE_SEND_CERT. Style fixed with few naming. [Uma] %s/PARING/PAIRING v5: msg_sz is initialized at definition. Lookup table is defined for HDMI HDCP2.2 msgs [Daniel].
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 187 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 187 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index 7988f958d835..f3672e192be6 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -30,6 +30,7 @@ #include <linux/slab.h> #include <linux/delay.h> #include <linux/hdmi.h> +#include <linux/mei_hdcp.h> #include <drm/drmP.h> #include <drm/drm_atomic_helper.h> #include <drm/drm_crtc.h> @@ -1116,6 +1117,187 @@ bool intel_hdmi_hdcp_check_link(struct intel_digital_port *intel_dig_port) return true; }
+static struct hdcp2_hdmi_msg_data { + uint8_t msg_id; + uint32_t timeout; + uint32_t timeout2; + } hdcp2_msg_data[] = { + {HDCP_2_2_AKE_INIT, 0, 0}, + {HDCP_2_2_AKE_SEND_CERT, HDCP_2_2_CERT_TIMEOUT, 0}, + {HDCP_2_2_AKE_NO_STORED_KM, 0, 0}, + {HDCP_2_2_AKE_STORED_KM, 0, 0}, + {HDCP_2_2_AKE_SEND_HPRIME, HDCP_2_2_HPRIME_PAIRED_TIMEOUT, + HDCP_2_2_HPRIME_NO_PAIRED_TIMEOUT}, + {HDCP_2_2_AKE_SEND_PAIRING_INFO, HDCP_2_2_PAIRING_TIMEOUT, 0}, + {HDCP_2_2_LC_INIT, 0, 0}, + {HDCP_2_2_LC_SEND_LPRIME, HDCP_2_2_HDMI_LPRIME_TIMEOUT, 0}, + {HDCP_2_2_SKE_SEND_EKS, 0, 0}, + {HDCP_2_2_REP_SEND_RECVID_LIST, + HDCP_2_2_RECVID_LIST_TIMEOUT, 0}, + {HDCP_2_2_REP_SEND_ACK, 0, 0}, + {HDCP_2_2_REP_STREAM_MANAGE, 0, 0}, + {HDCP_2_2_REP_STREAM_READY, HDCP_2_2_STREAM_READY_TIMEOUT, 0}, + }; + +static +int intel_hdmi_hdcp2_read_rx_status(struct intel_digital_port *intel_dig_port, + uint8_t *rx_status) +{ + return intel_hdmi_hdcp_read(intel_dig_port, + HDCP_2_2_HDMI_REG_RXSTATUS_OFFSET, + rx_status, + HDCP_2_2_HDMI_RXSTATUS_LEN); +} + +static int get_hdcp2_msg_timeout(uint8_t msg_id, bool is_paired) +{ + int i; + + for (i = 0; i < sizeof(hdcp2_msg_data); i++) + if (hdcp2_msg_data[i].msg_id == msg_id && + (msg_id != HDCP_2_2_AKE_SEND_HPRIME || is_paired)) + return hdcp2_msg_data[i].timeout; + else if (hdcp2_msg_data[i].msg_id == msg_id) + return hdcp2_msg_data[i].timeout2; + + return -EINVAL; +} + +static inline +int hdcp2_detect_msg_availability(struct intel_digital_port *intel_digital_port, + uint8_t msg_id, bool *msg_ready, + ssize_t *msg_sz) +{ + uint8_t rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN]; + int ret; + + ret = intel_hdmi_hdcp2_read_rx_status(intel_digital_port, rx_status); + if (ret < 0) { + DRM_DEBUG_KMS("rx_status read failed. Err %d\n", ret); + return ret; + } + + *msg_sz = ((HDCP_2_2_HDMI_RXSTATUS_MSG_SZ_HI(rx_status[1]) << 8) | + rx_status[0]); + + if (msg_id == HDCP_2_2_REP_SEND_RECVID_LIST) + *msg_ready = (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1]) && + *msg_sz); + else + *msg_ready = *msg_sz; + + return 0; +} + +static ssize_t +intel_hdmi_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port, + uint8_t msg_id, bool paired) +{ + bool msg_ready = false; + int timeout, ret; + ssize_t msg_sz = 0; + + timeout = get_hdcp2_msg_timeout(msg_id, paired); + if (timeout < 0) + return timeout; + + ret = __wait_for(ret = hdcp2_detect_msg_availability(intel_dig_port, + msg_id, &msg_ready, &msg_sz), + !ret && msg_ready && msg_sz, timeout * 1000, + 1000, 5 * 1000); + if (ret) + DRM_ERROR("msg_id: %d, ret: %d, timeout: %d\n", + msg_id, ret, timeout); + + return ret ? ret : msg_sz; +} + +static +int intel_hdmi_hdcp2_write_msg(struct intel_digital_port *intel_dig_port, + void *buf, size_t size) +{ + unsigned int offset; + + offset = HDCP_2_2_HDMI_REG_WR_MSG_OFFSET; + return intel_hdmi_hdcp_write(intel_dig_port, offset, buf, size); +} + +static +int intel_hdmi_hdcp2_read_msg(struct intel_digital_port *intel_dig_port, + uint8_t msg_id, void *buf, size_t size) +{ + struct intel_hdmi *hdmi = &intel_dig_port->hdmi; + struct intel_hdcp *hdcp = &hdmi->attached_connector->hdcp; + unsigned int offset; + ssize_t ret; + + ret = intel_hdmi_hdcp2_wait_for_msg(intel_dig_port, msg_id, + hdcp->is_paired); + if (ret < 0) + return ret; + + /* + * Available msg size should be equal to or lesser than the + * available buffer. + */ + if (ret > size) { + DRM_DEBUG_KMS("msg_sz(%zd) is more than exp size(%zu)\n", + ret, size); + return -1; + } + + offset = HDCP_2_2_HDMI_REG_RD_MSG_OFFSET; + ret = intel_hdmi_hdcp_read(intel_dig_port, offset, buf, ret); + if (ret) + DRM_DEBUG_KMS("Failed to read msg_id: %d(%zd)\n", msg_id, ret); + + return ret; +} + +static +int intel_hdmi_hdcp2_check_link(struct intel_digital_port *intel_dig_port) +{ + uint8_t rx_status[HDCP_2_2_HDMI_RXSTATUS_LEN]; + int ret; + + ret = intel_hdmi_hdcp2_read_rx_status(intel_dig_port, rx_status); + if (ret) + return ret; + + /* + * Re-auth request and Link Integrity Failures are represented by + * same bit. i.e reauth_req. + */ + if (HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(rx_status[1])) + ret = DRM_HDCP_REAUTH_REQUEST; + else if (HDCP_2_2_HDMI_RXSTATUS_READY(rx_status[1])) + ret = DRM_HDCP_TOPOLOGY_CHANGE; + + return ret; +} + +static +int intel_hdmi_hdcp2_capable(struct intel_digital_port *intel_dig_port, + bool *capable) +{ + uint8_t hdcp2_version; + int ret; + + *capable = false; + ret = intel_hdmi_hdcp_read(intel_dig_port, HDCP_2_2_HDMI_REG_VER_OFFSET, + &hdcp2_version, sizeof(hdcp2_version)); + if (!ret && hdcp2_version & HDCP_2_2_HDMI_SUPPORT_MASK) + *capable = true; + + return ret; +} + +static +enum hdcp_protocol intel_hdmi_hdcp2_protocol(void) +{ + return HDCP_PROTOCOL_HDMI; +} + static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = { .write_an_aksv = intel_hdmi_hdcp_write_an_aksv, .read_bksv = intel_hdmi_hdcp_read_bksv, @@ -1127,6 +1309,11 @@ static const struct intel_hdcp_shim intel_hdmi_hdcp_shim = { .read_v_prime_part = intel_hdmi_hdcp_read_v_prime_part, .toggle_signalling = intel_hdmi_hdcp_toggle_signalling, .check_link = intel_hdmi_hdcp_check_link, + .write_2_2_msg = intel_hdmi_hdcp2_write_msg, + .read_2_2_msg = intel_hdmi_hdcp2_read_msg, + .check_2_2_link = intel_hdmi_hdcp2_check_link, + .hdcp_2_2_capable = intel_hdmi_hdcp2_capable, + .hdcp_protocol = intel_hdmi_hdcp2_protocol, };
static void intel_hdmi_prepare(struct intel_encoder *encoder,
On DP connector init, intel_hdcp_init is passed with a flag for hdcp2.2 support based on the platform capability.
v2: Rebased. v3: No Changes. v4: Collected the reviewed-by received. v5: No change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_dp.c | 2 +- drivers/gpu/drm/i915/intel_drv.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index c8974a7d2d37..f5486f080951 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -6737,7 +6737,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
if (is_hdcp_supported(dev_priv, port) && !intel_dp_is_edp(intel_dp)) { int ret = intel_hdcp_init(intel_connector, &intel_dp_hdcp_shim, - false); + is_hdcp2_supported(dev_priv)); if (ret) DRM_DEBUG_KMS("HDCP init failed, skipping.\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 074dc5b53488..2ef3606a1810 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -1974,6 +1974,7 @@ int intel_hdcp_enable(struct intel_connector *connector); int intel_hdcp_disable(struct intel_connector *connector); bool is_hdcp_supported(struct drm_i915_private *dev_priv, enum port port); void intel_hdcp_handle_cp_irq(struct intel_connector *connector); +bool is_hdcp2_supported(struct drm_i915_private *dev_priv);
/* intel_psr.c */ #define CAN_PSR(dev_priv) (HAS_PSR(dev_priv) && dev_priv->psr.sink_support)
On HDMI connector init, intel_hdcp_init is passed with a flag for hdcp2.2 support based on the platform capability.
v2: Rebased. v3: No Changes. v4: Collected the reviewed-by received. v5: No change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Reviewed-by: Uma Shankar uma.shankar@intel.com --- drivers/gpu/drm/i915/intel_hdmi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c index f3672e192be6..05fa1f8da681 100644 --- a/drivers/gpu/drm/i915/intel_hdmi.c +++ b/drivers/gpu/drm/i915/intel_hdmi.c @@ -2553,7 +2553,8 @@ void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
if (is_hdcp_supported(dev_priv, port)) { int ret = intel_hdcp_init(intel_connector, - &intel_hdmi_hdcp_shim, false); + &intel_hdmi_hdcp_shim, + is_hdcp2_supported(dev_priv)); if (ret) DRM_DEBUG_KMS("HDCP init failed, skipping.\n"); }
ME FW is contributes a vital role in HDCP2.2 authentication. HDCP2.2 driver needs to communicate to ME FW for each step of the HDCP2.2 authentication.
ME FW prepare and HDCP2.2 authentication parameters and encrypt them as per spec. With such parameter Driver prepares HDCP2.2 auth messages and communicate with HDCP2.2 sink.
Similarly HDCP2. sink's response is shared with ME FW for decrypt and verification.
Once All the steps of HDCP2.2 authentications are complete on driver's request ME FW will configure the port as authenticated and supply the HDCP keys to the Gen HW for encryption.
Only after this stage HDCP2.2 driver can start the HDCP2.2 encryption for a port.
ME FW is interfaced to kernel through MEI Bus Driver. To obtain the HDCP2.2 services from the ME FW through MEI Bus driver MEI Client Driver is developed.
With this change MEI_HDCP drivers selected by I915 by default. In case if we want to exclude the mei_hdcp compilation, we need to introduce a new config called HDCP2.2. Using such CONFIG var we could control the compilation of the HDCP2.2 code in I915 and also the compilation of the MEI_HDCP.
v2: hdcp files are moved to drivers/misc/mei/hdcp/ [Tomas] v3: Squashed the Kbuild support [Tomas] UUID renamed and Module License is modified [Tomas] drv_data is set to null at remove [Tomas] v4: Module name is changed to "MEI HDCP" I915 Selects the MEI_HDCP v5: No Change.
Signed-off-by: Ramalingam C ramalingam.c@intel.com Signed-off-by: Tomas Winkler tomas.winkler@intel.com --- drivers/gpu/drm/i915/Kconfig | 1 + drivers/misc/mei/Kconfig | 7 ++++ drivers/misc/mei/Makefile | 2 ++ drivers/misc/mei/hdcp/Makefile | 6 ++++ drivers/misc/mei/hdcp/mei_hdcp.c | 74 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+) create mode 100644 drivers/misc/mei/hdcp/Makefile create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.c
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig index dfd95889f4b7..bfa8f987910b 100644 --- a/drivers/gpu/drm/i915/Kconfig +++ b/drivers/gpu/drm/i915/Kconfig @@ -23,6 +23,7 @@ config DRM_I915 select SYNC_FILE select IOSF_MBI select CRC32 + select INTEL_MEI_HDCP help Choose this option if you have a system that has "Intel Graphics Media Accelerator" or "HD Graphics" integrated graphics, diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig index c49e1d2269af..9c518b7f0011 100644 --- a/drivers/misc/mei/Kconfig +++ b/drivers/misc/mei/Kconfig @@ -43,3 +43,10 @@ config INTEL_MEI_TXE
Supported SoCs: Intel Bay Trail + +config INTEL_MEI_HDCP + tristate "Intel HDCP2.2 services of ME Interface" + select INTEL_MEI_ME + depends on DRM_I915 + help + MEI Support for HDCP2.2 Services on Intel SoCs. diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile index cd6825afa8e1..e64d1212fb85 100644 --- a/drivers/misc/mei/Makefile +++ b/drivers/misc/mei/Makefile @@ -23,3 +23,5 @@ mei-txe-objs += hw-txe.o
mei-$(CONFIG_EVENT_TRACING) += mei-trace.o CFLAGS_mei-trace.o = -I$(src) + +obj-$(CONFIG_INTEL_MEI_HDCP) += hdcp/ diff --git a/drivers/misc/mei/hdcp/Makefile b/drivers/misc/mei/hdcp/Makefile new file mode 100644 index 000000000000..75ac50203223 --- /dev/null +++ b/drivers/misc/mei/hdcp/Makefile @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile - HDCP client driver for Intel MEI Bus Driver. +# Copyright (c) 2010-2014, Intel Corporation. +# +obj-$(CONFIG_INTEL_MEI_HDCP) += mei_hdcp.o diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c new file mode 100644 index 000000000000..4cd6fdd01181 --- /dev/null +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -0,0 +1,74 @@ +/* SPDX-License-Identifier: GPL-2.0+ OR BSD-3-Clause */ +/* + * Copyright © 2017-2018 Intel Corporation + * + * Mei_hdcp.c: HDCP client driver for mei bus + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Authors: + * Ramalingam C ramalingam.c@intel.com + */ + +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/uuid.h> +#include <linux/mei_cl_bus.h> + +static int mei_hdcp_probe(struct mei_cl_device *cldev, + const struct mei_cl_device_id *id) +{ + int ret; + + ret = mei_cldev_enable(cldev); + if (ret < 0) + dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); + + return ret; +} + +static int mei_hdcp_remove(struct mei_cl_device *cldev) +{ + mei_cldev_set_drvdata(cldev, NULL); + return mei_cldev_disable(cldev); +} + +#define MEI_UUID_HDCP UUID_LE(0xB638AB7E, 0x94E2, 0x4EA2, 0xA5, \ + 0x52, 0xD1, 0xC5, 0x4B, \ + 0x62, 0x7F, 0x04) + +static struct mei_cl_device_id mei_hdcp_tbl[] = { + { .uuid = MEI_UUID_HDCP, .version = MEI_CL_VERSION_ANY }, + { } +}; +MODULE_DEVICE_TABLE(mei, mei_hdcp_tbl); + +static struct mei_cl_driver mei_hdcp_driver = { + .id_table = mei_hdcp_tbl, + .name = KBUILD_MODNAME, + .probe = mei_hdcp_probe, + .remove = mei_hdcp_remove, +}; + +module_mei_cl_driver(mei_hdcp_driver); + +MODULE_AUTHOR("Intel Corporation"); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_DESCRIPTION("MEI HDCP");
Mei hdcp driver is designed as component slave for the I915 component master.
v2: Rebased. v3: Notifier chain is adopted for cldev state update [Tomas] v4: Made static dummy functions as inline in mei_hdcp.h API for polling client device status IS_ENABLED used in header, for config status for mei_hdcp. v5: Replacing the notifier with component framework. [Daniel]
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 94 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 4cd6fdd01181..ba7550215b7f 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -31,6 +31,83 @@ #include <linux/slab.h> #include <linux/uuid.h> #include <linux/mei_cl_bus.h> +#include <linux/component.h> +#include <drm/i915_component.h> + +bool mei_hdcp_component_registered; +static struct mei_cl_device *mei_cldev; + +struct i915_hdcp_component_ops mei_hdcp_component_ops = { + .owner = THIS_MODULE, + .initiate_hdcp2_session = NULL, + .verify_receiver_cert_prepare_km = NULL, + .verify_hprime = NULL, + .store_pairing_info = NULL, + .initiate_locality_check = NULL, + .verify_lprime = NULL, + .get_session_key = NULL, + .repeater_check_flow_prepare_ack = NULL, + .verify_mprime = NULL, + .enable_hdcp_authentication = NULL, + .close_hdcp_session = NULL, +}; + +static int mei_hdcp_component_bind(struct device *mei_kdev, + struct device *i915_kdev, void *data) +{ + struct i915_hdcp_component *comp = data; + + WARN_ON(!mutex_is_locked(&comp->mutex)); + if (WARN_ON(comp->ops || comp->dev)) + return -EEXIST; + + dev_info(mei_kdev, "MEI HDCP comp bind\n"); + comp->ops = &mei_hdcp_component_ops; + comp->i915_kdev = i915_kdev; + comp->mei_cldev = mei_cldev; + mei_cldev_set_drvdata(mei_cldev, (void *)comp); + + return 0; +} + +static void mei_hdcp_component_unbind(struct device *mei_kdev, + struct device *i915_kdev, void *data) +{ + struct i915_hdcp_component *comp = data; + + WARN_ON(!mutex_is_locked(&comp->mutex)); + dev_info(mei_kdev, "MEI HDCP comp unbind\n"); + comp->ops = NULL; + comp->dev = NULL; + comp->mei_cldev = NULL; +} + +static const struct component_ops mei_hdcp_component_bind_ops = { + .bind = mei_hdcp_component_bind, + .unbind = mei_hdcp_component_unbind, +}; + +void mei_hdcp_component_init(struct device *dev) +{ + int ret; + + ret = component_add(dev, &mei_hdcp_component_bind_ops); + if (ret < 0) { + dev_err(dev, "Failed to add MEI HDCP comp (%d)\n", ret); + return; + } + + mei_hdcp_component_registered = true; +} + +void mei_hdcp_component_cleanup(struct device *dev) +{ + if (!mei_hdcp_component_registered) + return; + + component_del(dev, &mei_hdcp_component_bind_ops); + mei_hdcp_component_registered = false; +}
static int mei_hdcp_probe(struct mei_cl_device *cldev, const struct mei_cl_device_id *id) @@ -38,15 +115,28 @@ static int mei_hdcp_probe(struct mei_cl_device *cldev, int ret;
ret = mei_cldev_enable(cldev); - if (ret < 0) + if (ret < 0) { dev_err(&cldev->dev, "mei_cldev_enable Failed. %d\n", ret); + return ret; + }
- return ret; + mei_cldev = cldev; + mei_hdcp_component_init(&cldev->dev); + return 0; }
static int mei_hdcp_remove(struct mei_cl_device *cldev) { + struct i915_hdcp_component *comp; + + comp = mei_cldev_get_drvdata(cldev); + if (comp && comp->master_ops && comp->master_ops->pull_down_interface) + comp->master_ops->pull_down_interface(comp->i915_kdev); + + mei_cldev = NULL; mei_cldev_set_drvdata(cldev, NULL); + mei_hdcp_component_cleanup(&cldev->dev); + return mei_cldev_disable(cldev); }
Fixes: 0654edaa3690 ("misc/mei/hdcp: Component framework for I915 Interface") Signed-off-by: kbuild test robot fengguang.wu@intel.com --- mei_hdcp.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index ba75502..146a4be 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -34,10 +34,10 @@ #include <linux/component.h> #include <drm/i915_component.h>
-bool mei_hdcp_component_registered; +static bool mei_hdcp_component_registered; static struct mei_cl_device *mei_cldev;
-struct i915_hdcp_component_ops mei_hdcp_component_ops = { +static struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = NULL, .verify_receiver_cert_prepare_km = NULL, @@ -87,7 +87,7 @@ static const struct component_ops mei_hdcp_component_bind_ops = { .unbind = mei_hdcp_component_unbind, };
-void mei_hdcp_component_init(struct device *dev) +static void mei_hdcp_component_init(struct device *dev) { int ret;
@@ -100,7 +100,7 @@ void mei_hdcp_component_init(struct device *dev) mei_hdcp_component_registered = true; }
-void mei_hdcp_component_cleanup(struct device *dev) +static void mei_hdcp_component_cleanup(struct device *dev) { if (!mei_hdcp_component_registered) return;
Hi Ramalingam,
Thank you for the patch! Perhaps something to improve:
[auto build test WARNING on drm-intel/for-linux-next] [also build test WARNING on next-20180627] [cannot apply to v4.18-rc2] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ramalingam-C/drm-i915-Implement-HDC... base: git://anongit.freedesktop.org/drm-intel for-linux-next reproduce: # apt-get install sparse make ARCH=x86_64 allmodconfig make C=1 CF=-D__CHECK_ENDIAN__
sparse warnings: (new ones prefixed by >>)
drivers/misc/mei/hdcp/mei_hdcp.c:37:6: sparse: symbol 'mei_hdcp_component_registered' was not declared. Should it be static? drivers/misc/mei/hdcp/mei_hdcp.c:40:32: sparse: symbol 'mei_hdcp_component_ops' was not declared. Should it be static? drivers/misc/mei/hdcp/mei_hdcp.c:90:6: sparse: symbol 'mei_hdcp_component_init' was not declared. Should it be static? drivers/misc/mei/hdcp/mei_hdcp.c:103:6: sparse: symbol 'mei_hdcp_component_cleanup' was not declared. Should it be static?
Please review and possibly fold the followup patch.
--- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation
Defines the HDCP specific ME FW interfaces such as Request CMDs, payload structure for CMDs and their response status codes.
This patch defines payload size(Excluding the Header)for each WIRED HDCP2.2 CMDs.
v2: Rebased. v3: Extra comments are removed. v4: %s//**//* v5: Extra lines are removed.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.h | 408 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 408 insertions(+) create mode 100644 drivers/misc/mei/hdcp/mei_hdcp.h
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.h b/drivers/misc/mei/hdcp/mei_hdcp.h new file mode 100644 index 000000000000..b201cd1ffda4 --- /dev/null +++ b/drivers/misc/mei/hdcp/mei_hdcp.h @@ -0,0 +1,408 @@ +/* SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) */ +/* + * Copyright © 2017-2018 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + * + * Authors: + * Ramalingam C ramalingam.c@intel.com + */ + +#ifndef __MEI_HDCP_H__ +#define __MEI_HDCP_H__ + +#include <drm/drm_hdcp.h> + +/* + * me_hdcp_status: Enumeration of all HDCP Status Codes + */ +enum me_hdcp_status { + ME_HDCP_STATUS_SUCCESS = 0x0000, + + /* WiDi Generic Status Codes */ + ME_HDCP_STATUS_INTERNAL_ERROR = 0x1000, + ME_HDCP_STATUS_UNKNOWN_ERROR = 0x1001, + ME_HDCP_STATUS_INCORRECT_API_VERSION = 0x1002, + ME_HDCP_STATUS_INVALID_FUNCTION = 0x1003, + ME_HDCP_STATUS_INVALID_BUFFER_LENGTH = 0x1004, + ME_HDCP_STATUS_INVALID_PARAMS = 0x1005, + ME_HDCP_STATUS_AUTHENTICATION_FAILED = 0x1006, + + /* WiDi Status Codes */ + ME_HDCP_INVALID_SESSION_STATE = 0x6000, + ME_HDCP_SRM_FRAGMENT_UNEXPECTED = 0x6001, + ME_HDCP_SRM_INVALID_LENGTH = 0x6002, + ME_HDCP_SRM_FRAGMENT_OFFSET_INVALID = 0x6003, + ME_HDCP_SRM_VERIFICATION_FAILED = 0x6004, + ME_HDCP_SRM_VERSION_TOO_OLD = 0x6005, + ME_HDCP_RX_CERT_VERIFICATION_FAILED = 0x6006, + ME_HDCP_RX_REVOKED = 0x6007, + ME_HDCP_H_VERIFICATION_FAILED = 0x6008, + ME_HDCP_REPEATER_CHECK_UNEXPECTED = 0x6009, + ME_HDCP_TOPOLOGY_MAX_EXCEEDED = 0x600A, + ME_HDCP_V_VERIFICATION_FAILED = 0x600B, + ME_HDCP_L_VERIFICATION_FAILED = 0x600C, + ME_HDCP_STREAM_KEY_ALLOC_FAILED = 0x600D, + ME_HDCP_BASE_KEY_RESET_FAILED = 0x600E, + ME_HDCP_NONCE_GENERATION_FAILED = 0x600F, + ME_HDCP_STATUS_INVALID_E_KEY_STATE = 0x6010, + ME_HDCP_STATUS_INVALID_CS_ICV = 0x6011, + ME_HDCP_STATUS_INVALID_KB_KEY_STATE = 0x6012, + ME_HDCP_STATUS_INVALID_PAVP_MODE_ICV = 0x6013, + ME_HDCP_STATUS_INVALID_PAVP_MODE = 0x6014, + ME_HDCP_STATUS_LC_MAX_ATTEMPTS = 0x6015, + + /* New status for HDCP 2.1 */ + ME_HDCP_STATUS_MISMATCH_IN_M = 0x6016, + + /* New status code for HDCP 2.2 Rx */ + ME_HDCP_STATUS_RX_PROV_NOT_ALLOWED = 0x6017, + ME_HDCP_STATUS_RX_PROV_WRONG_SUBJECT = 0x6018, + ME_HDCP_RX_NEEDS_PROVISIONING = 0x6019, + ME_HDCP_BKSV_ICV_AUTH_FAILED = 0x6020, + ME_HDCP_STATUS_INVALID_STREAM_ID = 0x6021, + ME_HDCP_STATUS_CHAIN_NOT_INITIALIZED = 0x6022, + ME_HDCP_FAIL_NOT_EXPECTED = 0x6023, + ME_HDCP_FAIL_HDCP_OFF = 0x6024, + ME_HDCP_FAIL_INVALID_PAVP_MEMORY_MODE = 0x6025, + ME_HDCP_FAIL_AES_ECB_FAILURE = 0x6026, + ME_HDCP_FEATURE_NOT_SUPPORTED = 0x6027, + ME_HDCP_DMA_READ_ERROR = 0x6028, + ME_HDCP_DMA_WRITE_ERROR = 0x6029, + ME_HDCP_FAIL_INVALID_PACKET_SIZE = 0x6030, + ME_HDCP_H264_PARSING_ERROR = 0x6031, + ME_HDCP_HDCP2_ERRATA_VIDEO_VIOLATION = 0x6032, + ME_HDCP_HDCP2_ERRATA_AUDIO_VIOLATION = 0x6033, + ME_HDCP_TX_ACTIVE_ERROR = 0x6034, + ME_HDCP_MODE_CHANGE_ERROR = 0x6035, + ME_HDCP_STREAM_TYPE_ERROR = 0x6036, + ME_HDCP_STREAM_MANAGE_NOT_POSSIBLE = 0x6037, + + ME_HDCP_STATUS_PORT_INVALID_COMMAND = 0x6038, + ME_HDCP_STATUS_UNSUPPORTED_PROTOCOL = 0x6039, + ME_HDCP_STATUS_INVALID_PORT_INDEX = 0x603a, + ME_HDCP_STATUS_TX_AUTH_NEEDED = 0x603b, + ME_HDCP_STATUS_NOT_INTEGRATED_PORT = 0x603c, + ME_HDCP_STATUS_SESSION_MAX_REACHED = 0x603d, + + /* hdcp capable bit is not set in rx_caps(error is unique to DP) */ + ME_HDCP_STATUS_NOT_HDCP_CAPABLE = 0x6041, + + ME_HDCP_STATUS_INVALID_STREAM_COUNT = 0x6042, +}; + +#define HDCP_API_VERSION 0x00010000 + +#define HDCP_M_LEN 16 +#define HDCP_KH_LEN 16 + +/* + * Payload Buffer size(Excluding Header) for each CMD and corresponding response + */ +/* Wired_Tx_AKE */ +#define WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN (4 + 1) +#define WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_OUT (4 + 8 + 3) + +#define WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN (4 + 522 + 8 + 3) +#define WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MIN_OUT (4 + 1 + 3 + 16 + 16) +#define WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_MAX_OUT (4 + 1 + 3 + 128) + +#define WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN (4 + 32) +#define WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_OUT (4) + +#define WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN (4 + 16) +#define WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_OUT (4) + +#define WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN (4) +#define WIRED_CMD_BUF_LEN_CLOSE_SESSION_OUT (4) + +/* Wired_Tx_LC */ +#define WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN (4) +#define WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_OUT (4 + 8) + +#define WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN (4 + 32) +#define WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_OUT (4) + +/* Wired_Tx_SKE */ +#define WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN (4) +#define WIRED_CMD_BUF_LEN_GET_SESSION_KEY_OUT (4 + 16 + 8) + +/* Wired_Tx_SKE */ +#define WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN (4 + 1) +#define WIRED_CMD_BUF_LEN_ENABLE_AUTH_OUT (4) + +/* Wired_Tx_Repeater */ +#define WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN (4 + 2 + 3 + 16 + 155) +#define WIRED_CMD_BUF_LEN_VERIFY_REPEATER_OUT (4 + 1 + 16) + +#define WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN (4 + 3 + \ + 32 + 2 + 2) + +#define WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_OUT (4) + +/* + * hdcp_command_id: Enumeration of all WIRED HDCP Command IDs + */ +enum hdcp_command_id { + _WIDI_COMMAND_BASE = 0x00030000, + WIDI_INITIATE_HDCP2_SESSION = _WIDI_COMMAND_BASE, + HDCP_GET_SRM_STATUS, + HDCP_SEND_SRM_FRAGMENT, + + /* The wired HDCP Tx commands */ + _WIRED_COMMAND_BASE = 0x00031000, + WIRED_INITIATE_HDCP2_SESSION = _WIRED_COMMAND_BASE, + WIRED_VERIFY_RECEIVER_CERT, + WIRED_AKE_SEND_HPRIME, + WIRED_AKE_SEND_PAIRING_INFO, + WIRED_INIT_LOCALITY_CHECK, + WIRED_VALIDATE_LOCALITY, + WIRED_GET_SESSION_KEY, + WIRED_ENABLE_AUTH, + WIRED_VERIFY_REPEATER, + WIRED_REPEATER_AUTH_STREAM_REQ, + WIRED_CLOSE_SESSION, + + _WIRED_COMMANDS_COUNT, +}; + +union encrypted_buff { + uint8_t e_kpub_km[HDCP_2_2_E_KPUB_KM_LEN]; + uint8_t e_kh_km_m[HDCP_2_2_E_KH_KM_M_LEN]; + struct { + uint8_t e_kh_km[HDCP_KH_LEN]; + uint8_t m[HDCP_M_LEN]; + } __packed; +}; + +/* + * HDCP HECI message header. All header values are little endian. + */ +struct hdcp_cmd_header { + uint32_t api_version; + uint32_t command_id; + enum me_hdcp_status status; + /* Length of the HECI message (excluding the header) */ + uint32_t buffer_len; +} __packed; + +/* Empty command request or response. No data follows the header. */ +struct hdcp_cmd_no_data { + struct hdcp_cmd_header header; +} __packed; + +/* + * Uniquely identifies the hdcp port being addressed for a given command. + */ +struct hdcp_port_id { + uint8_t integrated_port_type; + uint8_t physical_port; + uint16_t reserved; +} __packed; + +/* + * Data structures for integrated wired HDCP2 Tx in + * support of the AKE protocol + */ +/* + * HECI struct for integrated wired HDCP Tx session initiation. + */ +struct wired_cmd_initiate_hdcp2_session_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t protocol; /* for HDMI vs DP */ +} __packed; + +struct wired_cmd_initiate_hdcp2_session_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t r_tx[HDCP_2_2_RTX_LEN]; + struct hdcp2_tx_caps tx_caps; +} __packed; + +/* + * HECI struct for ending an integrated wired HDCP Tx session. + */ +struct wired_cmd_close_session_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +struct wired_cmd_close_session_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +/* + * HECI struct for integrated wired HDCP Tx Rx Cert verification. + */ +struct wired_cmd_verify_receiver_cert_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + struct hdcp2_cert_rx cert_rx; + uint8_t r_rx[HDCP_2_2_RRX_LEN]; + uint8_t rx_caps[HDCP_2_2_RXCAPS_LEN]; +} __packed; + +struct wired_cmd_verify_receiver_cert_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t km_stored; + uint8_t reserved[3]; + union encrypted_buff ekm_buff; +} __packed; + +/* + * HECI struct for verification of Rx's Hprime in a HDCP Tx session + */ +struct wired_cmd_ake_send_hprime_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t h_prime[HDCP_2_2_H_PRIME_LEN]; +} __packed; + +struct wired_cmd_ake_send_hprime_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +/* + * HECI struct for sending in AKE pairing data generated by the Rx in an + * integrated wired HDCP Tx session. + */ +struct wired_cmd_ake_send_pairing_info_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t e_kh_km[HDCP_2_2_E_KH_KM_LEN]; +} __packed; + +struct wired_cmd_ake_send_pairing_info_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +/* + * Data structures for integrated wired HDCP2 Tx in support of the LC protocol + */ +/* + * HECI struct for initiating locality check with an + * integrated wired HDCP Tx session. + */ +struct wired_cmd_init_locality_check_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +struct wired_cmd_init_locality_check_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t r_n[HDCP_2_2_RN_LEN]; +} __packed; + +/* + * HECI struct for validating an Rx's LPrime value in an + * integrated wired HDCP Tx session. + */ +struct wired_cmd_validate_locality_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t l_prime[HDCP_2_2_L_PRIME_LEN]; +} __packed; + +struct wired_cmd_validate_locality_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +/* + * Data structures for integrated wired HDCP2 Tx in support of the SKE protocol + */ +/* + * HECI struct for creating session key + */ +struct wired_cmd_get_session_key_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +struct wired_cmd_get_session_key_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t e_dkey_ks[HDCP_2_2_E_DKEY_KS_LEN]; + uint8_t r_iv[HDCP_2_2_RIV_LEN]; +} __packed; + +/* + * HECI struct for the Tx enable authentication command + */ +struct wired_cmd_enable_auth_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t stream_type; +} __packed; + +struct wired_cmd_enable_auth_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +/* + * Data structures for integrated wired HDCP2 Tx in support of + * the repeater protocols + */ +/* + * HECI struct for verifying the downstream repeater's HDCP topology in an + * integrated wired HDCP Tx session. + */ +struct wired_cmd_verify_repeater_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t rx_info[HDCP_2_2_RXINFO_LEN]; + uint8_t seq_num_v[HDCP_2_2_SEQ_NUM_LEN]; + uint8_t v_prime[HDCP_2_2_LPRIME_HALF_LEN]; + uint8_t receiver_ids[HDCP_2_2_RECEIVER_IDS_MAX_LEN]; +} __packed; + +struct wired_cmd_verify_repeater_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t content_type_supported; + uint8_t v[HDCP_2_2_LPRIME_HALF_LEN]; +} __packed; + +/* + * HECI struct in support of stream management in an + * integrated wired HDCP Tx session. + */ +struct wired_cmd_repeater_auth_stream_req_in { + struct hdcp_cmd_header header; + struct hdcp_port_id port; + uint8_t seq_num_m[HDCP_2_2_SEQ_NUM_LEN]; + uint8_t m_prime[HDCP_2_2_MPRIME_LEN]; + uint16_t k; + struct hdcp2_streamid_type streams[1]; +} __packed; + +struct wired_cmd_repeater_auth_stream_req_out { + struct hdcp_cmd_header header; + struct hdcp_port_id port; +} __packed; + +#endif /* __MEI_HDCP_H__ */
Request ME FW to start the HDCP2.2 session for an intel port. Prepares payloads for command WIRED_INITIATE_HDCP2_SESSION and sends to ME FW.
On Success, ME FW will start a HDCP2.2 session for the port and provides the content for HDCP2.2 AKE_Init message.
v2: Rebased. v3: cldev is add as a separate parameter [Tomas] Redundant comment and typecast are removed [Tomas] v4: %zd is used for size [Alexander] %s/return -1/return -EIO [Alexander] Spellings in commit msg is fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 70 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index ba7550215b7f..7311e3095e94 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -32,14 +32,82 @@ #include <linux/uuid.h> #include <linux/mei_cl_bus.h> #include <linux/component.h> +#include <linux/mei_hdcp.h> #include <drm/i915_component.h> +#include <drm/drm_connector.h> + +#include "mei_hdcp.h"
bool mei_hdcp_component_registered; static struct mei_cl_device *mei_cldev;
+/* + * mei_initiate_hdcp2_session: + * Function to start a Wired HDCP2.2 Tx Session with ME FW + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * ake_data : ptr to store AKE_Init + * + * Returns 0 on Success, <0 on Failure. + */ +static int mei_initiate_hdcp2_session(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_init *ake_data) +{ + struct wired_cmd_initiate_hdcp2_session_in session_init_in = { { 0 } }; + struct wired_cmd_initiate_hdcp2_session_out + session_init_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !ake_data) + return -EINVAL; + + dev = &cldev->dev; + + session_init_in.header.api_version = HDCP_API_VERSION; + session_init_in.header.command_id = WIRED_INITIATE_HDCP2_SESSION; + session_init_in.header.status = ME_HDCP_STATUS_SUCCESS; + session_init_in.header.buffer_len = + WIRED_CMD_BUF_LEN_INITIATE_HDCP2_SESSION_IN; + + session_init_in.port.integrated_port_type = data->port_type; + session_init_in.port.physical_port = data->port; + session_init_in.protocol = (uint8_t)data->protocol; + + byte = mei_cldev_send(cldev, (u8 *)&session_init_in, + sizeof(session_init_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&session_init_out, + sizeof(session_init_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (session_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_INITIATE_HDCP2_SESSION, + session_init_out.header.status); + return -EIO; + } + + ake_data->msg_id = HDCP_2_2_AKE_INIT; + ake_data->tx_caps = session_init_out.tx_caps; + memcpy(ake_data->r_tx, session_init_out.r_tx, + sizeof(session_init_out.r_tx)); + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, - .initiate_hdcp2_session = NULL, + .initiate_hdcp2_session = mei_initiate_hdcp2_session, .verify_receiver_cert_prepare_km = NULL, .verify_hprime = NULL, .store_pairing_info = NULL,
Requests for verification for receiver certification and also the preparation for next AKE auth message with km.
On Success ME FW validate the HDCP2.2 receivers certificate and do the revocation check on the receiver ID. AKE_Stored_Km will be prepared if the receiver is already paired, else AKE_No_Stored_Km will be prepared.
Here AKE_Stored_Km and AKE_No_Stored_Km are HDCP2.2 protocol msgs.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd is used for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 85 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 7311e3095e94..fb717a7ff249 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -105,10 +105,93 @@ static int mei_initiate_hdcp2_session(struct mei_cl_device *cldev, return 0; }
+/* + * mei_verify_receiver_cert_prepare_km: + * Function to verify the Receiver Certificate AKE_Send_Cert + * and prepare AKE_Stored_Km or AKE_No_Stored_Km + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * rx_cert : Pointer for AKE_Send_Cert + * km_stored : Pointer for pairing status flag + * ek_pub_km : Pointer for output msg + * msg_sz : Pointer for size of AKE_XXXXX_Km + * + * Returns 0 on Success, <0 on Failure + */ +static int +mei_verify_receiver_cert_prepare_km(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_cert *rx_cert, + bool *km_stored, + struct hdcp2_ake_no_stored_km *ek_pub_km, + size_t *msg_sz) +{ + struct wired_cmd_verify_receiver_cert_in verify_rxcert_in = { { 0 } }; + struct wired_cmd_verify_receiver_cert_out verify_rxcert_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !rx_cert || !km_stored || !ek_pub_km || !msg_sz) + return -EINVAL; + + dev = &cldev->dev; + + verify_rxcert_in.header.api_version = HDCP_API_VERSION; + verify_rxcert_in.header.command_id = WIRED_VERIFY_RECEIVER_CERT; + verify_rxcert_in.header.status = ME_HDCP_STATUS_SUCCESS; + verify_rxcert_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_RECEIVER_CERT_IN; + + verify_rxcert_in.port.integrated_port_type = data->port_type; + verify_rxcert_in.port.physical_port = data->port; + + memcpy(&verify_rxcert_in.cert_rx, &rx_cert->cert_rx, + sizeof(rx_cert->cert_rx)); + memcpy(verify_rxcert_in.r_rx, &rx_cert->r_rx, sizeof(rx_cert->r_rx)); + memcpy(verify_rxcert_in.rx_caps, rx_cert->rx_caps, HDCP_2_2_RXCAPS_LEN); + + byte = mei_cldev_send(cldev, (u8 *)&verify_rxcert_in, + sizeof(verify_rxcert_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed: %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&verify_rxcert_out, + sizeof(verify_rxcert_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed: %zd\n", byte); + return byte; + } + + if (verify_rxcert_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_VERIFY_RECEIVER_CERT, + verify_rxcert_out.header.status); + return -EIO; + } + + *km_stored = verify_rxcert_out.km_stored; + if (verify_rxcert_out.km_stored) { + ek_pub_km->msg_id = HDCP_2_2_AKE_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_stored_km); + } else { + ek_pub_km->msg_id = HDCP_2_2_AKE_NO_STORED_KM; + *msg_sz = sizeof(struct hdcp2_ake_no_stored_km); + } + + memcpy(ek_pub_km->e_kpub_km, &verify_rxcert_out.ekm_buff, + sizeof(verify_rxcert_out.ekm_buff)); + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, - .verify_receiver_cert_prepare_km = NULL, + .verify_receiver_cert_prepare_km = + mei_verify_receiver_cert_prepare_km, .verify_hprime = NULL, .store_pairing_info = NULL, .initiate_locality_check = NULL,
Requests for the verification of AKE_Send_H_prime.
ME will calculate the H and comparing it with received H_Prime. The result will be returned as status.
Here AKE_Send_H_prime is a HDCP2.2 Authentication msg.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Styles and typos fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 61 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index fb717a7ff249..fb8b7ed889f5 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -187,12 +187,71 @@ mei_verify_receiver_cert_prepare_km(struct mei_cl_device *cldev, return 0; }
+/* + * mei_verify_hprime: + * Function to verify AKE_Send_H_prime received, through ME FW. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * rx_hprime : Pointer for AKE_Send_H_prime + * hprime_sz : Input buffer size + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_verify_hprime(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_hprime *rx_hprime) +{ + struct wired_cmd_ake_send_hprime_in send_hprime_in = { { 0 } }; + struct wired_cmd_ake_send_hprime_out send_hprime_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !rx_hprime) + return -EINVAL; + + dev = &cldev->dev; + + send_hprime_in.header.api_version = HDCP_API_VERSION; + send_hprime_in.header.command_id = WIRED_AKE_SEND_HPRIME; + send_hprime_in.header.status = ME_HDCP_STATUS_SUCCESS; + send_hprime_in.header.buffer_len = WIRED_CMD_BUF_LEN_AKE_SEND_HPRIME_IN; + + send_hprime_in.port.integrated_port_type = data->port_type; + send_hprime_in.port.physical_port = data->port; + + memcpy(send_hprime_in.h_prime, rx_hprime->h_prime, + sizeof(rx_hprime->h_prime)); + + byte = mei_cldev_send(cldev, (u8 *)&send_hprime_in, + sizeof(send_hprime_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&send_hprime_out, + sizeof(send_hprime_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (send_hprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X Failed. Status: 0x%X\n", + WIRED_AKE_SEND_HPRIME, send_hprime_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, .verify_receiver_cert_prepare_km = mei_verify_receiver_cert_prepare_km, - .verify_hprime = NULL, + .verify_hprime = mei_verify_hprime, .store_pairing_info = NULL, .initiate_locality_check = NULL, .verify_lprime = NULL,
Provides Pairing info to ME to store.
Pairing is a process to fast track the subsequent authentication with the same HDCP sink.
On Success, received HDCP pairing info is stored in non-volatile memory of ME.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 63 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index fb8b7ed889f5..7c833378bc60 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -246,13 +246,74 @@ static int mei_verify_hprime(struct mei_cl_device *cldev, return 0; }
+/* + * mei_store_pairing_info: + * Function to store pairing info received from panel + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * pairing_info : Pointer for AKE_Send_Pairing_Info + * + * Returns 0 on Success, <0 on Failure + */ +static int +mei_store_pairing_info(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ake_send_pairing_info *pairing_info) +{ + struct wired_cmd_ake_send_pairing_info_in pairing_info_in = { { 0 } }; + struct wired_cmd_ake_send_pairing_info_out pairing_info_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !pairing_info) + return -EINVAL; + + dev = &cldev->dev; + + pairing_info_in.header.api_version = HDCP_API_VERSION; + pairing_info_in.header.command_id = WIRED_AKE_SEND_PAIRING_INFO; + pairing_info_in.header.status = ME_HDCP_STATUS_SUCCESS; + pairing_info_in.header.buffer_len = + WIRED_CMD_BUF_LEN_SEND_PAIRING_INFO_IN; + + pairing_info_in.port.integrated_port_type = data->port_type; + pairing_info_in.port.physical_port = data->port; + + memcpy(pairing_info_in.e_kh_km, pairing_info->e_kh_km, + sizeof(pairing_info_in.e_kh_km)); + + byte = mei_cldev_send(cldev, (u8 *)&pairing_info_in, + sizeof(pairing_info_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&pairing_info_out, + sizeof(pairing_info_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (pairing_info_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. Status: 0x%X\n", + WIRED_AKE_SEND_PAIRING_INFO, + pairing_info_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, .verify_receiver_cert_prepare_km = mei_verify_receiver_cert_prepare_km, .verify_hprime = mei_verify_hprime, - .store_pairing_info = NULL, + .store_pairing_info = mei_store_pairing_info, .initiate_locality_check = NULL, .verify_lprime = NULL, .get_session_key = NULL,
Requests ME to start the second stage of HDCP2.2 authentication, called Locality Check.
On Success, ME FW will provide LC_Init message to send to hdcp sink.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd used for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 58 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 7c833378bc60..2a0369f46326 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -307,6 +307,62 @@ mei_store_pairing_info(struct mei_cl_device *cldev, return 0; }
+/* + * mei_initiate_locality_check: + * Function to prepare LC_Init. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * hdcp2_lc_init : Pointer for storing LC_Init + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_initiate_locality_check(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_lc_init *lc_init_data) +{ + struct wired_cmd_init_locality_check_in lc_init_in = { { 0 } }; + struct wired_cmd_init_locality_check_out lc_init_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !lc_init_data) + return -EINVAL; + + dev = &cldev->dev; + + lc_init_in.header.api_version = HDCP_API_VERSION; + lc_init_in.header.command_id = WIRED_INIT_LOCALITY_CHECK; + lc_init_in.header.status = ME_HDCP_STATUS_SUCCESS; + lc_init_in.header.buffer_len = WIRED_CMD_BUF_LEN_INIT_LOCALITY_CHECK_IN; + + lc_init_in.port.integrated_port_type = data->port_type; + lc_init_in.port.physical_port = data->port; + + byte = mei_cldev_send(cldev, (u8 *)&lc_init_in, sizeof(lc_init_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&lc_init_out, sizeof(lc_init_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (lc_init_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X Failed. status: 0x%X\n", + WIRED_INIT_LOCALITY_CHECK, lc_init_out.header.status); + return -EIO; + } + + lc_init_data->msg_id = HDCP_2_2_LC_INIT; + memcpy(lc_init_data->r_n, lc_init_out.r_n, HDCP_2_2_RN_LEN); + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -314,7 +370,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { mei_verify_receiver_cert_prepare_km, .verify_hprime = mei_verify_hprime, .store_pairing_info = mei_store_pairing_info, - .initiate_locality_check = NULL, + .initiate_locality_check = mei_initiate_locality_check, .verify_lprime = NULL, .get_session_key = NULL, .repeater_check_flow_prepare_ack = NULL,
Request to ME to verify the LPrime received from HDCP sink.
On Success, ME FW will verify the received Lprime by calculating and comparing with L.
This represents the completion of Locality Check.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 63 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 2a0369f46326..de8ffb589ca4 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -363,6 +363,66 @@ static int mei_initiate_locality_check(struct mei_cl_device *cldev, return 0; }
+/* + * mei_verify_lprime: + * Function to verify lprime. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * rx_lprime : Pointer for LC_Send_L_prime + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_verify_lprime(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_lc_send_lprime *rx_lprime) +{ + struct wired_cmd_validate_locality_in verify_lprime_in = { { 0 } }; + struct wired_cmd_validate_locality_out verify_lprime_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !rx_lprime) + return -EINVAL; + + dev = &cldev->dev; + + verify_lprime_in.header.api_version = HDCP_API_VERSION; + verify_lprime_in.header.command_id = WIRED_VALIDATE_LOCALITY; + verify_lprime_in.header.status = ME_HDCP_STATUS_SUCCESS; + verify_lprime_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VALIDATE_LOCALITY_IN; + + verify_lprime_in.port.integrated_port_type = data->port_type; + verify_lprime_in.port.physical_port = data->port; + + memcpy(verify_lprime_in.l_prime, rx_lprime->l_prime, + sizeof(rx_lprime->l_prime)); + + byte = mei_cldev_send(cldev, (u8 *)&verify_lprime_in, + sizeof(verify_lprime_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&verify_lprime_out, + sizeof(verify_lprime_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (verify_lprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", + WIRED_VALIDATE_LOCALITY, + verify_lprime_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -371,7 +431,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .verify_hprime = mei_verify_hprime, .store_pairing_info = mei_store_pairing_info, .initiate_locality_check = mei_initiate_locality_check, - .verify_lprime = NULL, + .verify_lprime = mei_verify_lprime, .get_session_key = NULL, .repeater_check_flow_prepare_ack = NULL, .verify_mprime = NULL, @@ -381,6 +441,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = {
static int mei_hdcp_component_bind(struct device *mei_kdev, struct device *i915_kdev, void *data) + { struct i915_hdcp_component *comp = data;
Request to ME to prepare the encrypted session key.
On Success, ME provides Encrypted session key. Function populates the HDCP2.2 authentication msg SKE_Send_Eks.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 62 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index de8ffb589ca4..8a065f17d6c9 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -423,6 +423,65 @@ static int mei_verify_lprime(struct mei_cl_device *cldev, return 0; }
+/* + * mei_get_session_key: + * Function to prepare SKE_Send_Eks. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * ske_data : Pointer for SKE_Send_Eks. + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_get_session_key(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_ske_send_eks *ske_data) +{ + struct wired_cmd_get_session_key_in get_skey_in = { { 0 } }; + struct wired_cmd_get_session_key_out get_skey_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data || !ske_data) + return -EINVAL; + + dev = &cldev->dev; + + get_skey_in.header.api_version = HDCP_API_VERSION; + get_skey_in.header.command_id = WIRED_GET_SESSION_KEY; + get_skey_in.header.status = ME_HDCP_STATUS_SUCCESS; + get_skey_in.header.buffer_len = WIRED_CMD_BUF_LEN_GET_SESSION_KEY_IN; + + get_skey_in.port.integrated_port_type = data->port_type; + get_skey_in.port.physical_port = data->port; + + byte = mei_cldev_send(cldev, (u8 *)&get_skey_in, sizeof(get_skey_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&get_skey_out, sizeof(get_skey_out)); + + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (get_skey_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", + WIRED_GET_SESSION_KEY, get_skey_out.header.status); + return -EIO; + } + + ske_data->msg_id = HDCP_2_2_SKE_SEND_EKS; + memcpy(ske_data->e_dkey_ks, get_skey_out.e_dkey_ks, + HDCP_2_2_E_DKEY_KS_LEN); + memcpy(ske_data->riv, get_skey_out.r_iv, HDCP_2_2_RIV_LEN); + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -432,7 +491,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .store_pairing_info = mei_store_pairing_info, .initiate_locality_check = mei_initiate_locality_check, .verify_lprime = mei_verify_lprime, - .get_session_key = NULL, + .get_session_key = mei_get_session_key, .repeater_check_flow_prepare_ack = NULL, .verify_mprime = NULL, .enable_hdcp_authentication = NULL, @@ -441,7 +500,6 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = {
static int mei_hdcp_component_bind(struct device *mei_kdev, struct device *i915_kdev, void *data) - { struct i915_hdcp_component *comp = data;
Request ME to verify the downstream topology information received.
ME FW will validate the Repeaters receiver id list and downstream topology.
On Success ME FW will provide the Least Significant 128bits of VPrime, which forms the repeater ack.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style and typos fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 77 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 8a065f17d6c9..1fa668a5f437 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -482,6 +482,80 @@ static int mei_get_session_key(struct mei_cl_device *cldev, return 0; }
+/* + * mei_repeater_check_flow_prepare_ack: + * Function to validate the Downstream topology and prepare rep_ack. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * rep_topology : Pointer for Receiver Id List to be validated. + * rep_send_ack : Pointer for repeater ack + * + * Returns 0 on Success, <0 on Failure + */ +static int +mei_repeater_check_flow_prepare_ack(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_rep_send_receiverid_list + *rep_topology, + struct hdcp2_rep_send_ack *rep_send_ack) +{ + struct wired_cmd_verify_repeater_in verify_repeater_in = { { 0 } }; + struct wired_cmd_verify_repeater_out verify_repeater_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!rep_topology || !rep_send_ack || !data) + return -EINVAL; + + dev = &cldev->dev; + + verify_repeater_in.header.api_version = HDCP_API_VERSION; + verify_repeater_in.header.command_id = WIRED_VERIFY_REPEATER; + verify_repeater_in.header.status = ME_HDCP_STATUS_SUCCESS; + verify_repeater_in.header.buffer_len = + WIRED_CMD_BUF_LEN_VERIFY_REPEATER_IN; + + verify_repeater_in.port.integrated_port_type = data->port_type; + verify_repeater_in.port.physical_port = data->port; + + memcpy(verify_repeater_in.rx_info, rep_topology->rx_info, + HDCP_2_2_RXINFO_LEN); + memcpy(verify_repeater_in.seq_num_v, rep_topology->seq_num_v, + HDCP_2_2_SEQ_NUM_LEN); + memcpy(verify_repeater_in.v_prime, rep_topology->v_prime, + HDCP_2_2_LPRIME_HALF_LEN); + memcpy(verify_repeater_in.receiver_ids, rep_topology->receiver_ids, + HDCP_2_2_RECEIVER_IDS_MAX_LEN); + + byte = mei_cldev_send(cldev, (u8 *)&verify_repeater_in, + sizeof(verify_repeater_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&verify_repeater_out, + sizeof(verify_repeater_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (verify_repeater_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", + WIRED_VERIFY_REPEATER, + verify_repeater_out.header.status); + return -EIO; + } + + memcpy(rep_send_ack->v, verify_repeater_out.v, + HDCP_2_2_LPRIME_HALF_LEN); + rep_send_ack->msg_id = HDCP_2_2_REP_SEND_ACK; + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -492,7 +566,8 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .initiate_locality_check = mei_initiate_locality_check, .verify_lprime = mei_verify_lprime, .get_session_key = mei_get_session_key, - .repeater_check_flow_prepare_ack = NULL, + .repeater_check_flow_prepare_ack = + mei_repeater_check_flow_prepare_ack, .verify_mprime = NULL, .enable_hdcp_authentication = NULL, .close_hdcp_session = NULL,
Request to ME to verify the M_Prime received from the HDCP sink.
ME FW will calculate the M and compare with M_prime received as part of RepeaterAuth_Stream_Ready, which is HDCP2.2 protocol msg.
On successful completion of this stage, downstream propagation of the stream management info is completed.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] endianness conversion func is moved to drm_hdcp.h [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 70 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 69 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 1fa668a5f437..3ff4de75ff21 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -556,6 +556,74 @@ mei_repeater_check_flow_prepare_ack(struct mei_cl_device *cldev, return 0; }
+/* + * mei_verify_mprime: + * Function to verify mprime. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * stream_ready : pointer for RepeaterAuth_Stream_Ready message. + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_verify_mprime(struct mei_cl_device *cldev, + struct mei_hdcp_data *data, + struct hdcp2_rep_stream_ready *stream_ready) +{ + struct wired_cmd_repeater_auth_stream_req_in + verify_mprime_in = { { 0 } }; + struct wired_cmd_repeater_auth_stream_req_out + verify_mprime_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!stream_ready || !data) + return -EINVAL; + + dev = &cldev->dev; + + verify_mprime_in.header.api_version = HDCP_API_VERSION; + verify_mprime_in.header.command_id = WIRED_REPEATER_AUTH_STREAM_REQ; + verify_mprime_in.header.status = ME_HDCP_STATUS_SUCCESS; + verify_mprime_in.header.buffer_len = + WIRED_CMD_BUF_LEN_REPEATER_AUTH_STREAM_REQ_MIN_IN; + + verify_mprime_in.port.integrated_port_type = data->port_type; + verify_mprime_in.port.physical_port = data->port; + + memcpy(verify_mprime_in.m_prime, stream_ready->m_prime, + HDCP_2_2_MPRIME_LEN); + reverse_endianness((u8 *)&verify_mprime_in.seq_num_m, + HDCP_2_2_SEQ_NUM_LEN, (u8 *)&data->seq_num_m); + memcpy(verify_mprime_in.streams, data->streams, + (data->k * sizeof(struct hdcp2_streamid_type))); + + verify_mprime_in.k = __swab16(data->k); + + byte = mei_cldev_send(cldev, (u8 *)&verify_mprime_in, + sizeof(verify_mprime_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&verify_mprime_out, + sizeof(verify_mprime_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (verify_mprime_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", + WIRED_REPEATER_AUTH_STREAM_REQ, + verify_mprime_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -568,7 +636,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .get_session_key = mei_get_session_key, .repeater_check_flow_prepare_ack = mei_repeater_check_flow_prepare_ack, - .verify_mprime = NULL, + .verify_mprime = mei_verify_mprime, .enable_hdcp_authentication = NULL, .close_hdcp_session = NULL, };
Request to ME to configure a port as authenticated.
On Success, ME FW will mark the port as authenticated and provides HDCP cipher with the encryption keys.
Enabling the Authentication can be requested once all stages of HDCP2.2 authentication is completed by interacting with ME FW.
Only after this stage, driver can enable the HDCP encryption for the port, through HW registers.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style and typos fixed [Uma] v5: Rebased.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 57 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index 3ff4de75ff21..c3d97a848c67 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -624,6 +624,60 @@ static int mei_verify_mprime(struct mei_cl_device *cldev, return 0; }
+/* + * mei_enable_hdcp_authentication: + * Function to request ME FW to mark a port as authenticated. + * + * cldev : Pointer for mei client device + * data : Intel HW specific Data + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_enable_hdcp_authentication(struct mei_cl_device *cldev, + struct mei_hdcp_data *data) +{ + struct wired_cmd_enable_auth_in enable_auth_in = { { 0 } }; + struct wired_cmd_enable_auth_out enable_auth_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data) + return -EINVAL; + + dev = &cldev->dev; + + enable_auth_in.header.api_version = HDCP_API_VERSION; + enable_auth_in.header.command_id = WIRED_ENABLE_AUTH; + enable_auth_in.header.status = ME_HDCP_STATUS_SUCCESS; + enable_auth_in.header.buffer_len = WIRED_CMD_BUF_LEN_ENABLE_AUTH_IN; + + enable_auth_in.port.integrated_port_type = data->port_type; + enable_auth_in.port.physical_port = data->port; + enable_auth_in.stream_type = data->streams[0].stream_type; + + byte = mei_cldev_send(cldev, (u8 *)&enable_auth_in, + sizeof(enable_auth_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&enable_auth_out, + sizeof(enable_auth_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (enable_auth_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "ME cmd 0x%08X failed. status: 0x%X\n", + WIRED_ENABLE_AUTH, enable_auth_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -637,7 +691,8 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .repeater_check_flow_prepare_ack = mei_repeater_check_flow_prepare_ack, .verify_mprime = mei_verify_mprime, - .enable_hdcp_authentication = NULL, + .enable_hdcp_authentication = + mei_enable_hdcp_authentication, .close_hdcp_session = NULL, };
Request the ME to terminate the HDCP2.2 session for a port.
On Success, ME FW will mark the intel port as Deauthenticated and terminate the wired HDCP2.2 Tx session started due to the cmd WIRED_INITIATE_HDCP2_SESSION.
v2: Rebased. v3: cldev is passed as first parameter [Tomas] Redundant comments and cast are removed [Tomas] v4: %zd for ssize_t [Alexander] %s/return -1/return -EIO [Alexander] Style and typos fixed [Uma] v5: Extra line is removed.
Signed-off-by: Ramalingam C ramalingam.c@intel.com --- drivers/misc/mei/hdcp/mei_hdcp.c | 56 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-)
diff --git a/drivers/misc/mei/hdcp/mei_hdcp.c b/drivers/misc/mei/hdcp/mei_hdcp.c index c3d97a848c67..8f5797e2eb51 100644 --- a/drivers/misc/mei/hdcp/mei_hdcp.c +++ b/drivers/misc/mei/hdcp/mei_hdcp.c @@ -678,6 +678,60 @@ static int mei_enable_hdcp_authentication(struct mei_cl_device *cldev, return 0; }
+/* + * mei_close_hdcp_session: + * Function to close the Wired HDCP Tx session of ME FW. + * This also disables the authenticated state of the port. + * + * data : Intel HW specific Data + * + * Returns 0 on Success, <0 on Failure + */ +static int mei_close_hdcp_session(struct mei_cl_device *cldev, + struct mei_hdcp_data *data) +{ + struct wired_cmd_close_session_in session_close_in = { { 0 } }; + struct wired_cmd_close_session_out session_close_out = { { 0 } }; + struct device *dev; + ssize_t byte; + + if (!data) + return -EINVAL; + + dev = &cldev->dev; + + session_close_in.header.api_version = HDCP_API_VERSION; + session_close_in.header.command_id = WIRED_CLOSE_SESSION; + session_close_in.header.status = ME_HDCP_STATUS_SUCCESS; + session_close_in.header.buffer_len = + WIRED_CMD_BUF_LEN_CLOSE_SESSION_IN; + + session_close_in.port.integrated_port_type = data->port_type; + session_close_in.port.physical_port = data->port; + + byte = mei_cldev_send(cldev, (u8 *)&session_close_in, + sizeof(session_close_in)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_send failed. %zd\n", byte); + return byte; + } + + byte = mei_cldev_recv(cldev, (u8 *)&session_close_out, + sizeof(session_close_out)); + if (byte < 0) { + dev_dbg(dev, "mei_cldev_recv failed. %zd\n", byte); + return byte; + } + + if (session_close_out.header.status != ME_HDCP_STATUS_SUCCESS) { + dev_dbg(dev, "Session Close Failed. status: 0x%X\n", + session_close_out.header.status); + return -EIO; + } + + return 0; +} + struct i915_hdcp_component_ops mei_hdcp_component_ops = { .owner = THIS_MODULE, .initiate_hdcp2_session = mei_initiate_hdcp2_session, @@ -693,7 +747,7 @@ struct i915_hdcp_component_ops mei_hdcp_component_ops = { .verify_mprime = mei_verify_mprime, .enable_hdcp_authentication = mei_enable_hdcp_authentication, - .close_hdcp_session = NULL, + .close_hdcp_session = mei_close_hdcp_session, };
static int mei_hdcp_component_bind(struct device *mei_kdev,
dri-devel@lists.freedesktop.org