diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index ff2865e94c4c..688cdb3296c2 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -14140,6 +14140,7 @@ static int intel_atomic_commit(struct drm_device *dev,
 	struct intel_atomic_state *intel_state = to_intel_atomic_state(state);
 	struct drm_i915_private *dev_priv = to_i915(dev);
 	int ret = 0;
+	u32 delay;
 
 	intel_state->wakeref = intel_runtime_pm_get(&dev_priv->runtime_pm);
 
@@ -14224,6 +14225,37 @@ static int intel_atomic_commit(struct drm_device *dev,
 			flush_workqueue(dev_priv->modeset_wq);
 		intel_atomic_commit_tail(intel_state);
 	}
+	/* PSR2 is enabled and only edp is connected */
+	if (dev_priv->csr.prefer_dc3co && dev_priv->psr.psr2_enabled &&
+	    dev_priv->psr.enabled) {
+		struct intel_crtc *crtc;
+		struct intel_crtc_state *cstate;
+
+		/*
+		 * As every flip go through intel_atomic_commit, so tracking a
+		 * atomic commit will be a hint for idle frames.
+		 * Delayed work for 6 idle frames will be enough to allow dc6
+		 * over dc3co for deepest power savings.
+		 * At every atomic commit cancel the delayed work first,
+		 * when delayed scheduled that means display has been idle
+		 * for the 6 idle frame.
+		 */
+		cancel_delayed_work(&dev_priv->csr.idle_work);
+		mutex_lock(&dev_priv->csr.dc5_mutex);
+		if (!dev_priv->csr.dc5_wakeref) {
+			dev_priv->csr.dc5_wakeref =
+			intel_display_power_get(dev_priv, POWER_DOMAIN_VIDEO);
+			tgl_psr2_deep_sleep_disable(dev_priv);
+		}
+		mutex_unlock(&dev_priv->csr.dc5_mutex);
+		crtc = intel_get_crtc_for_pipe(dev_priv, PIPE_A);
+		cstate = to_intel_crtc_state(crtc->base.state);
+
+		delay = DC5_REQ_IDLE_FRAMES * intel_get_frame_time_us(cstate);
+		schedule_delayed_work(&dev_priv->csr.idle_work,
+				      usecs_to_jiffies(delay));
+	}
+
 
 	return 0;
 }
@@ -16148,6 +16180,7 @@ int intel_modeset_init(struct drm_device *dev)
 	init_llist_head(&dev_priv->atomic_helper.free_list);
 	INIT_WORK(&dev_priv->atomic_helper.free_work,
 		  intel_atomic_helper_free_state_worker);
+	INIT_DELAYED_WORK(&dev_priv->csr.idle_work, intel_dc5_idle_thread);
 
 	intel_init_quirks(dev_priv);
 
@@ -17089,6 +17122,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
 	flush_workqueue(dev_priv->modeset_wq);
 
 	flush_work(&dev_priv->atomic_helper.free_work);
+	flush_delayed_work(&dev_priv->csr.idle_work);
 	WARN_ON(!llist_empty(&dev_priv->atomic_helper.free_list));
 
 	/*
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index ba1db571c013..de65a5122aff 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -19,6 +19,7 @@
 #include "intel_sideband.h"
 #include "intel_tc.h"
 #include "intel_pm.h"
+#include "intel_psr.h"
 
 bool intel_display_power_well_is_enabled(struct drm_i915_private *dev_priv,
 					 enum i915_power_well_id power_well_id);
@@ -883,6 +884,20 @@ void tgl_prefer_dc3co_over_dc5_check(struct drm_i915_private *dev_priv,
 	}
 }
 
+void intel_dc5_idle_thread(struct work_struct *work)
+{
+	intel_wakeref_t wakeref __maybe_unused;
+	struct drm_i915_private *dev_priv =
+		container_of(work, typeof(*dev_priv), csr.idle_work.work);
+
+	mutex_lock(&dev_priv->csr.dc5_mutex);
+	wakeref	= fetch_and_zero(&dev_priv->csr.dc5_wakeref);
+	if (wakeref)
+		intel_display_power_put(dev_priv, POWER_DOMAIN_VIDEO, wakeref);
+	tgl_psr2_deep_sleep_enable(dev_priv);
+	mutex_unlock(&dev_priv->csr.dc5_mutex);
+}
+
 static void tgl_allow_dc3co(struct drm_i915_private *dev_priv)
 {
 	gen9_set_dc_state(dev_priv, DC_STATE_EN_DC3CO);
@@ -1158,6 +1173,27 @@ static bool tgl_dc3co_power_well_enabled(struct drm_i915_private *dev_priv,
 		(I915_READ(DC_STATE_EN) & DC_STATE_EN_UPTO_DC5_DC6_MASK) == 0);
 }
 
+u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate)
+{
+	u32 pixel_rate, crtc_htotal, crtc_vtotal;
+	uint_fixed_16_16_t frametime_us;
+
+	if (!cstate || !cstate->base.active)
+		return 0;
+
+	pixel_rate = cstate->pixel_rate;
+
+	if (WARN_ON(pixel_rate == 0))
+		return 0;
+
+	crtc_htotal = cstate->base.adjusted_mode.crtc_htotal;
+	crtc_vtotal = cstate->base.adjusted_mode.crtc_vtotal;
+	frametime_us = div_fixed16(crtc_htotal * crtc_vtotal * 1000,
+				   pixel_rate);
+
+	return fixed16_to_u32_round_up(frametime_us);
+}
+
 static void i9xx_power_well_sync_hw_noop(struct drm_i915_private *dev_priv,
 					 struct i915_power_well *power_well)
 {
@@ -4228,6 +4264,7 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
 	BUILD_BUG_ON(POWER_DOMAIN_NUM > 64);
 
 	mutex_init(&power_domains->lock);
+	mutex_init(&dev_priv->csr.dc5_mutex);
 
 	INIT_DELAYED_WORK(&power_domains->async_put_work,
 			  intel_display_power_put_async_work);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 635b93cf67fd..2dd57c3bf383 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -10,6 +10,8 @@
 #include "intel_runtime_pm.h"
 #include "i915_reg.h"
 
+#define DC5_REQ_IDLE_FRAMES	6
+
 struct drm_i915_private;
 struct intel_encoder;
 struct intel_crtc_state;
@@ -236,6 +238,8 @@ struct i915_power_domains {
 
 void skl_enable_dc6(struct drm_i915_private *dev_priv);
 void gen9_sanitize_dc_state(struct drm_i915_private *dev_priv);
+void intel_dc5_idle_thread(struct work_struct *work);
+u32 intel_get_frame_time_us(const struct intel_crtc_state *cstate);
 void bxt_enable_dc9(struct drm_i915_private *dev_priv);
 void bxt_disable_dc9(struct drm_i915_private *dev_priv);
 void gen9_enable_dc5(struct drm_i915_private *dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 72bbc786053e..ae565661a095 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -358,6 +358,7 @@ struct intel_csr {
 	u32 mmiodata[20];
 	u32 dc_state;
 	u32 allowed_dc_mask;
+	struct delayed_work idle_work;
 	intel_wakeref_t wakeref;
 	bool prefer_dc3co;
 	intel_wakeref_t dc5_wakeref;
