diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 493a37b089fb..ada5fd3fdeab 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -534,6 +534,8 @@ struct intel_crtc_wm_state {
 		} skl;
 
 		struct {
+			/* non-inverted optimal watermarks */
+			struct vlv_pipe_wm noninverted[NUM_VLV_WM_LEVELS];
 			struct vlv_fifo_state fifo_state;
 			/* inverted optimal watermarks */
 			struct vlv_wm_state optimal;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 9371b9645c9d..ad02edb11ca2 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -1018,73 +1018,70 @@ static uint16_t vlv_compute_wm_level(const struct intel_crtc_state *crtc_state,
 	return min_t(int, wm, USHRT_MAX);
 }
 
-static void vlv_compute_fifo(struct intel_crtc_state *crtc_state)
+static int vlv_compute_fifo(struct intel_crtc_state *crtc_state)
 {
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
-	struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
+	const struct vlv_pipe_wm *noninverted =
+		&crtc_state->wm.vlv.noninverted[VLV_WM_LEVEL_PM2];
 	struct vlv_fifo_state *fifo_state = &crtc_state->wm.vlv.fifo_state;
-	struct drm_device *dev = crtc->base.dev;
-	struct intel_plane *plane;
-	unsigned int total_rate = 0;
-	const int fifo_size = 512 - 1;
+	unsigned int active_planes = crtc_state->active_planes & ~BIT(PLANE_CURSOR);
+	int num_active_planes = hweight32(active_planes);
+	const int fifo_size = 511;
 	int fifo_extra, fifo_left = fifo_size;
+	unsigned int total_rate;
+	enum plane_id plane_id;
 
-	for_each_intel_plane_on_crtc(dev, crtc, plane) {
-		struct intel_plane_state *state =
-			to_intel_plane_state(plane->base.state);
+	total_rate = noninverted->plane[PLANE_PRIMARY] +
+		noninverted->plane[PLANE_SPRITE0] +
+		noninverted->plane[PLANE_SPRITE1];
 
-		if (plane->id == PLANE_CURSOR)
-			continue;
+	if (total_rate > fifo_size)
+		return -EINVAL;
 
-		if (state->base.visible) {
-			wm_state->num_active_planes++;
-			total_rate += state->base.fb->format->cpp[0];
-		}
-	}
+	if (total_rate == 0)
+		total_rate = 1;
 
-	for_each_intel_plane_on_crtc(dev, crtc, plane) {
-		struct intel_plane_state *state =
-			to_intel_plane_state(plane->base.state);
+	for_each_plane_id_on_crtc(crtc, plane_id) {
 		unsigned int rate;
 
-		if (plane->id == PLANE_CURSOR) {
-			fifo_state->plane[plane->id] = 63;
+		if ((active_planes & BIT(plane_id)) == 0) {
+			fifo_state->plane[plane_id] = 0;
 			continue;
 		}
 
-		if (!state->base.visible) {
-			fifo_state->plane[plane->id] = 0;
-			continue;
-		}
-
-		rate = state->base.fb->format->cpp[0];
-		fifo_state->plane[plane->id] = fifo_size * rate / total_rate;
-		fifo_left -= fifo_state->plane[plane->id];
+		rate = noninverted->plane[plane_id];
+		fifo_state->plane[plane_id] = fifo_size * rate / total_rate;
+		fifo_left -= fifo_state->plane[plane_id];
 	}
 
-	fifo_extra = DIV_ROUND_UP(fifo_left, wm_state->num_active_planes ?: 1);
+	fifo_state->plane[PLANE_CURSOR] = 63;
+
+	fifo_extra = DIV_ROUND_UP(fifo_left, num_active_planes ?: 1);
 
 	/* spread the remainder evenly */
-	for_each_intel_plane_on_crtc(dev, crtc, plane) {
+	for_each_plane_id_on_crtc(crtc, plane_id) {
 		int plane_extra;
 
 		if (fifo_left == 0)
 			break;
 
-		if (plane->id == PLANE_CURSOR)
-			continue;
-
-		/* give it all to the first plane if none are active */
-		if (fifo_state->plane[plane->id] == 0 &&
-		    wm_state->num_active_planes)
+		if ((active_planes & BIT(plane_id)) == 0)
 			continue;
 
 		plane_extra = min(fifo_extra, fifo_left);
-		fifo_state->plane[plane->id] += plane_extra;
+		fifo_state->plane[plane_id] += plane_extra;
 		fifo_left -= plane_extra;
 	}
 
-	WARN_ON(fifo_left != 0);
+	WARN_ON(active_planes != 0 && fifo_left != 0);
+
+	/* give it all to the first plane if none are active */
+	if (active_planes == 0) {
+		WARN_ON(fifo_left != fifo_size);
+		fifo_state->plane[PLANE_PRIMARY] = fifo_left;
+	}
+
+	return 0;
 }
 
 static u16 vlv_invert_wm_value(u16 wm, u16 fifo_size)
@@ -1129,35 +1126,33 @@ static void vlv_compute_wm(struct intel_crtc_state *crtc_state)
 	struct intel_crtc *crtc = to_intel_crtc(crtc_state->base.crtc);
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	struct vlv_wm_state *wm_state = &crtc_state->wm.vlv.optimal;
-	const struct vlv_fifo_state *fifo_state =
-		&crtc_state->wm.vlv.fifo_state;
 	struct intel_plane *plane;
 	int level;
 
 	memset(wm_state, 0, sizeof(*wm_state));
+	memset(crtc_state->wm.vlv.noninverted, 0,
+	       sizeof(crtc_state->wm.vlv.noninverted));
 
 	wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed;
 	wm_state->num_levels = dev_priv->wm.max_level + 1;
 
 	wm_state->num_active_planes = 0;
 
-	vlv_compute_fifo(crtc_state);
-
 	if (wm_state->num_active_planes != 1)
 		wm_state->cxsr = false;
 
 	for_each_intel_plane_on_crtc(&dev_priv->drm, crtc, plane) {
 		struct intel_plane_state *state =
 			to_intel_plane_state(plane->base.state);
-		int level;
 
 		if (!state->base.visible)
 			continue;
 
-		/* normal watermarks */
 		for (level = 0; level < wm_state->num_levels; level++) {
+			struct vlv_pipe_wm *noninverted =
+				&crtc_state->wm.vlv.noninverted[level];
 			int wm = vlv_compute_wm_level(crtc_state, state, level);
-			int max_wm = fifo_state->plane[plane->id];
+			int max_wm = plane->id == PLANE_CURSOR ? 63 : 511;
 
 			/* hack */
 			if (WARN_ON(level == 0 && wm > max_wm))
@@ -1166,25 +1161,24 @@ static void vlv_compute_wm(struct intel_crtc_state *crtc_state)
 			if (wm > max_wm)
 				break;
 
-			wm_state->wm[level].plane[plane->id] = wm;
+			noninverted->plane[plane->id] = wm;
 		}
 
 		wm_state->num_levels = level;
+	}
 
-		if (!wm_state->cxsr)
-			continue;
-
-		/* maxfifo watermarks */
-		if (plane->id == PLANE_CURSOR) {
-			for (level = 0; level < wm_state->num_levels; level++)
-				wm_state->sr[level].cursor =
-					wm_state->wm[level].plane[PLANE_CURSOR];
-		} else {
-			for (level = 0; level < wm_state->num_levels; level++)
-				wm_state->sr[level].plane =
-					max(wm_state->sr[level].plane,
-					    wm_state->wm[level].plane[plane->id]);
-		}
+	vlv_compute_fifo(crtc_state);
+
+	for (level = 0; level < wm_state->num_levels; level++) {
+		struct vlv_pipe_wm *noninverted =
+			&crtc_state->wm.vlv.noninverted[level];
+
+		wm_state->wm[level] = *noninverted;
+
+		wm_state->sr[level].plane = max3(noninverted->plane[PLANE_PRIMARY],
+						 noninverted->plane[PLANE_SPRITE0],
+						 noninverted->plane[PLANE_SPRITE1]);
+		wm_state->sr[level].cursor = noninverted->plane[PLANE_CURSOR];
 	}
 
 	/* clear any (partially) filled invalid levels */
