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 20, 2018
1 parent 1aed7df commit 4482777
Show file tree
Hide file tree
Showing 10 changed files with 192 additions and 54 deletions.
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
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
170 changes: 139 additions & 31 deletions wsi/drm/drmdisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -178,26 +178,14 @@ 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);

if (value >= 0) {
switch (value) {
case 0:
current_protection_support_ = HWCContentProtection::kUnDesired;
break;
case 1:
current_protection_support_ = HWCContentProtection::kDesired;
break;
default:
break;
}
GetDrmObjectProperty("Content Protection", connector_props, &hdcp_id);
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 +201,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 +406,151 @@ 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 == HWCContentProtection::kEnabled) ||
(!current_state_ && val == HWCContentProtection::kDesired))
return true;

if (hdcp_id_prop_ <= 0) {
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_ <= 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
35 changes: 28 additions & 7 deletions wsi/drm/drmdisplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -108,6 +108,31 @@ class DrmDisplay : public PhysicalDisplay {
void HandleLazyInitialization() override;

private:
class DrmHDCPThread : public HWCThread {
public:
DrmHDCPThread(uint32_t gpu_fd, uint32_t connector, uint32_t hdcp_id,
uint32_t hdcp_cp_id);
~DrmHDCPThread() {
Exit();
}

bool SetHDCPState(bool enable, uint32_t type);

protected:
void HandleRoutine() override;
void HandleWait() override;

private:
bool DrmConnectorSetupHDCP();
bool CheckHDCPStatus();
uint32_t gpu_fd_;
uint32_t connector_;
uint32_t hdcp_id_;
uint32_t hdcp_cp_id_;
bool current_state_ = false;
uint32_t cp_type_ = 0;
};

void ShutDownPipe();
void GetDrmObjectPropertyValue(const char *name,
const ScopedDrmObjectPropertyPtr &props,
Expand Down Expand Up @@ -154,7 +179,6 @@ class DrmDisplay : public PhysicalDisplay {
uint32_t old_blob_id_ = 0;
uint32_t active_prop_ = 0;
uint32_t mode_id_prop_ = 0;
uint32_t hdcp_id_prop_ = 0;
uint32_t hdcp_srm_id_prop_ = 0;
uint32_t edid_prop_ = 0;
uint32_t canvas_color_prop_ = 0;
Expand All @@ -164,15 +188,12 @@ class DrmDisplay : public PhysicalDisplay {
int64_t broadcastrgb_full_ = -1;
int64_t broadcastrgb_automatic_ = -1;
uint32_t flags_ = DRM_MODE_ATOMIC_ALLOW_MODESET;
HWCContentProtection current_protection_support_ =
HWCContentProtection::kUnSupported;
HWCContentProtection desired_protection_support_ =
HWCContentProtection::kUnSupported;
drmModeModeInfo current_mode_;
HWCContentType content_type_ = kCONTENT_TYPE0;
std::vector<drmModeModeInfo> modes_;
SpinLock display_lock_;
bool protection_changed = false;
DrmDisplayManager *manager_;
std::unique_ptr<DrmHDCPThread> hdcp_thread_;
};

} // namespace hwcomposer
Expand Down

0 comments on commit 4482777

Please sign in to comment.