From 7aaa0e31fb5912a14d8512d483db43a9749f3448 Mon Sep 17 00:00:00 2001 From: Harish Krupo Date: Tue, 9 Oct 2018 04:33:15 +0000 Subject: [PATCH 1/2] tests: Add test for HDCP 2.2 Jira: None Test: ./testlayers -f 120 -j jsonconfigs/kmscube1layer.json &> log.txt Check log.txt to see if HDCP 1.4/2.2 was successfully enabled. Signed-off-by: Harish Krupo --- tests/apps/jsonlayerstest.cpp | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/tests/apps/jsonlayerstest.cpp b/tests/apps/jsonlayerstest.cpp index 02d50b827..670cf5f6b 100644 --- a/tests/apps/jsonlayerstest.cpp +++ b/tests/apps/jsonlayerstest.cpp @@ -411,6 +411,28 @@ class HotPlugEventCallback : public hwcomposer::DisplayHotPlugEventCallback { } } + bool EnableHDCP(hwcomposer::HWCContentType type) { + bool ret = true; + for (auto &display : connected_displays_) { + ret = ret && + display->SetHDCPState(hwcomposer::HWCContentProtection::kDesired, + type); + } + + return ret; + } + + bool DisableHDCP() { + bool ret = true; + for (auto &display : connected_displays_) { + ret = ret && + display->SetHDCPState(hwcomposer::HWCContentProtection::kUnDesired, + hwcomposer::HWCContentType::kInvalid); + } + + return ret; + } + private: std::vector connected_displays_; hwcomposer::GpuDevice *device_; @@ -964,6 +986,28 @@ int main(int argc, char *argv[]) { callback->SetContrast(0x80, 0x80, 0x80); callback->SetCanvasColor(0x0, 8); + // Test for HDCP 1.4: TYPE 0 content + + fprintf(stderr, "Trying to enable HDCP 1.4\n"); + ret = callback->EnableHDCP(hwcomposer::HWCContentType::kCONTENT_TYPE0); + if (!ret) { + fprintf(stderr, "Unable to enable HDCP 1.4\n"); + } else { + fprintf(stderr, "HDCP 1.4 successfully enabled\n"); + callback->DisableHDCP(); + } + + // Test for HDCP 2.2: TYPE 1 content + + fprintf(stderr, "Trying to enable HDCP 2.2\n"); + ret = callback->EnableHDCP(hwcomposer::HWCContentType::kCONTENT_TYPE1); + if (!ret) { + fprintf(stderr, "Unable to enable HDCP 2.2\n"); + } else { + fprintf(stderr, "HDCP 2.2 successfully enabled\n"); + callback->DisableHDCP(); + } + for (size_t i = 0; i < ARRAY_SIZE(frames); ++i) { struct frame *frame = &frames[i]; for (int32_t &fence : frame->fences) { From 2f3d0099eeec3799d8aeab2db1915466fcdab053 Mon Sep 17 00:00:00 2001 From: Harish Krupo Date: Wed, 17 Oct 2018 07:18:36 +0000 Subject: [PATCH 2/2] Add support for HDCP 2.2 With HDCP 2.2 a new connector property is added for marking the content type. This property controls the type of authentication that the kernel needs to perform. The content type property takes 2 values, 0 (TYPE0) and 1 (TYPE1). When the client marks the content as TYPE0, the kernel can choose whether to go for HDCP 1.4 or HDCP 2.2 authentication but when the client marks the content as TYPE1, the kernel is only allowed to attempt HDCP 2.2 authentication. Failing which, HDCP fails to enable. The spec states that the source needs to wait at least 5 seconds before declaring success/failure in authentication. Along with this wait, the kernel re-tries 3 times, thus the compositor needs to wait for ~15 seconds. Jira: None Test: Test introduced in jsonlayerstest.cpp in the previous patch Test it by running ./testlayers -f 120 -j jsonconfigs/kmscube1layer.json Change-Id: I5ee780157f074d295701c4f1aff9fc0f6a6d37a8 Signed-off-by: Harish Krupo --- common/core/logicaldisplay.cpp | 4 +- common/core/logicaldisplay.h | 2 +- common/core/logicaldisplaymanager.cpp | 10 ++- common/core/logicaldisplaymanager.h | 2 +- common/core/mosaicdisplay.cpp | 10 ++- common/core/mosaicdisplay.h | 2 +- public/hwcdefs.h | 13 ++-- public/nativedisplay.h | 3 +- wsi/drm/drmdisplay.cpp | 96 +++++++++++++++++++-------- wsi/drm/drmdisplay.h | 7 +- 10 files changed, 103 insertions(+), 46 deletions(-) diff --git a/common/core/logicaldisplay.cpp b/common/core/logicaldisplay.cpp index dce7f8039..8f076d976 100644 --- a/common/core/logicaldisplay.cpp +++ b/common/core/logicaldisplay.cpp @@ -68,9 +68,9 @@ bool LogicalDisplay::SetPowerMode(uint32_t power_mode) { return true; } -void LogicalDisplay::SetHDCPState(HWCContentProtection state, +bool LogicalDisplay::SetHDCPState(HWCContentProtection state, HWCContentType content_type) { - logical_display_manager_->SetHDCPState(state, content_type); + return logical_display_manager_->SetHDCPState(state, content_type); } void LogicalDisplay::SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) { diff --git a/common/core/logicaldisplay.h b/common/core/logicaldisplay.h index f09478b4c..883fdf8aa 100644 --- a/common/core/logicaldisplay.h +++ b/common/core/logicaldisplay.h @@ -122,7 +122,7 @@ class LogicalDisplay : public NativeDisplay { void HotPlugUpdate(bool connected) override; - void SetHDCPState(HWCContentProtection state, + bool SetHDCPState(HWCContentProtection state, HWCContentType content_type) override; void SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) override; diff --git a/common/core/logicaldisplaymanager.cpp b/common/core/logicaldisplaymanager.cpp index 67741c30e..f2baa4409 100644 --- a/common/core/logicaldisplaymanager.cpp +++ b/common/core/logicaldisplaymanager.cpp @@ -223,12 +223,18 @@ void LogicalDisplayManager::GetLogicalDisplays( } } -void LogicalDisplayManager::SetHDCPState(HWCContentProtection state, +bool LogicalDisplayManager::SetHDCPState(HWCContentProtection state, HWCContentType content_type) { uint32_t size = displays_.size(); + bool ret = true; for (uint32_t i = 0; i < size; i++) { - displays_.at(i)->SetHDCPState(state, content_type); + if (ret) + ret = displays_.at(i)->SetHDCPState(state, content_type); + else + break; } + + return ret; } void LogicalDisplayManager::SetHDCPSRM(const int8_t* SRM, uint32_t SRMLength) { diff --git a/common/core/logicaldisplaymanager.h b/common/core/logicaldisplaymanager.h index 7289c25e8..ff183d23f 100644 --- a/common/core/logicaldisplaymanager.h +++ b/common/core/logicaldisplaymanager.h @@ -95,7 +95,7 @@ class LogicalDisplayManager { * @param state an enum named HWCContentProtection * @param content_type an enum of HWCContentType */ - void SetHDCPState(HWCContentProtection state, HWCContentType content_type); + bool SetHDCPState(HWCContentProtection state, HWCContentType content_type); void SetHDCPSRM(const int8_t* SRM, uint32_t SRMLength); diff --git a/common/core/mosaicdisplay.cpp b/common/core/mosaicdisplay.cpp index a6eaa44b6..d76148e43 100644 --- a/common/core/mosaicdisplay.cpp +++ b/common/core/mosaicdisplay.cpp @@ -504,12 +504,18 @@ bool MosaicDisplay::GetDisplayName(uint32_t *size, char *name) { return true; } -void MosaicDisplay::SetHDCPState(HWCContentProtection state, +bool MosaicDisplay::SetHDCPState(HWCContentProtection state, HWCContentType content_type) { uint32_t size = physical_displays_.size(); + bool ret = true; for (uint32_t i = 0; i < size; i++) { - physical_displays_.at(i)->SetHDCPState(state, content_type); + if (ret) + ret = physical_displays_.at(i)->SetHDCPState(state, content_type); + else + break; } + + return ret; } void MosaicDisplay::SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) { diff --git a/common/core/mosaicdisplay.h b/common/core/mosaicdisplay.h index 03fd32f8a..a065fc9fd 100644 --- a/common/core/mosaicdisplay.h +++ b/common/core/mosaicdisplay.h @@ -109,7 +109,7 @@ class MosaicDisplay : public NativeDisplay { void HotPlugUpdate(bool connected); - void SetHDCPState(HWCContentProtection state, + bool SetHDCPState(HWCContentProtection state, HWCContentType content_type) override; void SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) override; diff --git a/public/hwcdefs.h b/public/hwcdefs.h index f320f3801..5e37d3140 100644 --- a/public/hwcdefs.h +++ b/public/hwcdefs.h @@ -40,15 +40,16 @@ enum class HWCBlending : int32_t { // Enumerations for content protection. enum HWCContentProtection { - kUnSupported = 0, // Content Protection is not supported. - kUnDesired = 1, // Content Protection is not required. - kDesired = 2 // Content Protection is desired. + kUnSupported = -1, // Content Protection is not supported. + kUnDesired = 0, // Content Protection is not required. + kDesired = 1, // Content Protection is desired. + kEnabled = 2 }; enum HWCContentType { - kInvalid, // Used when disabling HDCP. - kCONTENT_TYPE0, // Can support any HDCP specifiction. - kCONTENT_TYPE1, // Can support only HDCP 2.2 and higher specification. + kInvalid = -1, // Used when disabling HDCP. + kCONTENT_TYPE0 = 0, // Can support any HDCP specifiction. + kCONTENT_TYPE1 = 1, // Can support only HDCP 2.2 and higher specification. }; enum HWCTransform : uint32_t { diff --git a/public/nativedisplay.h b/public/nativedisplay.h index fdc02358d..473526cb9 100644 --- a/public/nativedisplay.h +++ b/public/nativedisplay.h @@ -400,8 +400,9 @@ class NativeDisplay { * tries to take advantage of any HDCP support advertised by * the Kernel. */ - virtual void SetHDCPState(HWCContentProtection /*state*/, + virtual bool SetHDCPState(HWCContentProtection /*state*/, HWCContentType /*content_type*/) { + return false; } virtual void SetPAVPSessionStatus(bool enabled, uint32_t pavp_session_id, diff --git a/wsi/drm/drmdisplay.cpp b/wsi/drm/drmdisplay.cpp index 961d91d00..0f00356bb 100644 --- a/wsi/drm/drmdisplay.cpp +++ b/wsi/drm/drmdisplay.cpp @@ -182,22 +182,12 @@ bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info, GetDrmHDCPObjectProperty("Content Protection", connector, connector_props, &hdcp_id_prop_, &value); - if (value >= 0) { - switch (value) { - case 0: - current_protection_support_ = HWCContentProtection::kUnDesired; - break; - case 1: - current_protection_support_ = HWCContentProtection::kDesired; - break; - default: - break; - } + current_protection_support_ = static_cast(value); - if (desired_protection_support_ == HWCContentProtection::kUnSupported) { - desired_protection_support_ = current_protection_support_; - } - } + GetDrmHDCPObjectProperty("CP_Content_Type", connector, connector_props, + &hdcp_type_prop_, &value); + + current_content_type_ = static_cast(value); GetDrmHDCPObjectProperty("CP_SRM", connector, connector_props, &hdcp_srm_id_prop_, &value); @@ -213,7 +203,6 @@ bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info, ITRACE("DCIP3 support not available"); PhysicalDisplay::Connect(); - SetHDCPState(desired_protection_support_, content_type_); drmModePropertyPtr broadcastrgb_props = drmModeGetProperty(gpu_fd_, broadcastrgb_id_); @@ -419,30 +408,81 @@ bool DrmDisplay::SetBroadcastRGB(const char *range_property) { return true; } -void DrmDisplay::SetHDCPState(HWCContentProtection state, +bool DrmDisplay::CheckHDCPStatus() { + int val = -1; + uint32_t i; + ScopedDrmObjectPropertyPtr cprops(drmModeObjectGetProperties( + gpu_fd_, connector_, DRM_MODE_OBJECT_CONNECTOR)); + for (i = 0; i < cprops->count_props; i++) { + if (cprops->props[i] == hdcp_id_prop_) { + val = cprops->prop_values[i]; + break; + } + } + + if ((current_protection_support_ && val == HWCContentProtection::kEnabled) || + (!current_protection_support_ && val == HWCContentProtection::kDesired)) + return true; + + return false; +} + +bool DrmDisplay::SetHDCPState(HWCContentProtection state, HWCContentType content_type) { desired_protection_support_ = state; - content_type_ = content_type; - if (desired_protection_support_ == current_protection_support_) - return; + desired_content_type_ = content_type; + + if (desired_protection_support_ == current_protection_support_ && + desired_content_type_ == current_content_type_) + return true; if (hdcp_id_prop_ <= 0) { ETRACE("Cannot set HDCP state as Connector property is not supported \n"); - return; + return false; + } + if ((hdcp_type_prop_ <= 0) && (desired_content_type_ == 1)) { + ETRACE("Content type property unavailable. HDCP 2.2 cannot be enabled\n"); + return false; } if (!(connection_state_ & kConnected)) { - return; + return false; } - current_protection_support_ = desired_protection_support_; - uint32_t value = 0; - if (current_protection_support_ == kDesired) { - value = 1; + ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc()); + int ret = drmModeAtomicAddProperty(pset.get(), connector_, hdcp_id_prop_, + desired_protection_support_) < 0; + if (current_protection_support_ && (hdcp_type_prop_ > 0)) + ret = ret || + drmModeAtomicAddProperty(pset.get(), connector_, hdcp_type_prop_, + desired_content_type_) < 0; + if (ret) { + ETRACE("Unable to fill pset for HDCP\n"); + return false; + } + ret = drmModeAtomicCommit(gpu_fd_, pset.get(), DRM_MODE_ATOMIC_ALLOW_MODESET, + NULL); + if (ret) { + ETRACE("Failed to commit HDCP ret %d errno %d : %s\n", ret, errno, + PRINTERROR()); + return false; } - drmModeConnectorSetProperty(gpu_fd_, connector_, hdcp_id_prop_, value); - ETRACE("Ignored Content type. \n"); + /* Wait for Enable should be 5.1 Sec * 3(kernel reattempt cnt) */ + for (uint8_t i = 0; i < 160; i++) { + if (CheckHDCPStatus()) { + current_protection_support_ = desired_protection_support_; + current_content_type_ = desired_content_type_; + return true; + } + usleep(100 * 1000); + } + + // HDCP failed to enable, mark it as undesired + drmModeConnectorSetProperty(gpu_fd_, connector_, hdcp_id_prop_, + HWCContentProtection::kUnDesired); + + return false; } void DrmDisplay::SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) { diff --git a/wsi/drm/drmdisplay.h b/wsi/drm/drmdisplay.h index 790708291..faf9145b2 100644 --- a/wsi/drm/drmdisplay.h +++ b/wsi/drm/drmdisplay.h @@ -53,7 +53,7 @@ class DrmDisplay : public PhysicalDisplay { bool SetBroadcastRGB(const char *range_property) override; - void SetHDCPState(HWCContentProtection state, + bool SetHDCPState(HWCContentProtection state, HWCContentType content_type) override; void SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) override; @@ -139,6 +139,7 @@ class DrmDisplay : public PhysicalDisplay { std::vector FindExtendedBlocksForTag(uint8_t *edid, uint8_t block_tag); void DrmConnectorGetDCIP3Support(const ScopedDrmObjectPropertyPtr &props); + bool CheckHDCPStatus(); uint32_t crtc_id_ = 0; uint32_t mmWidth_ = 0; @@ -155,6 +156,7 @@ class DrmDisplay : public PhysicalDisplay { uint32_t active_prop_ = 0; uint32_t mode_id_prop_ = 0; uint32_t hdcp_id_prop_ = 0; + uint32_t hdcp_type_prop_ = 0; uint32_t hdcp_srm_id_prop_ = 0; uint32_t edid_prop_ = 0; uint32_t canvas_color_prop_ = 0; @@ -169,7 +171,8 @@ class DrmDisplay : public PhysicalDisplay { HWCContentProtection desired_protection_support_ = HWCContentProtection::kUnSupported; drmModeModeInfo current_mode_; - HWCContentType content_type_ = kCONTENT_TYPE0; + HWCContentType current_content_type_ = kCONTENT_TYPE0; + HWCContentType desired_content_type_ = kInvalid; std::vector modes_; SpinLock display_lock_; DrmDisplayManager *manager_;