diff --git a/drivers/gpu/drm/i915/display/intel_psr.c b/drivers/gpu/drm/i915/display/intel_psr.c
index d87b357806c91..f7b7b374374b1 100644
--- a/drivers/gpu/drm/i915/display/intel_psr.c
+++ b/drivers/gpu/drm/i915/display/intel_psr.c
@@ -1450,6 +1450,22 @@ static inline u32 man_trk_ctl_partial_frame_bit_get(struct drm_i915_private *dev
 	       PSR2_MAN_TRK_CTL_SF_PARTIAL_FRAME_UPDATE;
 }
 
+static inline u32 man_trk_ctl_continuos_full_frame(struct drm_i915_private *dev_priv)
+{
+	return IS_ALDERLAKE_P(dev_priv) ?
+	       ADLP_PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME :
+	       PSR2_MAN_TRK_CTL_SF_CONTINUOS_FULL_FRAME;
+}
+
+static inline u32 man_trk_ctl_su_region_start_end_mask(struct drm_i915_private *dev_priv)
+{
+	if (IS_ALDERLAKE_P(dev_priv))
+		return ADLP_PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR_MASK |
+		       ADLP_PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR_MASK;
+	return PSR2_MAN_TRK_CTL_SU_REGION_START_ADDR_MASK |
+	       PSR2_MAN_TRK_CTL_SU_REGION_END_ADDR_MASK;
+}
+
 static void psr_force_hw_tracking_exit(struct intel_dp *intel_dp)
 {
 	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
@@ -1546,8 +1562,9 @@ void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_st
 	if (!crtc_state->enable_psr2_sel_fetch)
 		return;
 
-	intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder),
-		       crtc_state->psr2_man_track_ctl);
+	intel_de_rmw(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder),
+		     man_trk_ctl_su_region_start_end_mask(dev_priv),
+		     crtc_state->psr2_man_track_ctl);
 }
 
 static void psr2_man_trk_ctl_calc(struct intel_crtc_state *crtc_state,
@@ -2127,6 +2144,26 @@ static void intel_psr_work(struct work_struct *work)
 	mutex_unlock(&intel_dp->psr.lock);
 }
 
+static void _psr_invalidate_handle(struct intel_dp *intel_dp,
+				   unsigned int prev_busy_frontbuffer_bits)
+{
+	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+	if (intel_dp->psr.psr2_sel_fetch_enabled) {
+		u32 val = man_trk_ctl_continuos_full_frame(dev_priv) |
+			  man_trk_ctl_partial_frame_bit_get(dev_priv);
+
+		/* continuos full frame is already enabled */
+		if (prev_busy_frontbuffer_bits)
+			return;
+
+		intel_de_rmw(dev_priv, PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder), 0, val);
+		intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
+	} else {
+		intel_psr_exit(intel_dp);
+	}
+}
+
 /**
  * intel_psr_invalidate - Invalidade PSR
  * @dev_priv: i915 device
@@ -2151,6 +2188,7 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
 	for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
 		unsigned int pipe_frontbuffer_bits = frontbuffer_bits;
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+		unsigned int prev_busy_frontbuffer_bits;
 
 		mutex_lock(&intel_dp->psr.lock);
 		if (!intel_dp->psr.enabled) {
@@ -2158,12 +2196,13 @@ void intel_psr_invalidate(struct drm_i915_private *dev_priv,
 			continue;
 		}
 
+		prev_busy_frontbuffer_bits = intel_dp->psr.busy_frontbuffer_bits;
 		pipe_frontbuffer_bits &=
 			INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe);
 		intel_dp->psr.busy_frontbuffer_bits |= pipe_frontbuffer_bits;
 
 		if (pipe_frontbuffer_bits)
-			intel_psr_exit(intel_dp);
+			_psr_invalidate_handle(intel_dp, prev_busy_frontbuffer_bits);
 
 		mutex_unlock(&intel_dp->psr.lock);
 	}
@@ -2195,6 +2234,49 @@ tgl_dc3co_flush_locked(struct intel_dp *intel_dp, unsigned int frontbuffer_bits,
 			 intel_dp->psr.dc3co_exit_delay);
 }
 
+static void _psr_flush_handle(struct intel_dp *intel_dp,
+			      unsigned int prev_busy_frontbuffer_bits)
+{
+	struct drm_i915_private *dev_priv = dp_to_i915(intel_dp);
+
+	if (intel_dp->psr.psr2_sel_fetch_enabled) {
+		/* is continuos full frame enabled? */
+		if (prev_busy_frontbuffer_bits) {
+			/* it is, can we turn it off? */
+			if (intel_dp->psr.busy_frontbuffer_bits == 0) {
+				u32 clear = man_trk_ctl_continuos_full_frame(dev_priv);
+				u32 set = man_trk_ctl_single_full_frame_bit_get(dev_priv) |
+					  man_trk_ctl_partial_frame_bit_get(dev_priv);
+
+				/*
+				 * turn continuos full frame off and do a single
+				 * full frame
+				 */
+				intel_de_rmw(dev_priv,
+					     PSR2_MAN_TRK_CTL(intel_dp->psr.transcoder),
+					     clear, set);
+				intel_de_write(dev_priv, CURSURFLIVE(intel_dp->psr.pipe), 0);
+			}
+		} else {
+			/*
+			 * continuos full frame is disabled, only a single full
+			 * frame is required
+			 */
+			psr_force_hw_tracking_exit(intel_dp);
+		}
+	} else {
+		/*
+		 * if prev_busy_frontbuffer_bits is set, it means that PSR is
+		 * inactive
+		 */
+		if (prev_busy_frontbuffer_bits == 0)
+			psr_force_hw_tracking_exit(intel_dp);
+
+		if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits)
+			schedule_work(&intel_dp->psr.work);
+	}
+}
+
 /**
  * intel_psr_flush - Flush PSR
  * @dev_priv: i915 device
@@ -2216,6 +2298,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
 	for_each_intel_encoder_with_psr(&dev_priv->drm, encoder) {
 		unsigned int pipe_frontbuffer_bits = frontbuffer_bits;
 		struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+		unsigned int prev_busy_frontbuffer_bits;
 
 		mutex_lock(&intel_dp->psr.lock);
 		if (!intel_dp->psr.enabled) {
@@ -2223,6 +2306,7 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
 			continue;
 		}
 
+		prev_busy_frontbuffer_bits = intel_dp->psr.busy_frontbuffer_bits;
 		pipe_frontbuffer_bits &=
 			INTEL_FRONTBUFFER_ALL_MASK(intel_dp->psr.pipe);
 		intel_dp->psr.busy_frontbuffer_bits &= ~pipe_frontbuffer_bits;
@@ -2232,25 +2316,22 @@ void intel_psr_flush(struct drm_i915_private *dev_priv,
 		 * we have to ensure that the PSR is not activated until
 		 * intel_psr_resume() is called.
 		 */
-		if (intel_dp->psr.paused) {
-			mutex_unlock(&intel_dp->psr.lock);
-			continue;
-		}
+		if (intel_dp->psr.paused)
+			goto exit;
 
 		if (origin == ORIGIN_FLIP ||
 		    (origin == ORIGIN_CURSOR_UPDATE &&
 		     !intel_dp->psr.psr2_sel_fetch_enabled)) {
 			tgl_dc3co_flush_locked(intel_dp, frontbuffer_bits, origin);
-			mutex_unlock(&intel_dp->psr.lock);
-			continue;
+			goto exit;
 		}
 
-		/* By definition flush = invalidate + flush */
-		if (pipe_frontbuffer_bits)
-			psr_force_hw_tracking_exit(intel_dp);
+		if (pipe_frontbuffer_bits == 0)
+			goto exit;
 
-		if (!intel_dp->psr.active && !intel_dp->psr.busy_frontbuffer_bits)
-			schedule_work(&intel_dp->psr.work);
+		/* By definition flush = invalidate + flush */
+		_psr_flush_handle(intel_dp, prev_busy_frontbuffer_bits);
+exit:
 		mutex_unlock(&intel_dp->psr.lock);
 	}
 }
