[Why]
We need to manage the content protection property changes for
different usecase, once cp is DESIRED we need to maintain the
ENABLED/DESIRED status for different cases.

[How]
1. Attach the content_protection property

2. HDCP enable (UNDESIRED -> DESIRED)
        call into the module with the correct parameters to start
        hdcp. Set cp to ENABLED

3. HDCP disable (ENABLED -> UNDESIRED)
        Call the module to disable hdcp.

3. Handle Special cases (Hotplug, S3, headless S3, DPMS)
        If already ENABLED: set to DESIRED on unplug/suspend/dpms,
        and disable hdcp

        Then on plugin/resume/dpms: enable HDCP

Signed-off-by: Bhawanpreet Lakha <bhawanpreet.la...@amd.com>
Reviewed-by: Harry Wentland <harry.wentl...@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 96 +++++++++++++++++++
 1 file changed, 96 insertions(+)

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 2cc95ab0b645..591b8ab9d4ad 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -68,6 +68,7 @@
 #include <drm/drm_fb_helper.h>
 #include <drm/drm_edid.h>
 #include <drm/drm_audio_component.h>
+#include <drm/drm_hdcp.h>
 
 #if defined(CONFIG_DRM_AMD_DC_DCN1_0)
 #include "ivsrcid/dcn/irqsrcs_dcn_1_0.h"
@@ -1466,6 +1467,11 @@ amdgpu_dm_update_connector_after_detect(struct 
amdgpu_dm_connector *aconnector)
                dc_sink_release(aconnector->dc_sink);
                aconnector->dc_sink = NULL;
                aconnector->edid = NULL;
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+               /* Set CP to DESIRED if it was ENABLED, so we can re-enable it 
again on hotplug */
+               if (connector->state->content_protection == 
DRM_MODE_CONTENT_PROTECTION_ENABLED)
+                       connector->state->content_protection = 
DRM_MODE_CONTENT_PROTECTION_DESIRED;
+#endif
        }
 
        mutex_unlock(&dev->mode_config.mutex);
@@ -1480,6 +1486,9 @@ static void handle_hpd_irq(void *param)
        struct drm_connector *connector = &aconnector->base;
        struct drm_device *dev = connector->dev;
        enum dc_connection_type new_connection_type = dc_connection_none;
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+       struct amdgpu_device *adev = dev->dev_private;
+#endif
 
        /*
         * In case of failure or MST no need to update connector status or 
notify the OS
@@ -1487,6 +1496,9 @@ static void handle_hpd_irq(void *param)
         */
        mutex_lock(&aconnector->hpd_lock);
 
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+       hdcp_reset_display(adev->dm.hdcp_workqueue, 
aconnector->dc_link->link_index);
+#endif
        if (aconnector->fake_enable)
                aconnector->fake_enable = false;
 
@@ -5075,6 +5087,9 @@ void amdgpu_dm_connector_init_helper(struct 
amdgpu_display_manager *dm,
                                        adev->mode_info.freesync_property, 0);
                drm_object_attach_property(&aconnector->base.base,
                                adev->mode_info.freesync_capable_property, 0);
+#ifdef CONFIG_DRM_AMD_DC_HDCP
+               
drm_connector_attach_content_protection_property(&aconnector->base, false);
+#endif
        }
 }
 
@@ -5317,6 +5332,63 @@ is_scaling_state_different(const struct 
dm_connector_state *dm_state,
        return false;
 }
 
+#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)
+{
+       struct amdgpu_dm_connector *aconnector = 
to_amdgpu_dm_connector(connector);
+
+       /* CP is being re enabled, ignore this */
+       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;
+               return false;
+       }
+
+       /* S3 resume case, since old state will always be 0 (UNDESIRED) and the 
restored state will be 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;
+
+       /* Check if something is connected/enabled, otherwise we start hdcp but 
nothing is connected/enabled
+        * hot-plug, headless s3, dpms
+        */
+       if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED && 
connector->dpms == DRM_MODE_DPMS_ON &&
+           aconnector->dc_sink != NULL)
+               return true;
+
+       if (old_state->content_protection == state->content_protection)
+               return false;
+
+       if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_UNDESIRED)
+               return true;
+
+       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);
+
+       if (state->content_protection == DRM_MODE_CONTENT_PROTECTION_DESIRED) {
+               hdcp_add_display(hdcp_w, aconnector->dc_link->link_index);
+
+               /*
+                * TODO: ENABLED should be verified using psp, it is planned 
later.
+                * Just set this to ENABLED for now
+                */
+               state->content_protection = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+
+               return;
+       }
+
+       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,
                          struct dc_stream_state *stream)
@@ -6241,6 +6313,30 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
                                acrtc->otg_inst = status->primary_otg_inst;
                }
        }
+#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);
+
+               new_crtc_state = NULL;
+
+               if (acrtc)
+                       new_crtc_state = drm_atomic_get_new_crtc_state(state, 
&acrtc->base);
+
+               dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+
+               if (dm_new_crtc_state && dm_new_crtc_state->stream == NULL &&
+                   connector->state->content_protection == 
DRM_MODE_CONTENT_PROTECTION_ENABLED) {
+                       hdcp_reset_display(adev->dm.hdcp_workqueue, 
aconnector->dc_link->link_index);
+                       new_con_state->content_protection = 
DRM_MODE_CONTENT_PROTECTION_DESIRED;
+                       continue;
+               }
+
+               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);
+       }
+#endif
 
        /* Handle connector state changes */
        for_each_oldnew_connector_in_state(state, connector, old_con_state, 
new_con_state, i) {
-- 
2.17.1

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to