diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index eb1bb8b3f9a6..c5bdef6281f3 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2189,58 +2189,109 @@ static void vlv_optimize_watermarks(struct intel_atomic_state *state,
 	mutex_unlock(&dev_priv->wm.wm_mutex);
 }
 
-static void i965_update_wm(struct intel_crtc *unused_crtc)
+static int i965_compute_pipe_wm(struct intel_crtc_state *crtc_state)
 {
-	struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
-	struct intel_crtc *crtc;
+	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
+	struct intel_atomic_state *state =
+		to_intel_atomic_state(crtc_state->base.state);
+	struct i9xx_wm_state *wm_state = &crtc_state->wm.i9xx.optimal;
+	struct intel_plane *plane = to_intel_plane(crtc->base.primary);
+	const struct drm_plane_state *primary_plane_state = NULL;
+	const struct drm_plane_state *cursor_plane_state = NULL;
+
+	memset(wm_state, 0, sizeof(*wm_state));
+
+	if (crtc_state->base.plane_mask & BIT(drm_plane_index(&plane->base)))
+		primary_plane_state = __drm_atomic_get_current_plane_state(&state->base, &plane->base);
+
+	if (crtc_state->base.plane_mask & BIT(drm_plane_index(crtc->base.cursor)))
+		cursor_plane_state = __drm_atomic_get_current_plane_state(&state->base, crtc->base.cursor);
+
+	if (primary_plane_state) {
+		static const int sr_latency_ns = 12000;
+		const struct drm_display_mode *adjusted_mode =
+			&crtc_state->base.adjusted_mode;
+		unsigned active_crtcs;
+		unsigned long entries;
+		bool may_cxsr;
+
+		if (state->modeset)
+			active_crtcs = state->active_crtcs;
+		else
+			active_crtcs = dev_priv->active_crtcs;
+
+		may_cxsr = active_crtcs == drm_crtc_mask(&crtc->base);
+
+		if (may_cxsr && intel_wm_plane_visible(crtc_state, to_intel_plane_state(primary_plane_state))) {
+			struct drm_framebuffer *fb = primary_plane_state->fb;
+			unsigned cpp = fb->format->cpp[0];
+
+			entries = intel_wm_method2(adjusted_mode->crtc_clock,
+						   adjusted_mode->crtc_htotal,
+						   crtc_state->pipe_src_w, cpp,
+						   sr_latency_ns / 100);
+			entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
+			if (entries < I965_FIFO_SIZE)
+				wm_state->sr.plane = I965_FIFO_SIZE - entries;
+			else
+				may_cxsr = false;
+
+			DRM_DEBUG_KMS("self-refresh entries: %ld\n", entries);
+		}
+
+		/* No need to use intel_wm_plane_visible here, since cursor. */
+		if (may_cxsr && cursor_plane_state && crtc_state->base.active) {
+			entries = intel_wm_method2(adjusted_mode->crtc_clock,
+						   adjusted_mode->crtc_htotal,
+						   cursor_plane_state->crtc_w, 4,
+						   sr_latency_ns / 100);
+
+			entries = DIV_ROUND_UP(entries,
+					      i965_cursor_wm_info.cacheline_size) +
+				i965_cursor_wm_info.guard_size;
+
+			if (entries < i965_cursor_wm_info.fifo_size)
+				wm_state->sr.cursor = min(i965_cursor_wm_info.fifo_size - entries,
+							  (unsigned long)(i965_cursor_wm_info.max_wm));
+			else
+				may_cxsr = false;
+		} else if (may_cxsr)
+			wm_state->sr.cursor = 16;
+
+		wm_state->cxsr = may_cxsr;
+
+		DRM_DEBUG_KMS("FIFO watermarks - can cxsr: %s, display plane %d, cursor SR size: %d\n",
+			      yesno(wm_state->cxsr), wm_state->sr.plane, wm_state->sr.cursor);
+	}
+
+	return 0;
+}
+
+static void i965_update_wm(struct intel_crtc *crtc)
+{
+	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	int srwm = 1;
 	int cursor_sr = 16;
-	bool cxsr_enabled;
+	bool cxsr_enabled = false;
+
+	crtc->wm.active.i9xx = crtc->config->wm.i9xx.optimal;
 
 	/* Calc sr entries for one plane configs */
 	crtc = single_enabled_crtc(dev_priv);
-	if (crtc) {
-		/* self-refresh has much higher latency */
-		static const int sr_latency_ns = 12000;
-		const struct drm_display_mode *adjusted_mode =
-			&crtc->config->base.adjusted_mode;
-		const struct drm_framebuffer *fb =
-			crtc->base.primary->state->fb;
-		int clock = adjusted_mode->crtc_clock;
-		int htotal = adjusted_mode->crtc_htotal;
-		int hdisplay = crtc->config->pipe_src_w;
-		int cpp = fb->format->cpp[0];
-		int entries;
-
-		entries = intel_wm_method2(clock, htotal,
-					   hdisplay, cpp, sr_latency_ns / 100);
-		entries = DIV_ROUND_UP(entries, I915_FIFO_LINE_SIZE);
-		srwm = I965_FIFO_SIZE - entries;
-		if (srwm < 0)
-			srwm = 1;
-		srwm &= 0x1ff;
-		DRM_DEBUG_KMS("self-refresh entries: %d, wm: %d\n",
-			      entries, srwm);
-
-		entries = intel_wm_method2(clock, htotal,
-					   crtc->base.cursor->state->crtc_w, 4,
-					   sr_latency_ns / 100);
-		entries = DIV_ROUND_UP(entries,
-				       i965_cursor_wm_info.cacheline_size) +
-			i965_cursor_wm_info.guard_size;
-
-		cursor_sr = i965_cursor_wm_info.fifo_size - entries;
-		if (cursor_sr > i965_cursor_wm_info.max_wm)
-			cursor_sr = i965_cursor_wm_info.max_wm;
+	if (crtc && crtc->wm.active.i9xx.cxsr) {
+		struct i9xx_wm_state *wm_state = &crtc->wm.active.i9xx;
+
+		srwm = wm_state->sr.plane;
+		cursor_sr = wm_state->sr.cursor;
 
 		DRM_DEBUG_KMS("self-refresh watermark: display plane %d "
 			      "cursor %d\n", srwm, cursor_sr);
 
 		cxsr_enabled = true;
-	} else {
-		cxsr_enabled = false;
+	} else if (dev_priv->wm.i9xx.cxsr) {
 		/* Turn off self refresh if both pipes are enabled */
-		intel_set_memory_cxsr(dev_priv, false);
+		_intel_set_memory_cxsr(dev_priv, false);
 	}
 
 	DRM_DEBUG_KMS("Setting FIFO watermarks - A: 8, B: 8, C: 8, SR %d\n",
@@ -2257,7 +2308,9 @@ static void i965_update_wm(struct intel_crtc *unused_crtc)
 	I915_WRITE(DSPFW3, FW_WM(cursor_sr, CURSOR_SR));
 
 	if (cxsr_enabled)
-		intel_set_memory_cxsr(dev_priv, true);
+		_intel_set_memory_cxsr(dev_priv, true);
+
+	dev_priv->wm.i9xx.cxsr = cxsr_enabled;
 }
 
 #undef FW_WM
@@ -8857,6 +8910,7 @@ void intel_init_pm(struct drm_i915_private *dev_priv)
 			dev_priv->display.optimize_watermarks = i9xx_optimize_watermarks;
 		}
 	} else if (IS_GEN4(dev_priv)) {
+		dev_priv->display.compute_pipe_wm = i965_compute_pipe_wm;
 		dev_priv->display.update_wm = i965_update_wm;
 	} else if (IS_GEN3(dev_priv)) {
 		dev_priv->display.compute_pipe_wm = i9xx_compute_pipe_wm;
