drm/amd/display: phase3 mst hdcp for multiple displays
authorjsg <jsg@openbsd.org>
Thu, 24 Aug 2023 06:14:13 +0000 (06:14 +0000)
committerjsg <jsg@openbsd.org>
Thu, 24 Aug 2023 06:14:13 +0000 (06:14 +0000)
From hersen wu
81e6cf447a2e3affcf54928c01b2476bca28916b in linux-6.1.y/6.1.47
e8fd3eeb5e8711af39b00642da06474e52f4780c in mainline linux

sys/dev/pci/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 4fff701..c3991a1 100644 (file)
@@ -7401,27 +7401,55 @@ is_scaling_state_different(const struct dm_connector_state *dm_state,
 }
 
 #ifdef CONFIG_DRM_AMD_DC_HDCP
-static bool is_content_protection_different(struct drm_connector_state *state,
-                                           const struct drm_connector_state *old_state,
-                                           const struct drm_connector *connector, struct hdcp_workqueue *hdcp_w)
+static bool is_content_protection_different(struct drm_crtc_state *new_crtc_state,
+                                           struct drm_crtc_state *old_crtc_state,
+                                           struct drm_connector_state *new_conn_state,
+                                           struct drm_connector_state *old_conn_state,
+                                           const struct drm_connector *connector,
+                                           struct hdcp_workqueue *hdcp_w)
 {
        struct amdgpu_dm_connector *aconnector = to_amdgpu_dm_connector(connector);
        struct dm_connector_state *dm_con_state = to_dm_connector_state(connector->state);
 
-       /* Handle: Type0/1 change */
-       if (old_state->hdcp_content_type != state->hdcp_content_type &&
-           state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
-               state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+       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_conn_state->content_protection, new_conn_state->content_protection);
+
+       if (old_crtc_state)
+               pr_debug("[HDCP_DM] 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("[HDCP_DM] 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);
+
+       /* hdcp content type change */
+       if (old_conn_state->hdcp_content_type != new_conn_state->hdcp_content_type &&
+           new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_UNDESIRED) {
+               new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+               pr_debug("[HDCP_DM] Type0/1 change %s :true\n", __func__);
                return true;
        }
 
-       /* CP is being re enabled, ignore this
-        *
-        * Handles:     ENABLED -> DESIRED
-        */
-       if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
-           state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
-               state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+       /* CP is being re enabled, ignore this */
+       if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED &&
+           new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+               if (new_crtc_state && new_crtc_state->mode_changed) {
+                       new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+                       pr_debug("[HDCP_DM] ENABLED->DESIRED & mode_changed %s :true\n", __func__);
+                       return true;
+               };
+               new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+               pr_debug("[HDCP_DM] ENABLED -> DESIRED %s :false\n", __func__);
                return false;
        }
 
@@ -7429,9 +7457,9 @@ static bool is_content_protection_different(struct drm_connector_state *state,
         *
         * Handles:     UNDESIRED -> ENABLED
         */
-       if (old_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
-           state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
-               state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+       if (old_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED &&
+           new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_ENABLED)
+               new_conn_state->content_protection = DRM_MODE_CONTENT_PROTECTION_DESIRED;
 
        /* Stream removed and re-enabled
         *
@@ -7441,10 +7469,12 @@ static bool is_content_protection_different(struct drm_connector_state *state,
         *
         * Handles:     DESIRED -> DESIRED (Special case)
         */
-       if (!(old_state->crtc && old_state->crtc->enabled) &&
-               state->crtc && state->crtc->enabled &&
+       if (!(old_conn_state->crtc && old_conn_state->crtc->enabled) &&
+               new_conn_state->crtc && new_conn_state->crtc->enabled &&
                connector->state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
                dm_con_state->update_hdcp = false;
+               pr_debug("[HDCP_DM] DESIRED->DESIRED (Stream removed and re-enabled) %s :true\n",
+                       __func__);
                return true;
        }
 
@@ -7456,35 +7486,42 @@ static bool is_content_protection_different(struct drm_connector_state *state,
         *
         * Handles:     DESIRED -> DESIRED (Special case)
         */
-       if (dm_con_state->update_hdcp && state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
-           connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) {
+       if (dm_con_state->update_hdcp &&
+       new_conn_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED &&
+       connector->dpms == DRM_MODE_DPMS_ON && aconnector->dc_sink != NULL) {
                dm_con_state->update_hdcp = false;
+               pr_debug("[HDCP_DM] DESIRED->DESIRED (Hot-plug, headless s3, dpms) %s :true\n",
+                       __func__);
                return true;
        }
 
-       /*
-        * Handles:     UNDESIRED -> UNDESIRED
-        *              DESIRED -> DESIRED
-        *              ENABLED -> ENABLED
-        */
-       if (old_state->content_protection == state->content_protection)
+       if (old_conn_state->content_protection == new_conn_state->content_protection) {
+               if (new_conn_state->content_protection >= DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+                       if (new_crtc_state && new_crtc_state->mode_changed) {
+                               pr_debug("[HDCP_DM] DESIRED->DESIRED or ENABLE->ENABLE mode_change %s :true\n",
+                                       __func__);
+                               return true;
+                       };
+                       pr_debug("[HDCP_DM] DESIRED->DESIRED & ENABLE->ENABLE %s :false\n",
+                               __func__);
+                       return false;
+               };
+
+               pr_debug("[HDCP_DM] UNDESIRED->UNDESIRED %s :false\n", __func__);
                return false;
+       }
 
-       /*
-        * Handles:     UNDESIRED -> DESIRED
-        *              DESIRED -> UNDESIRED
-        *              ENABLED -> UNDESIRED
-        */
-       if (state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED)
+       if (new_conn_state->content_protection != DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+               pr_debug("[HDCP_DM] UNDESIRED->DESIRED or DESIRED->UNDESIRED or ENABLED->UNDESIRED %s :true\n",
+                       __func__);
                return true;
+       }
 
-       /*
-        * Handles:     DESIRED -> ENABLED
-        */
+       pr_debug("[HDCP_DM] DESIRED->ENABLED %s :false\n", __func__);
        return false;
 }
-
 #endif
+
 static void remove_stream(struct amdgpu_device *adev,
                          struct amdgpu_crtc *acrtc,
                          struct dc_stream_state *stream)
@@ -8334,15 +8371,66 @@ 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);
 
@@ -8354,7 +8442,8 @@ 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,
@@ -8364,6 +8453,11 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                         * 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;
@@ -8376,11 +8470,16 @@ static void amdgpu_dm_atomic_commit_tail(struct drm_atomic_state *state)
                                        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,
-                               new_con_state->hdcp_content_type,
-                               new_con_state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED);
-    }
+                               new_con_state->hdcp_content_type, enable_encryption);
+               }
        }
 #endif