]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
drm/amd/display: query hdcp capability during link detect
authorBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Wed, 1 Apr 2020 19:07:26 +0000 (15:07 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Thu, 9 Apr 2020 14:43:17 +0000 (10:43 -0400)
[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 <Bhawanpreet.Lakha@amd.com>
Reviewed-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link.c
drivers/gpu/drm/amd/display/dc/dc.h
drivers/gpu/drm/amd/display/dc/dc_link.h
drivers/gpu/drm/amd/display/dc/hdcp/hdcp_msg.c
drivers/gpu/drm/amd/display/include/hdcp_types.h

index 6e99b8c3b5ffbdb19a36156bd04e5f2bc657dd65..75caa36ef85b6c9d534b1e53c12f2e25f5f69c24 100644 (file)
@@ -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 */
index 2c70d40f1ecece77a79ad98ee2dce2fd5b1a952d..8560032a66ba25d0cdfebe9d656d14de33f6ba5b 100644 (file)
@@ -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);
index 00ff5e98278c2f731957a08fcf0c4bb32ca5ed2e..0077f9dcd07c60d11ee72f078fc9def766843ccc 100644 (file)
@@ -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;
index 6f730b5bfe425cb06c220d79acdc4a17769e9de8..5e384a8a83dc21713d1a8bde89b779826713fca4 100644 (file)
@@ -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;
+}
+
index f31e6befc8d68e260eb55acfa4d6e206f97f043e..42229b4effdce756fd5454fcb0c1d12797d75f09 100644 (file)
@@ -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