From: hersen wu <[email protected]>

[Why]
connector hdcp properties are lost after display is
unplgged from mst hub. connector is destroyed with
dm_dp_mst_connector_destroy. when display is plugged
back, hdcp is not desired, hdcp could not be enabled
by linux kernel automatically.

[How]
save hdcp properties into hdcp_work within
amdgpu_dm_atomic_commit_tail. if the same display is
plugged back with same display index, its hdcp
properties will be retrieved from hdcp_work within
dm_dp_mst_get_modes

Reviewed-by: Bhawanpreet Lakha <[email protected]>
Acked-by: Jasdeep Dhillon <[email protected]>
Signed-off-by: hersen wu <[email protected]>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 104 +++++++++++++++++-
 .../amd/display/amdgpu_dm/amdgpu_dm_hdcp.h    |  13 +++
 .../display/amdgpu_dm/amdgpu_dm_mst_types.c   |  25 +++++
 3 files changed, 138 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
index bbacd764bf0f..7affe0899418 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8292,15 +8292,65 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
                }
        }
 #ifdef CONFIG_DRM_AMD_DC_HDCP
+       for_each_oldnew_connector_in_state(state, connector, old_con_state, 
new_con_state, i) {
+               struct dm_connector_state *dm_new_con_state = 
to_dm_connector_state(new_con_state);
+               struct amdgpu_crtc *acrtc = 
to_amdgpu_crtc(dm_new_con_state->base.crtc);
+               struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
+
+               pr_debug("[HDCP_DM] -------------- i : %x ----------\n", i);
+
+               if (!connector)
+                       continue;
+
+               pr_debug("[HDCP_DM] connector->index: %x connect_status: %x 
dpms: %x\n",
+                       connector->index, connector->status, connector->dpms);
+               pr_debug("[HDCP_DM] state protection old: %x new: %x\n",
+                       old_con_state->content_protection, 
new_con_state->content_protection);
+
+               if (aconnector->dc_sink) {
+                       if (aconnector->dc_sink->sink_signal != 
SIGNAL_TYPE_VIRTUAL &&
+                               aconnector->dc_sink->sink_signal != 
SIGNAL_TYPE_NONE) {
+                               pr_debug("[HDCP_DM] pipe_ctx dispname=%s\n",
+                               aconnector->dc_sink->edid_caps.display_name);
+                       }
+               }
+
+               new_crtc_state = NULL;
+               old_crtc_state = NULL;
+
+               if (acrtc) {
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state, 
&acrtc->base);
+                       old_crtc_state = drm_atomic_get_old_crtc_state(state, 
&acrtc->base);
+               }
+               if (old_crtc_state)
+                       pr_debug("old crtc en: %x a: %x m: %x a-chg: %x c-chg: 
%x\n",
+                       old_crtc_state->enable,
+                       old_crtc_state->active,
+                       old_crtc_state->mode_changed,
+                       old_crtc_state->active_changed,
+                       old_crtc_state->connectors_changed);
+
+               if (new_crtc_state)
+                       pr_debug("NEW crtc en: %x a: %x m: %x a-chg: %x c-chg: 
%x\n",
+                       new_crtc_state->enable,
+                       new_crtc_state->active,
+                       new_crtc_state->mode_changed,
+                       new_crtc_state->active_changed,
+                       new_crtc_state->connectors_changed);
+       }
+
        for_each_oldnew_connector_in_state(state, connector, old_con_state, 
new_con_state, i) {
                struct dm_connector_state *dm_new_con_state = 
to_dm_connector_state(new_con_state);
                struct amdgpu_crtc *acrtc = 
to_amdgpu_crtc(dm_new_con_state->base.crtc);
                struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
 
                new_crtc_state = NULL;
+               old_crtc_state = NULL;
 
-               if (acrtc)
+               if (acrtc) {
                        new_crtc_state = drm_atomic_get_new_crtc_state(state, 
&acrtc->base);
+                       old_crtc_state = drm_atomic_get_old_crtc_state(state, 
&acrtc->base);
+               }
 
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
 
@@ -8312,11 +8362,57 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
                        continue;
                }
 
-               if (is_content_protection_different(new_con_state, 
old_con_state, connector, adev->dm.hdcp_workqueue))
+               if (is_content_protection_different(
+                       new_crtc_state,
+                       old_crtc_state,
+                       new_con_state,
+                       old_con_state,
+                       connector,
+                       adev->dm.hdcp_workqueue)) {
+                       /* when display is unplugged from mst hub, connctor will
+                        * be destroyed within dm_dp_mst_connector_destroy. 
connector
+                        * hdcp perperties, like type, undesired, desired, 
enabled,
+                        * will be lost. So, save hdcp properties into 
hdcp_work within
+                        * amdgpu_dm_atomic_commit_tail. if the same display is
+                        * plugged back with same display index, its hdcp 
properties
+                        * will be retrieved from hdcp_work within 
dm_dp_mst_get_modes
+                        */
+
+                       bool enable_encryption = false;
+
+                       if (new_con_state->content_protection ==
+                               DRM_MODE_CONTENT_PROTECTION_DESIRED)
+                               enable_encryption = true;
+
+
+                       if (aconnector->dc_link && aconnector->dc_sink &&
+                               aconnector->dc_link->type == 
dc_connection_mst_branch) {
+                               struct hdcp_workqueue *hdcp_work = 
adev->dm.hdcp_workqueue;
+                               struct hdcp_workqueue *hdcp_w =
+                                       
&hdcp_work[aconnector->dc_link->link_index];
+
+                               hdcp_w->hdcp_content_type[connector->index] =
+                                       new_con_state->hdcp_content_type;
+                               hdcp_w->content_protection[connector->index] =
+                                       new_con_state->content_protection;
+                       }
+
+                       if (new_crtc_state && new_crtc_state->mode_changed &&
+                               new_con_state->content_protection >=
+                                       DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+                               enable_encryption = true;
+                       }
+
+                       DRM_INFO("[HDCP_DM] hdcp_update_display 
enable_encryption = %x\n",
+                               enable_encryption);
+
                        hdcp_update_display(
-                               adev->dm.hdcp_workqueue, 
aconnector->dc_link->link_index, aconnector,
+                               adev->dm.hdcp_workqueue, 
+                               aconnector->dc_link->link_index, 
+                               aconnector,
                                new_con_state->hdcp_content_type,
-                               new_con_state->content_protection == 
DRM_MODE_CONTENT_PROTECTION_DESIRED);
+                               enable_encryption);
+               }
        }
 #endif
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
index 6e2537e579fa..69b445b011c8 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_hdcp.h
@@ -52,6 +52,19 @@ struct hdcp_workqueue {
        struct mod_hdcp_link link;
 
        enum mod_hdcp_encryption_status 
encryption_status[AMDGPU_DM_MAX_DISPLAY_INDEX];
+       /* when display is unplugged from mst hub, connctor will be
+        * destroyed within dm_dp_mst_connector_destroy. connector
+        * hdcp perperties, like type, undesired, desired, enabled,
+        * will be lost. So, save hdcp properties into hdcp_work within
+        * amdgpu_dm_atomic_commit_tail. if the same display is
+        * plugged back with same display index, its hdcp properties
+        * will be retrieved from hdcp_work within dm_dp_mst_get_modes
+        */
+       /* un-desired, desired, enabled */
+       unsigned int content_protection[AMDGPU_DM_MAX_DISPLAY_INDEX];
+       /* hdcp1.x, hdcp2.x */
+       unsigned int hdcp_content_type[AMDGPU_DM_MAX_DISPLAY_INDEX];
+
        uint8_t max_link;
 
        uint8_t *srm;
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
index eef71940e43d..3270c61d3afe 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c
@@ -31,6 +31,9 @@
 #include "amdgpu.h"
 #include "amdgpu_dm.h"
 #include "amdgpu_dm_mst_types.h"
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+#include "amdgpu_dm_hdcp.h"
+#endif
 
 #include "dc.h"
 #include "dm_helpers.h"
@@ -344,6 +347,28 @@ static int dm_dp_mst_get_modes(struct drm_connector 
*connector)
                /* dc_link_add_remote_sink returns a new reference */
                aconnector->dc_sink = dc_sink;
 
+               /* when display is unplugged from mst hub, connctor will be
+                * destroyed within dm_dp_mst_connector_destroy. connector
+                * hdcp perperties, like type, undesired, desired, enabled,
+                * will be lost. So, save hdcp properties into hdcp_work within
+                * amdgpu_dm_atomic_commit_tail. if the same display is
+                * plugged back with same display index, its hdcp properties
+                * will be retrieved from hdcp_work within dm_dp_mst_get_modes
+                */
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+               if (aconnector->dc_sink && connector->state) {
+                       struct drm_device *dev = connector->dev;
+                       struct amdgpu_device *adev = drm_to_adev(dev);
+                       struct hdcp_workqueue *hdcp_work = 
adev->dm.hdcp_workqueue;
+                       struct hdcp_workqueue *hdcp_w = 
&hdcp_work[aconnector->dc_link->link_index];
+
+                       connector->state->hdcp_content_type =
+                       hdcp_w->hdcp_content_type[connector->index];
+                       connector->state->content_protection =
+                       hdcp_w->content_protection[connector->index];
+               }
+#endif
+
                if (aconnector->dc_sink) {
                        amdgpu_dm_update_freesync_caps(
                                        connector, aconnector->edid);
-- 
2.34.1

Reply via email to