}
 #endif
 
+#ifdef CONFIG_DEBUG_FS
+static int create_crtc_crc_properties(struct amdgpu_display_manager *dm)
+{
+       dm->crc_win_x_start_property =
+               drm_property_create_range(adev_to_drm(dm->adev),
+                                         DRM_MODE_PROP_ATOMIC,
+                                         "AMD_CRC_WIN_X_START", 0, U16_MAX);
+       if (!dm->crc_win_x_start_property)
+               return -ENOMEM;
+
+       dm->crc_win_y_start_property =
+               drm_property_create_range(adev_to_drm(dm->adev),
+                                         DRM_MODE_PROP_ATOMIC,
+                                         "AMD_CRC_WIN_Y_START", 0, U16_MAX);
+       if (!dm->crc_win_y_start_property)
+               return -ENOMEM;
+
+       dm->crc_win_x_end_property =
+               drm_property_create_range(adev_to_drm(dm->adev),
+                                         DRM_MODE_PROP_ATOMIC,
+                                         "AMD_CRC_WIN_X_END", 0, U16_MAX);
+       if (!dm->crc_win_x_end_property)
+               return -ENOMEM;
+
+       dm->crc_win_y_end_property =
+               drm_property_create_range(adev_to_drm(dm->adev),
+                                         DRM_MODE_PROP_ATOMIC,
+                                         "AMD_CRC_WIN_Y_END", 0, U16_MAX);
+       if (!dm->crc_win_y_end_property)
+               return -ENOMEM;
+
+       return 0;
+}
+#endif
+
 static int amdgpu_dm_init(struct amdgpu_device *adev)
 {
        struct dc_init_data init_data;
 
                dc_init_callbacks(adev->dm.dc, &init_params);
        }
+#endif
+#ifdef CONFIG_DEBUG_FS
+       if (create_crtc_crc_properties(&adev->dm))
+               DRM_ERROR("amdgpu: failed to create crc property.\n");
 #endif
        if (amdgpu_dm_initialize_drm_device(adev)) {
                DRM_ERROR(
        state->crc_src = cur->crc_src;
        state->cm_has_degamma = cur->cm_has_degamma;
        state->cm_is_degamma_srgb = cur->cm_is_degamma_srgb;
-
+#ifdef CONFIG_DEBUG_FS
+       state->crc_window = cur->crc_window;
+#endif
        /* TODO Duplicate dc_stream after objects are stream object is flattened */
 
        return &state->base;
 }
 
+#ifdef CONFIG_DEBUG_FS
+int amdgpu_dm_crtc_atomic_set_property(struct drm_crtc *crtc,
+                                           struct drm_crtc_state *crtc_state,
+                                           struct drm_property *property,
+                                           uint64_t val)
+{
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct dm_crtc_state *dm_new_state =
+               to_dm_crtc_state(crtc_state);
+
+       if (property == adev->dm.crc_win_x_start_property)
+               dm_new_state->crc_window.x_start = val;
+       else if (property == adev->dm.crc_win_y_start_property)
+               dm_new_state->crc_window.y_start = val;
+       else if (property == adev->dm.crc_win_x_end_property)
+               dm_new_state->crc_window.x_end = val;
+       else if (property == adev->dm.crc_win_y_end_property)
+               dm_new_state->crc_window.y_end = val;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+
+int amdgpu_dm_crtc_atomic_get_property(struct drm_crtc *crtc,
+                                           const struct drm_crtc_state *state,
+                                           struct drm_property *property,
+                                           uint64_t *val)
+{
+       struct drm_device *dev = crtc->dev;
+       struct amdgpu_device *adev = drm_to_adev(dev);
+       struct dm_crtc_state *dm_state =
+               to_dm_crtc_state(state);
+
+       if (property == adev->dm.crc_win_x_start_property)
+               *val = dm_state->crc_window.x_start;
+       else if (property == adev->dm.crc_win_y_start_property)
+               *val = dm_state->crc_window.y_start;
+       else if (property == adev->dm.crc_win_x_end_property)
+               *val = dm_state->crc_window.x_end;
+       else if (property == adev->dm.crc_win_y_end_property)
+               *val = dm_state->crc_window.y_end;
+       else
+               return -EINVAL;
+
+       return 0;
+}
+#endif
+
 static inline int dm_set_vupdate_irq(struct drm_crtc *crtc, bool enable)
 {
        enum dc_irq_source irq_source;
        .enable_vblank = dm_enable_vblank,
        .disable_vblank = dm_disable_vblank,
        .get_vblank_timestamp = drm_crtc_vblank_helper_get_vblank_timestamp,
+#ifdef CONFIG_DEBUG_FS
+       .atomic_set_property = amdgpu_dm_crtc_atomic_set_property,
+       .atomic_get_property = amdgpu_dm_crtc_atomic_get_property,
+#endif
 };
 
 static enum drm_connector_status
        return 0;
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void attach_crtc_crc_properties(struct amdgpu_display_manager *dm,
+                               struct amdgpu_crtc *acrtc)
+{
+       drm_object_attach_property(&acrtc->base.base,
+                                  dm->crc_win_x_start_property,
+                                  0);
+       drm_object_attach_property(&acrtc->base.base,
+                                  dm->crc_win_y_start_property,
+                                  0);
+       drm_object_attach_property(&acrtc->base.base,
+                                  dm->crc_win_x_end_property,
+                                  0);
+       drm_object_attach_property(&acrtc->base.base,
+                                  dm->crc_win_y_end_property,
+                                  0);
+}
+#endif
+
 static int amdgpu_dm_crtc_init(struct amdgpu_display_manager *dm,
                               struct drm_plane *plane,
                               uint32_t crtc_index)
        drm_crtc_enable_color_mgmt(&acrtc->base, MAX_COLOR_LUT_ENTRIES,
                                   true, MAX_COLOR_LUT_ENTRIES);
        drm_mode_crtc_set_gamma_size(&acrtc->base, MAX_COLOR_LEGACY_LUT_ENTRIES);
-
+#ifdef CONFIG_DEBUG_FS
+       attach_crtc_crc_properties(dm, acrtc);
+#endif
        return 0;
 
 fail:
         */
        for_each_oldnew_crtc_in_state(state, crtc, old_crtc_state, new_crtc_state, i) {
                struct amdgpu_crtc *acrtc = to_amdgpu_crtc(crtc);
+               bool configure_crc = false;
 
                dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
 
                        dc_stream_retain(dm_new_crtc_state->stream);
                        acrtc->dm_irq_params.stream = dm_new_crtc_state->stream;
                        manage_dm_interrupts(adev, acrtc, true);
-
+               }
 #ifdef CONFIG_DEBUG_FS
+               if (new_crtc_state->active &&
+                       amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
                        /**
                         * Frontend may have changed so reapply the CRC capture
                         * settings for the stream.
                         */
                        dm_new_crtc_state = to_dm_crtc_state(new_crtc_state);
+                       dm_old_crtc_state = to_dm_crtc_state(old_crtc_state);
 
-                       if (amdgpu_dm_is_valid_crc_source(dm_new_crtc_state->crc_src)) {
-                               amdgpu_dm_crtc_configure_crc_source(
-                                       crtc, dm_new_crtc_state,
-                                       dm_new_crtc_state->crc_src);
+                       if (amdgpu_dm_crc_window_is_default(dm_new_crtc_state)) {
+                               if (!old_crtc_state->active || drm_atomic_crtc_needs_modeset(new_crtc_state))
+                                       configure_crc = true;
+                       } else {
+                               if (amdgpu_dm_crc_window_changed(dm_new_crtc_state, dm_old_crtc_state))
+                                       configure_crc = true;
                        }
-#endif
+
+                       if (configure_crc)
+                               amdgpu_dm_crtc_configure_crc_source(
+                                       crtc, dm_new_crtc_state, dm_new_crtc_state->crc_src);
                }
+#endif
        }
 
        for_each_new_crtc_in_state(state, crtc, new_crtc_state, j)
 
        return pipe_crc_sources;
 }
 
+bool amdgpu_dm_crc_window_is_default(struct dm_crtc_state *dm_crtc_state)
+{
+       bool ret = true;
+
+       if ((dm_crtc_state->crc_window.x_start != 0) ||
+               (dm_crtc_state->crc_window.y_start != 0) ||
+               (dm_crtc_state->crc_window.x_end != 0) ||
+               (dm_crtc_state->crc_window.y_end != 0))
+               ret = false;
+
+       return ret;
+}
+
+bool amdgpu_dm_crc_window_changed(struct dm_crtc_state *dm_new_crtc_state,
+                                       struct dm_crtc_state *dm_old_crtc_state)
+{
+       bool ret = false;
+
+       if ((dm_new_crtc_state->crc_window.x_start != dm_old_crtc_state->crc_window.x_start) ||
+               (dm_new_crtc_state->crc_window.y_start != dm_old_crtc_state->crc_window.y_start) ||
+               (dm_new_crtc_state->crc_window.x_end != dm_old_crtc_state->crc_window.x_end) ||
+               (dm_new_crtc_state->crc_window.y_end != dm_old_crtc_state->crc_window.y_end))
+               ret = true;
+
+       return ret;
+}
+
 int
 amdgpu_dm_crtc_verify_crc_source(struct drm_crtc *crtc, const char *src_name,
                                 size_t *values_cnt)
        struct dc_stream_state *stream_state = dm_crtc_state->stream;
        bool enable = amdgpu_dm_is_valid_crc_source(source);
        int ret = 0;
+       struct crc_params *crc_window = NULL, tmp_window;
 
        /* Configuration will be deferred to stream enable. */
        if (!stream_state)
 
        /* Enable CRTC CRC generation if necessary. */
        if (dm_is_crc_source_crtc(source)) {
+               if (!amdgpu_dm_crc_window_is_default(dm_crtc_state)) {
+                       crc_window = &tmp_window;
+
+                       tmp_window.windowa_x_start = dm_crtc_state->crc_window.x_start;
+                       tmp_window.windowa_y_start = dm_crtc_state->crc_window.y_start;
+                       tmp_window.windowa_x_end = dm_crtc_state->crc_window.x_end;
+                       tmp_window.windowa_y_end = dm_crtc_state->crc_window.y_end;
+                       tmp_window.windowb_x_start = dm_crtc_state->crc_window.x_start;
+                       tmp_window.windowb_y_start = dm_crtc_state->crc_window.y_start;
+                       tmp_window.windowb_x_end = dm_crtc_state->crc_window.x_end;
+                       tmp_window.windowb_y_end = dm_crtc_state->crc_window.y_end;
+               }
+
                if (!dc_stream_configure_crc(stream_state->ctx->dc,
-                                            stream_state, NULL, enable, enable)) {
+                                            stream_state, crc_window, enable, enable)) {
                        ret = -EINVAL;
                        goto unlock;
                }