drm/amd/display: Refactor HDCP to handle multiple displays per link
authorBhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Wed, 28 Aug 2019 19:10:03 +0000 (15:10 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 19 Nov 2019 15:12:53 +0000 (10:12 -0500)
[Why]
We need to do this to support HDCP over MST

Currently we save a display per link, in a MST case we need to save
multiple displays per link.

[How]
We can create an array per link to cache the displays, but it
complicates the design. Instead we can use the module to cache the
displays.

Now we will always add all the displays to the module, but we use the
adjustment flag to disable hdcp on all of them before they are added.

When we want to enable hdcp we just query the display(cache), remove
it then add it back with different adjustments. Its the similar for
disable.

Signed-off-by: Bhawanpreet Lakha <Bhawanpreet.Lakha@amd.com>
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.c
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h

index d368bb8d712b40983564972f4a948e71a7022eb6..eb7eb128744c452d61baa500e5b02279702f27c8 100644 (file)
@@ -5867,20 +5867,6 @@ static bool is_content_protection_different(struct drm_connector_state *state,
        return false;
 }
 
-static void update_content_protection(struct drm_connector_state *state, const struct drm_connector *connector,
-                                     struct hdcp_workqueue *hdcp_w)
-{
-       struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
-       bool disable_type1 = state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 ? true : false;
-
-       if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
-               hdcp_reset_display(hdcp_w, aconnector->dc_link->link_index);
-               hdcp_add_display(hdcp_w, aconnector->dc_link->link_index, aconnector, disable_type1);
-       } else if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-               hdcp_remove_display(hdcp_w, aconnector->dc_link->link_index, aconnector->base.index);
-       }
-
-}
 #endif
 static void remove_stream(struct amdgpu_device *adev,
                          struct amdgpu_crtc *acrtc,
@@ -6850,7 +6836,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                }
 
                if (is_content_protection_different(new_con_state, old_con_state, connector, adev->dm.hdcp_workqueue))
-                       update_content_protection(new_con_state, connector, adev->dm.hdcp_workqueue);
+                       hdcp_update_display(
+                               adev->dm.hdcp_workqueue, aconnector->dc_link->link_index, aconnector,
+                               new_con_state->hdcp_content_type == DRM_MODE_HDCP_CONTENT_TYPE0 ? true : false,
+                               new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED ? true
+                                                                                                        : false);
        }
 #endif
 
index a2ad1390977d88498aea4f74926f0efcd5892c5c..53e382bff54d1b65e4cf0815f571ca82c6eb6802 100644 (file)
@@ -87,43 +87,45 @@ static void process_output(struct hdcp_workqueue *hdcp_work)
 
 }
 
-void hdcp_add_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index, struct amdgpu_dm_connector *aconnector,
-                     bool disable_type1)
+void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+                        unsigned int link_index,
+                        struct amdgpu_dm_connector *aconnector,
+                        bool disable_type1,
+                        bool enable_encryption)
 {
        struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
        struct mod_hdcp_display *display = &hdcp_work[link_index].display;
        struct mod_hdcp_link *link = &hdcp_work[link_index].link;
+       struct mod_hdcp_display_query query;
 
        mutex_lock(&hdcp_w->mutex);
        hdcp_w->aconnector = aconnector;
 
-       hdcp_w->link.adjust.hdcp2.disable_type1 = disable_type1;
-
-       mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
-
-       schedule_delayed_work(&hdcp_w->property_validate_dwork, msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
-
-       process_output(hdcp_w);
-
-       mutex_unlock(&hdcp_w->mutex);
-
-}
-
-void hdcp_remove_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index,  unsigned int display_index)
-{
-       struct hdcp_workqueue *hdcp_w = &hdcp_work[link_index];
-
-       mutex_lock(&hdcp_w->mutex);
+       query.display = NULL;
+       mod_hdcp_query_display(&hdcp_w->hdcp, aconnector->base.index, &query);
+
+       if (query.display != NULL) {
+               memcpy(display, query.display, sizeof(struct mod_hdcp_display));
+               mod_hdcp_remove_display(&hdcp_w->hdcp, aconnector->base.index, &hdcp_w->output);
+
+               if (enable_encryption) {
+                       display->adjust.disable = 0;
+                       hdcp_w->link.adjust.hdcp2.disable_type1 = disable_type1;
+                       schedule_delayed_work(&hdcp_w->property_validate_dwork,
+                                             msecs_to_jiffies(DRM_HDCP_CHECK_PERIOD_MS));
+               } else {
+                       display->adjust.disable = 1;
+                       hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+                       cancel_delayed_work(&hdcp_w->property_validate_dwork);
+               }
 
-       mod_hdcp_remove_display(&hdcp_w->hdcp, display_index, &hdcp_w->output);
+               display->state = MOD_HDCP_DISPLAY_ACTIVE;
+       }
 
-       cancel_delayed_work(&hdcp_w->property_validate_dwork);
-       hdcp_w->encryption_status = MOD_HDCP_ENCRYPTION_STATUS_HDCP_OFF;
+       mod_hdcp_add_display(&hdcp_w->hdcp, link, display, &hdcp_w->output);
 
        process_output(hdcp_w);
-
        mutex_unlock(&hdcp_w->mutex);
-
 }
 
 void hdcp_reset_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index)
@@ -303,7 +305,10 @@ static void update_config(void *handle, struct cp_psp_stream_config *config)
        link->dig_be = config->link_enc_inst;
        link->ddc_line = aconnector->dc_link->ddc_hw_inst + 1;
        link->dp.rev = aconnector->dc_link->dpcd_caps.dpcd_rev.raw;
+       display->adjust.disable = 1;
+       link->adjust.auth_delay = 2;
 
+       hdcp_update_display(hdcp_work, link_index, aconnector, false, false);
 }
 
 struct hdcp_workqueue *hdcp_create_workqueue(void *psp_context, struct cp_psp *cp_psp, struct dc *dc)
index 098f7218f83a66eeb00c706e3e5f43a5f5e4e380..71e121f037cbc3fc5a44bc155f34d50c118c8c3b 100644 (file)
@@ -54,9 +54,12 @@ struct hdcp_workqueue {
        uint8_t max_link;
 };
 
-void hdcp_add_display(struct hdcp_workqueue *hdcp_work, unsigned int link_index, struct amdgpu_dm_connector *aconnector,
-                     bool disable_type1);
-void hdcp_remove_display(struct hdcp_workqueue *work, unsigned int link_index, unsigned int display_index);
+void hdcp_update_display(struct hdcp_workqueue *hdcp_work,
+                        unsigned int link_index,
+                        struct amdgpu_dm_connector *aconnector,
+                        bool disable_type1,
+                        bool enable_encryption);
+
 void hdcp_reset_display(struct hdcp_workqueue *work, unsigned int link_index);
 void hdcp_handle_cpirq(struct hdcp_workqueue *work, unsigned int link_index);
 void hdcp_destroy(struct hdcp_workqueue *work);