}
 
 unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
-                                  const struct intel_plane_state *plane_state)
+                                  const struct intel_plane_state *plane_state,
+                                  int color_plane)
 {
        const struct drm_framebuffer *fb = plane_state->hw.fb;
-       unsigned int cpp;
-       unsigned int pixel_rate;
 
        if (!plane_state->uapi.visible)
                return 0;
 
-       pixel_rate = intel_plane_pixel_rate(crtc_state, plane_state);
-
-       cpp = fb->format->cpp[0];
-
-       /*
-        * Based on HSD#:1408715493
-        * NV12 cpp == 4, P010 cpp == 8
-        *
-        * FIXME what is the logic behind this?
-        */
-       if (fb->format->is_yuv && fb->format->num_planes > 1)
-               cpp *= 4;
-
-       return pixel_rate * cpp;
+       return intel_plane_pixel_rate(crtc_state, plane_state) *
+               fb->format->cpp[color_plane];
 }
 
 int intel_plane_calc_min_cdclk(struct intel_atomic_state *state,
        crtc_state->nv12_planes &= ~BIT(plane->id);
        crtc_state->c8_planes &= ~BIT(plane->id);
        crtc_state->data_rate[plane->id] = 0;
+       crtc_state->data_rate_y[plane->id] = 0;
        crtc_state->min_cdclk[plane->id] = 0;
 
        plane_state->uapi.visible = false;
        if (new_plane_state->uapi.visible || old_plane_state->uapi.visible)
                new_crtc_state->update_planes |= BIT(plane->id);
 
-       new_crtc_state->data_rate[plane->id] =
-               intel_plane_data_rate(new_crtc_state, new_plane_state);
+       if (new_plane_state->uapi.visible &&
+           intel_format_info_is_yuv_semiplanar(fb->format, fb->modifier)) {
+               new_crtc_state->data_rate_y[plane->id] =
+                       intel_plane_data_rate(new_crtc_state, new_plane_state, 0);
+               new_crtc_state->data_rate[plane->id] =
+                       intel_plane_data_rate(new_crtc_state, new_plane_state, 1);
+       } else if (new_plane_state->uapi.visible) {
+               new_crtc_state->data_rate[plane->id] =
+                       intel_plane_data_rate(new_crtc_state, new_plane_state, 0);
+       }
 
        return intel_plane_atomic_calc_changes(old_crtc_state, new_crtc_state,
                                               old_plane_state, new_plane_state);
 
                                    const struct intel_plane_state *plane_state);
 
 unsigned int intel_plane_data_rate(const struct intel_crtc_state *crtc_state,
-                                  const struct intel_plane_state *plane_state);
+                                  const struct intel_plane_state *plane_state,
+                                  int color_plane);
 void intel_plane_copy_uapi_to_hw_state(struct intel_plane_state *plane_state,
                                       const struct intel_plane_state *from_plane_state,
                                       struct intel_crtc *crtc);
 
 static unsigned int intel_bw_crtc_data_rate(const struct intel_crtc_state *crtc_state)
 {
        struct intel_crtc *crtc = to_intel_crtc(crtc_state->uapi.crtc);
+       struct drm_i915_private *i915 = to_i915(crtc->base.dev);
        unsigned int data_rate = 0;
        enum plane_id plane_id;
 
                        continue;
 
                data_rate += crtc_state->data_rate[plane_id];
+
+               if (DISPLAY_VER(i915) < 11)
+                       data_rate += crtc_state->data_rate_y[plane_id];
        }
 
        return data_rate;
        for_each_plane_id_on_crtc(crtc, plane_id) {
                const struct skl_ddb_entry *ddb =
                        &crtc_state->wm.skl.plane_ddb[plane_id];
-               const struct skl_ddb_entry *ddb_y =
-                       &crtc_state->wm.skl.plane_ddb_y[plane_id];
                unsigned int data_rate = crtc_state->data_rate[plane_id];
-               unsigned int dbuf_mask = 0;
+               unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb);
                enum dbuf_slice slice;
 
-               dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb);
-               dbuf_mask |= skl_ddb_dbuf_slice_mask(i915, ddb_y);
+               for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask)
+                       crtc_bw->used_bw[slice] += data_rate;
+       }
+
+       if (DISPLAY_VER(i915) >= 11)
+               return;
+
+       for_each_plane_id_on_crtc(crtc, plane_id) {
+               const struct skl_ddb_entry *ddb =
+                       &crtc_state->wm.skl.plane_ddb_y[plane_id];
+               unsigned int data_rate = crtc_state->data_rate_y[plane_id];
+               unsigned int dbuf_mask = skl_ddb_dbuf_slice_mask(i915, ddb);
+               enum dbuf_slice slice;
 
-               /*
-                * FIXME: To calculate that more properly we probably
-                * need to split per plane data_rate into data_rate_y
-                * and data_rate_uv for multiplanar formats in order not
-                * to get accounted those twice if they happen to reside
-                * on different slices.
-                * However for pre-icl this would work anyway because
-                * we have only single slice and for icl+ uv plane has
-                * non-zero data rate.
-                * So in worst case those calculation are a bit
-                * pessimistic, which shouldn't pose any significant
-                * problem anyway.
-                */
                for_each_dbuf_slice_in_mask(i915, slice, dbuf_mask)
                        crtc_bw->used_bw[slice] += data_rate;
        }
 
        intel_set_plane_visible(crtc_state, plane_state, false);
        fixup_plane_bitmasks(crtc_state);
        crtc_state->data_rate[plane->id] = 0;
+       crtc_state->data_rate_y[plane->id] = 0;
        crtc_state->min_cdclk[plane->id] = 0;
 
        if ((crtc_state->active_planes & ~BIT(PLANE_CURSOR)) == 0 &&
                        crtc_state->enabled_planes &= ~BIT(plane->id);
                        crtc_state->active_planes &= ~BIT(plane->id);
                        crtc_state->update_planes |= BIT(plane->id);
+                       crtc_state->data_rate[plane->id] = 0;
                }
 
                plane_state->planar_slave = false;
                crtc_state->enabled_planes |= BIT(linked->id);
                crtc_state->active_planes |= BIT(linked->id);
                crtc_state->update_planes |= BIT(linked->id);
+               crtc_state->data_rate[linked->id] =
+                       crtc_state->data_rate_y[plane->id];
                drm_dbg_kms(&dev_priv->drm, "Using %s as Y plane for %s\n",
                            linked->base.name, plane->base.name);
 
 
 
        int min_cdclk[I915_MAX_PLANES];
 
+       /* for packed/planar CbCr */
        u32 data_rate[I915_MAX_PLANES];
+       /* for planar Y */
+       u32 data_rate_y[I915_MAX_PLANES];
 
        /* FIXME unify with data_rate[] */
        u64 plane_data_rate[I915_MAX_PLANES];