drm/amd/display: Add DCN3.1 HDCP support

New DTM interface is V3 and we need to extend our existing support
to enable HDCP on DCN3.1.

Version the helpers and fallback to the older versions on failure
in the new interfaces.

Acked-by: Huang Rui <ray.huang@amd.com>
Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Nicholas Kazlauskas 2021-05-19 12:37:16 -04:00 committed by Alex Deucher
parent 809fe88d83
commit bf62221e9d
6 changed files with 214 additions and 4 deletions

View File

@ -454,6 +454,13 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
display->dig_fe = config->dig_fe;
link->dig_be = config->dig_be;
link->ddc_line = aconnector->dc_link->ddc_hw_inst + 1;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
display->stream_enc_idx = config->stream_enc_idx;
link->link_enc_idx = config->link_enc_idx;
link->phy_idx = config->phy_idx;
link->hdcp_supported_informational = dc_link_is_hdcp14(aconnector->dc_link,
aconnector->dc_sink->sink_signal) ? 1 : 0;
#endif
link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw;
link->dp.assr_enabled = config->assr_enabled;
link->dp.mst_enabled = config->mst_enabled;
@ -637,6 +644,12 @@ struct hdcp_workqueue *hdcp_create_workqueue(struct amdgpu_device *adev, struct
INIT_DELAYED_WORK(&hdcp_work[i].property_validate_dwork, event_property_validate);
hdcp_work[i].hdcp.config.psp.handle = &adev->psp;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
if (dc->ctx->dce_version == DCN_VERSION_3_1) {
hdcp_work[i].hdcp.config.psp.caps.dtm_v3_supported = 1;
hdcp_work[i].hdcp.config.psp.caps.opm_state_query_supported = false;
}
#endif
hdcp_work[i].hdcp.config.ddc.handle = dc_get_link_at_index(dc, i);
hdcp_work[i].hdcp.config.ddc.funcs.write_i2c = lp_write_i2c;
hdcp_work[i].hdcp.config.ddc.funcs.read_i2c = lp_read_i2c;

View File

@ -32,6 +32,11 @@ struct cp_psp_stream_config {
uint8_t otg_inst;
uint8_t dig_be;
uint8_t dig_fe;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
uint8_t link_enc_idx;
uint8_t stream_enc_idx;
uint8_t phy_idx;
#endif
uint8_t assr_enabled;
uint8_t mst_enabled;
void *dm_stream_ctx;

View File

@ -172,6 +172,10 @@ char *mod_hdcp_status_to_str(int32_t status)
return "MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE";
case MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE:
return "MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE";
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
case MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE:
return "MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE";
#endif
default:
return "MOD_HDCP_STATUS_UNKNOWN";
}

View File

@ -44,11 +44,16 @@ static void hdcp2_message_init(struct mod_hdcp *hdcp,
in->process.msg3_desc.msg_id = TA_HDCP_HDCP2_MSG_ID__NULL_MESSAGE;
in->process.msg3_desc.msg_size = 0;
}
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
static enum mod_hdcp_status mod_hdcp_remove_display_from_topology_v2(
struct mod_hdcp *hdcp, uint8_t index)
#else
enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
struct mod_hdcp *hdcp, uint8_t index)
{
struct psp_context *psp = hdcp->config.psp.handle;
struct ta_dtm_shared_memory *dtm_cmd;
#endif
{
struct psp_context *psp = hdcp->config.psp.handle;
struct ta_dtm_shared_memory *dtm_cmd;
struct mod_hdcp_display *display =
get_active_display_at_index(hdcp, index);
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
@ -79,8 +84,66 @@ enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
mutex_unlock(&psp->dtm_context.mutex);
return status;
}
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
static enum mod_hdcp_status mod_hdcp_remove_display_from_topology_v3(
struct mod_hdcp *hdcp, uint8_t index)
{
struct psp_context *psp = hdcp->config.psp.handle;
struct ta_dtm_shared_memory *dtm_cmd;
struct mod_hdcp_display *display =
get_active_display_at_index(hdcp, index);
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf;
if (!display || !is_display_active(display))
return MOD_HDCP_STATUS_DISPLAY_NOT_FOUND;
mutex_lock(&psp->dtm_context.mutex);
memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3;
dtm_cmd->dtm_in_message.topology_update_v3.display_handle = display->index;
dtm_cmd->dtm_in_message.topology_update_v3.is_active = 0;
dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE;
psp_dtm_invoke(psp, dtm_cmd->cmd_id);
if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) {
status = mod_hdcp_remove_display_from_topology_v2(hdcp, index);
if (status != MOD_HDCP_STATUS_SUCCESS)
display->state = MOD_HDCP_DISPLAY_INACTIVE;
} else {
display->state = MOD_HDCP_DISPLAY_ACTIVE;
HDCP_TOP_REMOVE_DISPLAY_TRACE(hdcp, display->index);
}
mutex_unlock(&psp->dtm_context.mutex);
return status;
}
enum mod_hdcp_status mod_hdcp_remove_display_from_topology(
struct mod_hdcp *hdcp, uint8_t index)
{
enum mod_hdcp_status status = MOD_HDCP_STATUS_UPDATE_TOPOLOGY_FAILURE;
if (hdcp->config.psp.caps.dtm_v3_supported)
status = mod_hdcp_remove_display_from_topology_v3(hdcp, index);
else
status = mod_hdcp_remove_display_from_topology_v2(hdcp, index);
return status;
}
#endif
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
static enum mod_hdcp_status mod_hdcp_add_display_to_topology_v2(
struct mod_hdcp *hdcp, struct mod_hdcp_display *display)
#else
enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp,
struct mod_hdcp_display *display)
#endif
{
struct psp_context *psp = hdcp->config.psp.handle;
struct ta_dtm_shared_memory *dtm_cmd;
@ -126,6 +189,72 @@ enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp,
return status;
}
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
static enum mod_hdcp_status mod_hdcp_add_display_to_topology_v3(
struct mod_hdcp *hdcp, struct mod_hdcp_display *display)
{
struct psp_context *psp = hdcp->config.psp.handle;
struct ta_dtm_shared_memory *dtm_cmd;
struct mod_hdcp_link *link = &hdcp->connection.link;
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
if (!psp->dtm_context.dtm_initialized) {
DRM_INFO("Failed to add display topology, DTM TA is not initialized.");
display->state = MOD_HDCP_DISPLAY_INACTIVE;
return MOD_HDCP_STATUS_FAILURE;
}
dtm_cmd = (struct ta_dtm_shared_memory *)psp->dtm_context.dtm_shared_buf;
mutex_lock(&psp->dtm_context.mutex);
memset(dtm_cmd, 0, sizeof(struct ta_dtm_shared_memory));
dtm_cmd->cmd_id = TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3;
dtm_cmd->dtm_in_message.topology_update_v3.display_handle = display->index;
dtm_cmd->dtm_in_message.topology_update_v3.is_active = 1;
dtm_cmd->dtm_in_message.topology_update_v3.controller = display->controller;
dtm_cmd->dtm_in_message.topology_update_v3.ddc_line = link->ddc_line;
dtm_cmd->dtm_in_message.topology_update_v3.link_enc = link->link_enc_idx;
dtm_cmd->dtm_in_message.topology_update_v3.stream_enc = display->stream_enc_idx;
if (is_dp_hdcp(hdcp))
dtm_cmd->dtm_in_message.topology_update_v3.is_assr = link->dp.assr_enabled;
dtm_cmd->dtm_in_message.topology_update_v3.dp_mst_vcid = display->vc_id;
dtm_cmd->dtm_in_message.topology_update_v3.max_hdcp_supported_version =
TA_DTM_HDCP_VERSION_MAX_SUPPORTED__2_3;
dtm_cmd->dtm_in_message.topology_update_v3.encoder_type = TA_DTM_ENCODER_TYPE__DIG;
dtm_cmd->dtm_status = TA_DTM_STATUS__GENERIC_FAILURE;
dtm_cmd->dtm_in_message.topology_update_v3.phy_id = link->phy_idx;
dtm_cmd->dtm_in_message.topology_update_v3.link_hdcp_cap = link->hdcp_supported_informational;
psp_dtm_invoke(psp, dtm_cmd->cmd_id);
if (dtm_cmd->dtm_status != TA_DTM_STATUS__SUCCESS) {
status = mod_hdcp_add_display_to_topology_v2(hdcp, display);
if (status != MOD_HDCP_STATUS_SUCCESS)
display->state = MOD_HDCP_DISPLAY_INACTIVE;
} else {
HDCP_TOP_ADD_DISPLAY_TRACE(hdcp, display->index);
}
mutex_unlock(&psp->dtm_context.mutex);
return status;
}
enum mod_hdcp_status mod_hdcp_add_display_to_topology(struct mod_hdcp *hdcp,
struct mod_hdcp_display *display)
{
enum mod_hdcp_status status = MOD_HDCP_STATUS_SUCCESS;
if (hdcp->config.psp.caps.dtm_v3_supported)
status = mod_hdcp_add_display_to_topology_v3(hdcp, display);
else
status = mod_hdcp_add_display_to_topology_v2(hdcp, display);
return status;
}
#endif
enum mod_hdcp_status mod_hdcp_hdcp1_create_session(struct mod_hdcp *hdcp)
{

View File

@ -44,7 +44,12 @@ enum bgd_security_hdcp2_content_type {
enum ta_dtm_command {
TA_DTM_COMMAND__UNUSED_1 = 1,
TA_DTM_COMMAND__TOPOLOGY_UPDATE_V2,
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE,
TA_DTM_COMMAND__TOPOLOGY_UPDATE_V3
#else
TA_DTM_COMMAND__TOPOLOGY_ASSR_ENABLE
#endif
};
/* DTM related enumerations */
@ -86,6 +91,33 @@ struct ta_dtm_topology_update_input_v2 {
uint32_t max_hdcp_supported_version;
};
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
/* For security reason/HW may change value, these encoder type enum values are not HW register values */
/* Security code will check real HW register values and these SW enum values */
enum ta_dtm_encoder_type {
TA_DTM_ENCODER_TYPE__INVALID = 0,
TA_DTM_ENCODER_TYPE__DIG = 0x10
};
struct ta_dtm_topology_update_input_v3 {
/* display handle is unique across the driver and is used to identify a display */
/* for all security interfaces which reference displays such as HDCP */
/* link_hdcp_cap means link is HDCP-capable for audio HDCP capable property(informational), not for other logic(e.g. Crossbar) */
uint32_t display_handle;
uint32_t is_active;
uint32_t is_miracast;
uint32_t controller;
uint32_t ddc_line;
uint32_t link_enc;
uint32_t stream_enc;
uint32_t dp_mst_vcid;
uint32_t is_assr;
uint32_t max_hdcp_supported_version;
enum ta_dtm_encoder_type encoder_type;
uint32_t phy_id;
uint32_t link_hdcp_cap;
};
#endif
struct ta_dtm_topology_assr_enable {
uint32_t display_topology_dig_be_index;
};
@ -99,6 +131,9 @@ struct ta_dtm_topology_assr_enable {
union ta_dtm_cmd_input {
struct ta_dtm_topology_update_input_v2 topology_update_v2;
struct ta_dtm_topology_assr_enable topology_assr_enable;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
struct ta_dtm_topology_update_input_v3 topology_update_v3;
#endif
};
union ta_dtm_cmd_output {
@ -278,6 +313,9 @@ enum ta_hdcp2_version {
TA_HDCP2_VERSION_UNKNOWN = 0,
TA_HDCP2_VERSION_2_0 = 20,
TA_HDCP2_VERSION_2_1 = 21,
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
TA_HDCP2_VERSION_2_3 = 23,
#endif
TA_HDCP2_VERSION_2_2 = 22
};

View File

@ -1,5 +1,5 @@
/*
* Copyright 2019 Advanced Micro Devices, Inc.
* Copyright 2018 Advanced Micro Devices, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -97,6 +97,9 @@ enum mod_hdcp_status {
MOD_HDCP_STATUS_HDCP2_REAUTH_REQUEST,
MOD_HDCP_STATUS_HDCP2_REAUTH_LINK_INTEGRITY_FAILURE,
MOD_HDCP_STATUS_HDCP2_DEVICE_COUNT_MISMATCH_FAILURE,
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
MOD_HDCP_STATUS_UNSUPPORTED_PSP_VER_FAILURE,
#endif
};
struct mod_hdcp_displayport {
@ -120,6 +123,13 @@ enum mod_hdcp_display_state {
MOD_HDCP_DISPLAY_ENCRYPTION_ENABLED
};
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
struct mod_hdcp_psp_caps {
uint8_t dtm_v3_supported;
uint8_t opm_state_query_supported;
};
#endif
enum mod_hdcp_display_disable_option {
MOD_HDCP_DISPLAY_NOT_DISABLE = 0,
MOD_HDCP_DISPLAY_DISABLE_AUTHENTICATION,
@ -152,6 +162,9 @@ struct mod_hdcp_ddc {
struct mod_hdcp_psp {
void *handle;
void *funcs;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
struct mod_hdcp_psp_caps caps;
#endif
};
struct mod_hdcp_display_adjustment {
@ -227,6 +240,9 @@ struct mod_hdcp_display {
uint8_t index;
uint8_t controller;
uint8_t dig_fe;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
uint8_t stream_enc_idx;
#endif
union {
uint8_t vc_id;
};
@ -239,6 +255,11 @@ struct mod_hdcp_link {
enum mod_hdcp_operation_mode mode;
uint8_t dig_be;
uint8_t ddc_line;
#if defined(CONFIG_DRM_AMD_DC_DCN3_1)
uint8_t link_enc_idx;
uint8_t phy_idx;
uint8_t hdcp_supported_informational;
#endif
union {
struct mod_hdcp_displayport dp;
struct mod_hdcp_hdmi hdmi;