From fe8db3bcf2e5f9d9056f923b12c7158d6541e435 Mon Sep 17 00:00:00 2001 From: Bhawanpreet Lakha Date: Wed, 1 Apr 2020 15:07:26 -0400 Subject: drm/amd/display: query hdcp capability during link detect [Why] Query the hdcp caps of a link, it is useful and can be reported to the user [How] Create a query function and call it during link detect Signed-off-by: Bhawanpreet Lakha Reviewed-by: Rodrigo Siqueira Signed-off-by: Alex Deucher --- drivers/gpu/drm/amd/display/dc/core/dc_link.c | 56 +++++++++++++++ drivers/gpu/drm/amd/display/dc/dc.h | 41 +++++++++++ drivers/gpu/drm/amd/display/dc/dc_link.h | 3 + drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c | 89 ++++++++++++++++++++++++ drivers/gpu/drm/amd/display/include/hdcp_types.h | 7 ++ 5 files changed, 196 insertions(+) (limited to 'drivers/gpu/drm/amd') diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_link.c b/drivers/gpu/drm/amd/display/dc/core/dc_link.c index 6e99b8c3b5ff..75caa36ef85b 100644 --- a/drivers/gpu/drm/amd/display/dc/core/dc_link.c +++ b/drivers/gpu/drm/amd/display/dc/core/dc_link.c @@ -515,6 +515,50 @@ static void link_disconnect_remap(struct dc_sink *prev_sink, struct dc_link *lin link->local_sink = prev_sink; } +#if defined(CONFIG_DRM_AMD_DC_HDCP) +static void query_hdcp_capability(enum signal_type signal, struct dc_link *link) +{ + struct hdcp_protection_message msg22; + struct hdcp_protection_message msg14; + + memset(&msg22, 0, sizeof(struct hdcp_protection_message)); + memset(&msg14, 0, sizeof(struct hdcp_protection_message)); + memset(link->hdcp_caps.rx_caps.raw, 0, + sizeof(link->hdcp_caps.rx_caps.raw)); + + if ((link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT && + link->ddc->transaction_type == + DDC_TRANSACTION_TYPE_I2C_OVER_AUX) || + link->connector_signal == SIGNAL_TYPE_EDP) { + msg22.data = link->hdcp_caps.rx_caps.raw; + msg22.length = sizeof(link->hdcp_caps.rx_caps.raw); + msg22.msg_id = HDCP_MESSAGE_ID_RX_CAPS; + } else { + msg22.data = &link->hdcp_caps.rx_caps.fields.version; + msg22.length = sizeof(link->hdcp_caps.rx_caps.fields.version); + msg22.msg_id = HDCP_MESSAGE_ID_HDCP2VERSION; + } + msg22.version = HDCP_VERSION_22; + msg22.link = HDCP_LINK_PRIMARY; + msg22.max_retries = 5; + dc_process_hdcp_msg(signal, link, &msg22); + + if (signal == SIGNAL_TYPE_DISPLAY_PORT || signal == SIGNAL_TYPE_DISPLAY_PORT_MST) { + enum hdcp_message_status status = HDCP_MESSAGE_UNSUPPORTED; + + msg14.data = &link->hdcp_caps.bcaps.raw; + msg14.length = sizeof(link->hdcp_caps.bcaps.raw); + msg14.msg_id = HDCP_MESSAGE_ID_READ_BCAPS; + msg14.version = HDCP_VERSION_14; + msg14.link = HDCP_LINK_PRIMARY; + msg14.max_retries = 5; + + status = dc_process_hdcp_msg(signal, link, &msg14); + } + +} +#endif + static void read_current_link_settings_on_detect(struct dc_link *link) { union lane_count_set lane_count_set = { {0} }; @@ -607,6 +651,12 @@ static bool detect_dp(struct dc_link *link, dal_ddc_service_set_transaction_type(link->ddc, sink_caps->transaction_type); +#if defined(CONFIG_DRM_AMD_DC_HDCP) + /* In case of fallback to SST when topology discovery below fails + * HDCP caps will be querried again later by the upper layer (caller + * of this function). */ + query_hdcp_capability(SIGNAL_TYPE_DISPLAY_PORT_MST, link); +#endif /* * This call will initiate MST topology discovery. Which * will detect MST ports and add new DRM connector DRM @@ -976,6 +1026,9 @@ static bool dc_link_detect_helper(struct dc_link *link, * TODO debug why Dell 2413 doesn't like * two link trainings */ +#if defined(CONFIG_DRM_AMD_DC_HDCP) + query_hdcp_capability(sink->sink_signal, link); +#endif // verify link cap for SST non-seamless boot if (!perform_dp_seamless_boot) @@ -989,6 +1042,9 @@ static bool dc_link_detect_helper(struct dc_link *link, sink = prev_sink; prev_sink = NULL; } +#if defined(CONFIG_DRM_AMD_DC_HDCP) + query_hdcp_capability(sink->sink_signal, link); +#endif } /* HDMI-DVI Dongle */ diff --git a/drivers/gpu/drm/amd/display/dc/dc.h b/drivers/gpu/drm/amd/display/dc/dc.h index 2c70d40f1ece..8560032a66ba 100644 --- a/drivers/gpu/drm/amd/display/dc/dc.h +++ b/drivers/gpu/drm/amd/display/dc/dc.h @@ -29,6 +29,9 @@ #include "dc_types.h" #include "grph_object_defs.h" #include "logger_types.h" +#if defined(CONFIG_DRM_AMD_DC_HDCP) +#include "hdcp_types.h" +#endif #include "gpio_types.h" #include "link_service_types.h" #include "grph_object_ctrl_defs.h" @@ -1004,6 +1007,35 @@ union dpcd_sink_ext_caps { uint8_t raw; }; +#if defined(CONFIG_DRM_AMD_DC_HDCP) +union hdcp_rx_caps { + struct { + uint8_t version; + uint8_t reserved; + struct { + uint8_t repeater : 1; + uint8_t hdcp_capable : 1; + uint8_t reserved : 6; + } byte0; + } fields; + uint8_t raw[3]; +}; + +union hdcp_bcaps { + struct { + uint8_t HDCP_CAPABLE:1; + uint8_t REPEATER:1; + uint8_t RESERVED:6; + } bits; + uint8_t raw; +}; + +struct hdcp_caps { + union hdcp_rx_caps rx_caps; + union hdcp_bcaps bcaps; +}; +#endif + #include "dc_link.h" /******************************************************************************* @@ -1107,6 +1139,15 @@ void dc_resume(struct dc *dc); unsigned int dc_get_current_backlight_pwm(struct dc *dc); unsigned int dc_get_target_backlight_pwm(struct dc *dc); +#if defined(CONFIG_DRM_AMD_DC_HDCP) +/* + * HDCP Interfaces + */ +enum hdcp_message_status dc_process_hdcp_msg( + enum signal_type signal, + struct dc_link *link, + struct hdcp_protection_message *message_info); +#endif bool dc_is_dmcu_initialized(struct dc *dc); enum dc_status dc_set_clock(struct dc *dc, enum dc_clock_type clock_type, uint32_t clk_khz, uint32_t stepping); diff --git a/drivers/gpu/drm/amd/display/dc/dc_link.h b/drivers/gpu/drm/amd/display/dc/dc_link.h index 00ff5e98278c..0077f9dcd07c 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_link.h +++ b/drivers/gpu/drm/amd/display/dc/dc_link.h @@ -126,6 +126,9 @@ struct dc_link { uint32_t dongle_max_pix_clk; unsigned short chip_caps; unsigned int dpcd_sink_count; +#if defined(CONFIG_DRM_AMD_DC_HDCP) + struct hdcp_caps hdcp_caps; +#endif enum edp_revision edp_revision; bool psr_feature_enabled; bool psr_allow_active; diff --git a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c index 6f730b5bfe42..5e384a8a83dc 100644 --- a/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c +++ b/drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c @@ -322,3 +322,92 @@ static const struct protection_properties dp_11_protection = { .process_transaction = dp_11_process_transaction }; +static const struct protection_properties *get_protection_properties_by_signal( + struct dc_link *link, + enum signal_type st, + enum hdcp_version version) +{ + switch (version) { + case HDCP_VERSION_14: + switch (st) { + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_HDMI_TYPE_A: + return &hdmi_14_protection; + case SIGNAL_TYPE_DISPLAY_PORT: + if (link && + (link->dpcd_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER || + link->dpcd_caps.dongle_caps.dongle_type == DISPLAY_DONGLE_DP_VGA_CONVERTER)) { + return &non_supported_protection; + } + return &dp_11_protection; + case SIGNAL_TYPE_DISPLAY_PORT_MST: + case SIGNAL_TYPE_EDP: + return &dp_11_protection; + default: + return &non_supported_protection; + } + break; + case HDCP_VERSION_22: + switch (st) { + case SIGNAL_TYPE_DVI_SINGLE_LINK: + case SIGNAL_TYPE_DVI_DUAL_LINK: + case SIGNAL_TYPE_HDMI_TYPE_A: + return &hdmi_14_protection; //todo version2.2 + case SIGNAL_TYPE_DISPLAY_PORT: + case SIGNAL_TYPE_DISPLAY_PORT_MST: + case SIGNAL_TYPE_EDP: + return &dp_11_protection; //todo version2.2 + default: + return &non_supported_protection; + } + break; + default: + return &non_supported_protection; + } +} + +enum hdcp_message_status dc_process_hdcp_msg( + enum signal_type signal, + struct dc_link *link, + struct hdcp_protection_message *message_info) +{ + enum hdcp_message_status status = HDCP_MESSAGE_FAILURE; + uint32_t i = 0; + + const struct protection_properties *protection_props; + + if (!message_info) + return HDCP_MESSAGE_UNSUPPORTED; + + if (message_info->msg_id < HDCP_MESSAGE_ID_READ_BKSV || + message_info->msg_id >= HDCP_MESSAGE_ID_MAX) + return HDCP_MESSAGE_UNSUPPORTED; + + protection_props = + get_protection_properties_by_signal( + link, + signal, + message_info->version); + + if (!protection_props->supported) + return HDCP_MESSAGE_UNSUPPORTED; + + if (protection_props->process_transaction( + link, + message_info)) { + status = HDCP_MESSAGE_SUCCESS; + } else { + for (i = 0; i < message_info->max_retries; i++) { + if (protection_props->process_transaction( + link, + message_info)) { + status = HDCP_MESSAGE_SUCCESS; + break; + } + } + } + + return status; +} + diff --git a/drivers/gpu/drm/amd/display/include/hdcp_types.h b/drivers/gpu/drm/amd/display/include/hdcp_types.h index f31e6befc8d6..42229b4effdc 100644 --- a/drivers/gpu/drm/amd/display/include/hdcp_types.h +++ b/drivers/gpu/drm/amd/display/include/hdcp_types.h @@ -83,6 +83,12 @@ enum hdcp_link { HDCP_LINK_SECONDARY }; +enum hdcp_message_status { + HDCP_MESSAGE_SUCCESS, + HDCP_MESSAGE_FAILURE, + HDCP_MESSAGE_UNSUPPORTED +}; + struct hdcp_protection_message { enum hdcp_version version; /* relevant only for DVI */ @@ -91,6 +97,7 @@ struct hdcp_protection_message { uint32_t length; uint8_t max_retries; uint8_t *data; + enum hdcp_message_status status; }; #endif -- cgit v1.2.3