Skip to content
This repository has been archived by the owner on Oct 8, 2024. It is now read-only.

Commit

Permalink
Add support for HDCP 2.2
Browse files Browse the repository at this point in the history
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.
Once HDCP is enabled, it is expected that the compositor should continuously poll the
connector property to ensure that HDCP is active. If HDCP gets disabled due to link
failure, the compositor should re-try the authentication either till it succeeds or the
client notifies that it doesn't require HDCP.
This patch adds code to fulfill the above requirements.

Jira: None
Test: Test introduced in jsonlayerstest.cpp in the previous patch
      Test it by running ./testlayers -f 120 -j jsonconfigs/kmscube1layer.json

Signed-off-by: Harish Krupo <[email protected]>
  • Loading branch information
harishkrupo committed Oct 17, 2018
1 parent 3181dd0 commit 571cddc
Show file tree
Hide file tree
Showing 12 changed files with 198 additions and 62 deletions.
14 changes: 7 additions & 7 deletions common/core/gpudevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -583,15 +583,15 @@ void GpuDevice::HandleHWCSettings() {
}
}

void GpuDevice::EnableHDCPSessionForDisplay(uint32_t display,
bool GpuDevice::EnableHDCPSessionForDisplay(uint32_t display,
HWCContentType content_type) {
if (total_displays_.size() <= display) {
ETRACE("Tried to enable HDCP for invalid display %u \n", display);
return;
return false;
}

NativeDisplay *native_display = total_displays_.at(display);
native_display->SetHDCPState(HWCContentProtection::kDesired, content_type);
return native_display->SetHDCPState(HWCContentProtection::kDesired, content_type);
}

void GpuDevice::EnableHDCPSessionForAllDisplays(HWCContentType content_type) {
Expand All @@ -602,15 +602,15 @@ void GpuDevice::EnableHDCPSessionForAllDisplays(HWCContentType content_type) {
}
}

void GpuDevice::DisableHDCPSessionForDisplay(uint32_t display) {
bool GpuDevice::DisableHDCPSessionForDisplay(uint32_t display) {
if (total_displays_.size() <= display) {
ETRACE("Tried to enable HDCP for invalid display %u \n", display);
return;
return false;
}

NativeDisplay *native_display = total_displays_.at(display);
native_display->SetHDCPState(HWCContentProtection::kUnDesired,
HWCContentType::kInvalid);
return native_display->SetHDCPState(HWCContentProtection::kUnDesired,
HWCContentType::kInvalid);
}

void GpuDevice::DisableHDCPSessionForAllDisplays() {
Expand Down
4 changes: 2 additions & 2 deletions common/core/logicaldisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion common/core/logicaldisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 5 additions & 2 deletions common/core/logicaldisplaymanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -223,12 +223,15 @@ 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);
ret = ret && displays_.at(i)->SetHDCPState(state, content_type);
}

return ret;
}

void LogicalDisplayManager::SetHDCPSRM(const int8_t* SRM, uint32_t SRMLength) {
Expand Down
2 changes: 1 addition & 1 deletion common/core/logicaldisplaymanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
7 changes: 5 additions & 2 deletions common/core/mosaicdisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,12 +504,15 @@ 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);
ret = ret && physical_displays_.at(i)->SetHDCPState(state, content_type);
}

return ret;
}

void MosaicDisplay::SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) {
Expand Down
2 changes: 1 addition & 1 deletion common/core/mosaicdisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions public/gpudevice.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class GpuDevice : public HWCThread {
// have ability to fallback to older specifications i.e. HDCP 2.2 and 1.4
// in case latest speicification cannot be supported for some reason.
// Content type is defined by content_type.
void EnableHDCPSessionForDisplay(uint32_t display,
bool EnableHDCPSessionForDisplay(uint32_t display,
HWCContentType content_type);

// Enables the usage of HDCP for all planes supporting this feature
Expand All @@ -76,7 +76,7 @@ class GpuDevice : public HWCThread {

// The control disables the usage of HDCP for all planes supporting this
// feature on display.
void DisableHDCPSessionForDisplay(uint32_t display);
bool DisableHDCPSessionForDisplay(uint32_t display);

// The control disables the usage of HDCP for all planes supporting this
// feature on all connected displays.
Expand Down
14 changes: 8 additions & 6 deletions public/hwcdefs.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

#include <unordered_map>
#include <vector>
#include "hwcthread.h"

namespace hwcomposer {

Expand All @@ -40,15 +41,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 {
Expand Down
3 changes: 2 additions & 1 deletion public/nativedisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
166 changes: 136 additions & 30 deletions wsi/drm/drmdisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,26 +178,15 @@ bool DrmDisplay::ConnectDisplay(const drmModeModeInfo &mode_info,
return false;
}

uint32_t hdcp_id = 0, hdcp_cp_id = 0;
int value = -1;
GetDrmHDCPObjectProperty("Content Protection", connector, connector_props,
&hdcp_id_prop_, &value);
&hdcp_id, &value);

if (value >= 0) {
switch (value) {
case 0:
current_protection_support_ = HWCContentProtection::kUnDesired;
break;
case 1:
current_protection_support_ = HWCContentProtection::kDesired;
break;
default:
break;
}
GetDrmObjectProperty("CP_Content_Type", connector_props, &hdcp_cp_id);

if (desired_protection_support_ == HWCContentProtection::kUnSupported) {
desired_protection_support_ = current_protection_support_;
}
}
hdcp_thread_.reset(
new DrmHDCPThread(gpu_fd_, connector_, hdcp_id, hdcp_cp_id));

GetDrmHDCPObjectProperty("CP_SRM", connector, connector_props,
&hdcp_srm_id_prop_, &value);
Expand All @@ -213,7 +202,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_);
Expand Down Expand Up @@ -419,30 +407,148 @@ bool DrmDisplay::SetBroadcastRGB(const char *range_property) {
return true;
}

void DrmDisplay::SetHDCPState(HWCContentProtection state,
HWCContentType content_type) {
desired_protection_support_ = state;
content_type_ = content_type;
if (desired_protection_support_ == current_protection_support_)
return;
DrmDisplay::DrmHDCPThread::DrmHDCPThread(uint32_t gpu_fd, uint32_t connector,
uint32_t hdcp_id, uint32_t hdcp_cp_id)
: HWCThread(-8, "HDCPThread"),
gpu_fd_(gpu_fd),
connector_(connector),
hdcp_id_(hdcp_id),
hdcp_cp_id_(hdcp_cp_id) {
}

bool DrmDisplay::DrmHDCPThread::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_) {
val = cprops->prop_values[i];
break;
}
}

if ((current_state_ && val == 2) || (!current_state_ && val == 0))
return true;

return false;
}

bool DrmDisplay::DrmHDCPThread::DrmConnectorSetupHDCP() {
int i;
ScopedDrmAtomicReqPtr pset(drmModeAtomicAlloc());

int ret = drmModeAtomicAddProperty(pset.get(), connector_, hdcp_id_,
current_state_) < 0;

if (current_state_ && (hdcp_cp_id_ > 0))
ret = ret || drmModeAtomicAddProperty(pset.get(), connector_, hdcp_cp_id_,
cp_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;
}

/* Wait for Enable should be 5.1 Sec * 3(kernel reattempt cnt) */
for (i = 0; i < 160; i++) {
if (CheckHDCPStatus())
return true;
usleep(100 * 1000);
}

return false;
}

bool DrmDisplay::DrmHDCPThread::SetHDCPState(bool enable, uint32_t type) {
bool ret;

if (hdcp_id_prop_ <= 0) {
if ((hdcp_id_ <= 0)) {
ETRACE("Cannot set HDCP state as Connector property is not supported \n");
return;
return false;
}

if ((hdcp_cp_id_ <= 0) && (type == 1)) {
ETRACE("Content type property unavailable. HDCP 2.2 cannot be enabled\n");
return false;
}

if (enable == current_state_) {
ITRACE("HDCP already enabled");
return true;
}

current_state_ = enable;
cp_type_ = type;

if (!enable) {
Exit();
ret = DrmConnectorSetupHDCP();
} else {
ret = DrmConnectorSetupHDCP();
if (ret && !InitWorker()) {
ETRACE("Failed to start hdcp poll thread. %s", PRINTERROR());
}
}

if (!ret) {
current_state_ = !enable;
// if we tried to enable hdcp and failed
// toggle the property from desired -> undesired
if (enable)
DrmConnectorSetupHDCP();
}

return ret;
}

void DrmDisplay::DrmHDCPThread::HandleWait() {
usleep(50 * 1000);
}

void DrmDisplay::DrmHDCPThread::HandleRoutine() {
if (!CheckHDCPStatus()) {
ETRACE("HDCP link failed. Re-trying to establish the link");
DrmConnectorSetupHDCP();
}
}

bool DrmDisplay::SetHDCPState(HWCContentProtection state,
HWCContentType content_type) {

bool ret = false;
std::string err_str;
if (!(connection_state_ & kConnected)) {
return;
ITRACE("Display not connected. Cannot set HDCP state");
return ret;
}

current_protection_support_ = desired_protection_support_;
uint32_t value = 0;
if (current_protection_support_ == kDesired) {
if (state == kDesired) {
value = 1;
}

drmModeConnectorSetProperty(gpu_fd_, connector_, hdcp_id_prop_, value);
ETRACE("Ignored Content type. \n");
ret = hdcp_thread_->SetHDCPState(value, content_type);
if (ret) {
if (value)
err_str = "Successfully enabled HDCP\n";
else
err_str = "Successfully disabled HDCP\n";
} else {
if (value)
err_str = "Unable to enable HDCP\n";
else
err_str = "Unable to disable HDCP\n";
}

ITRACE("%s", err_str.c_str());

return ret;
}

void DrmDisplay::SetHDCPSRM(const int8_t *SRM, uint32_t SRMLength) {
Expand Down
Loading

0 comments on commit 571cddc

Please sign in to comment.