Retrieve and store checksum_region's CRC data from the DC hardware in vline0 irq
handler. A new function amdgpu_dm_crtc_update_checksum_region_crc() is
implemented and hooked to CRTC callback for updating the latest CRC values
to the checksum CRC blob.

Signed-off-by: Alan Liu <haoping....@amd.com>
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c |  8 ++-
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c | 55 +++++++++++++++----
 .../drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h | 11 ++++
 .../amd/display/amdgpu_dm/amdgpu_dm_crtc.c    | 47 ++++++++++++++++
 4 files changed, 110 insertions(+), 11 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 26da07a25085..9fd08281fe27 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c
@@ -8877,7 +8877,12 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
                                (struct drm_checksum_region 
*)new_crtc_state->checksum_region.region_blob->data;
 
                        if (region_data->checksum_region_enable) {
+                               struct secure_display_context 
*secure_display_ctx =
+                                       
&dm->secure_display_ctxs[acrtc->crtc_id];
+
                                if (!amdgpu_dm_crc_window_is_activated(crtc)) {
+                                       
init_completion(&secure_display_ctx->crc.completion);
+
                                        /* Enable secure display: set crc 
source to "crtc" */
                                        
amdgpu_dm_crtc_set_secure_display_crc_source(crtc, "crtc");
 
@@ -8887,7 +8892,8 @@ static void amdgpu_dm_atomic_commit_tail(struct 
drm_atomic_state *state)
                                        
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
                                        
acrtc->dm_irq_params.window_param.activated = true;
                                        
spin_unlock_irqrestore(&adev_to_drm(adev)->event_lock, flags);
-                               }
+                               } else
+                                       
reinit_completion(&secure_display_ctx->crc.completion);
 
                                /* Update ROI: copy ROI from crtc_state to 
dm_irq_params */
                                
spin_lock_irqsave(&adev_to_drm(adev)->event_lock, flags);
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
index 26017e9fbc4a..f881ccd93a25 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.c
@@ -529,6 +529,8 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc 
*crtc)
        struct amdgpu_crtc *acrtc = NULL;
        struct amdgpu_device *adev = NULL;
        struct secure_display_context *secure_display_ctx = NULL;
+       bool reset_crc_frame_count = false, crc_is_updated = false;
+       uint32_t crc[3] = {0};
        unsigned long flags1;
 
        if (crtc == NULL)
@@ -543,15 +545,14 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc 
*crtc)
 
        /* Early return if CRC capture is not enabled. */
        if (!amdgpu_dm_is_valid_crc_source(cur_crc_src) ||
-               !dm_is_crc_source_crtc(cur_crc_src))
-               goto cleanup;
-
-       if (!acrtc->dm_irq_params.window_param.activated)
-               goto cleanup;
+           !dm_is_crc_source_crtc(cur_crc_src)) {
+               spin_unlock_irqrestore(&drm_dev->event_lock, flags1);
+               return;
+       }
 
-       if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
-               acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
-               goto cleanup;
+       if (!acrtc->dm_irq_params.window_param.activated) {
+               spin_unlock_irqrestore(&drm_dev->event_lock, flags1);
+               return;
        }
 
        secure_display_ctx = &adev->dm.secure_display_ctxs[acrtc->crtc_id];
@@ -562,16 +563,23 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc 
*crtc)
                secure_display_ctx->crtc = crtc;
        }
 
+       if (acrtc->dm_irq_params.window_param.skip_frame_cnt) {
+               acrtc->dm_irq_params.window_param.skip_frame_cnt -= 1;
+               goto cleanup;
+       }
+
        if (acrtc->dm_irq_params.window_param.update_win) {
                /* prepare work for dmub to update ROI */
                secure_display_ctx->rect.x = 
acrtc->dm_irq_params.window_param.x_start;
                secure_display_ctx->rect.y = 
acrtc->dm_irq_params.window_param.y_start;
                secure_display_ctx->rect.width = 
acrtc->dm_irq_params.window_param.x_end -
-                                                               
acrtc->dm_irq_params.window_param.x_start;
+                                       
acrtc->dm_irq_params.window_param.x_start;
                secure_display_ctx->rect.height = 
acrtc->dm_irq_params.window_param.y_end -
-                                                               
acrtc->dm_irq_params.window_param.y_start;
+                                       
acrtc->dm_irq_params.window_param.y_start;
                schedule_work(&secure_display_ctx->forward_roi_work);
 
+               reset_crc_frame_count = true;
+
                acrtc->dm_irq_params.window_param.update_win = false;
 
                /* Statically skip 1 frame, because we may need to wait below 
things
@@ -582,12 +590,39 @@ void amdgpu_dm_crtc_handle_crc_window_irq(struct drm_crtc 
*crtc)
                acrtc->dm_irq_params.window_param.skip_frame_cnt = 1;
 
        } else {
+               struct dc_stream_state *stream_state = 
to_dm_crtc_state(crtc->state)->stream;
+
+               if (!dc_stream_get_crc(stream_state->ctx->dc, stream_state,
+                                       &crc[0], &crc[1], &crc[2]))
+                       DRM_ERROR("Secure Display: fail to get crc\n");
+               else
+                       crc_is_updated = true;
+
                /* prepare work for psp to read ROI/CRC and send to I2C */
                schedule_work(&secure_display_ctx->notify_ta_work);
        }
 
 cleanup:
        spin_unlock_irqrestore(&drm_dev->event_lock, flags1);
+
+       spin_lock_irqsave(&secure_display_ctx->crc.lock, flags1);
+
+       if (reset_crc_frame_count || secure_display_ctx->crc.frame_count == 
UINT_MAX)
+               /* Reset the reference frame count after user update the ROI
+                * or it reaches the maximum value.
+                */
+               secure_display_ctx->crc.frame_count = 0;
+       else
+               secure_display_ctx->crc.frame_count += 1;
+
+       if (crc_is_updated) {
+               secure_display_ctx->crc.crc_R = crc[0];
+               secure_display_ctx->crc.crc_G = crc[1];
+               secure_display_ctx->crc.crc_B = crc[2];
+               complete_all(&secure_display_ctx->crc.completion);
+       }
+
+       spin_unlock_irqrestore(&secure_display_ctx->crc.lock, flags1);
 }
 
 struct secure_display_context *
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
index f4765bcae840..7c7bd5922b7b 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crc.h
@@ -40,6 +40,15 @@ enum amdgpu_dm_pipe_crc_source {
 };
 
 #ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+struct crc_data {
+       uint32_t crc_R;
+       uint32_t crc_G;
+       uint32_t crc_B;
+       uint32_t frame_count;
+       spinlock_t lock;
+       struct completion completion;
+};
+
 struct crc_window_param {
        uint16_t x_start;
        uint16_t y_start;
@@ -64,6 +73,8 @@ struct secure_display_context {
 
        /* Region of Interest (ROI) */
        struct rect rect;
+
+       struct crc_data crc;
 };
 #endif
 
diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c 
b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
index e94fe4a7e492..b673338f048d 100644
--- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
+++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_crtc.c
@@ -280,6 +280,50 @@ static void dm_crtc_reset_state(struct drm_crtc *crtc)
        __drm_atomic_helper_crtc_reset(crtc, &state->base);
 }
 
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+static bool amdgpu_dm_crtc_update_checksum_region_crc(struct drm_crtc *crtc)
+{
+       struct amdgpu_device *adev = drm_to_adev(crtc->dev);
+       struct drm_crtc_state *crtc_state = crtc->state;
+       struct secure_display_context *secure_display_ctx =
+               &adev->dm.secure_display_ctxs[crtc->index];
+       struct drm_checksum_crc *new_data;
+       struct drm_property_blob *new_blob, **old_blob;
+       unsigned long flag;
+
+       if (!amdgpu_dm_crc_window_is_activated(crtc))
+               goto fail;
+
+       wait_for_completion_interruptible_timeout(
+               &secure_display_ctx->crc.completion, 10 * HZ);
+
+       new_blob = drm_property_create_blob(crtc->dev,
+                                       sizeof(struct drm_checksum_crc),
+                                       NULL);
+       if (IS_ERR(new_blob))
+               goto fail;
+
+       /* save new value to blob */
+       new_data = (struct drm_checksum_crc *) new_blob->data;
+       spin_lock_irqsave(&secure_display_ctx->crc.lock, flag);
+       new_data->crc_r = secure_display_ctx->crc.crc_R;
+       new_data->crc_g = secure_display_ctx->crc.crc_G;
+       new_data->crc_b = secure_display_ctx->crc.crc_B;
+       new_data->frame_count = secure_display_ctx->crc.frame_count;
+       spin_unlock_irqrestore(&secure_display_ctx->crc.lock, flag);
+
+       old_blob = &crtc_state->checksum_region.crc_blob;
+       if (!drm_property_replace_blob(old_blob, new_blob))
+               goto fail;
+       
+       return true;
+
+fail:
+       DRM_WARN("Checksum Region: fail to update checksum_region CRC\n");
+       return false;
+}
+#endif
+
 #ifdef CONFIG_DEBUG_FS
 static int amdgpu_dm_crtc_late_register(struct drm_crtc *crtc)
 {
@@ -307,6 +351,9 @@ static const struct drm_crtc_funcs amdgpu_dm_crtc_funcs = {
 #if defined(CONFIG_DEBUG_FS)
        .late_register = amdgpu_dm_crtc_late_register,
 #endif
+#ifdef CONFIG_DRM_AMD_SECURE_DISPLAY
+       .update_checksum_region_crc = amdgpu_dm_crtc_update_checksum_region_crc,
+#endif
 };
 
 static void dm_crtc_helper_disable(struct drm_crtc *crtc)
-- 
2.34.1

Reply via email to