return mul_fixed16(downscale_w, downscale_h);
 }
 
+static uint_fixed_16_16_t
+skl_pipe_downscale_amount(const struct intel_crtc_state *crtc_state)
+{
+       uint_fixed_16_16_t pipe_downscale = u32_to_fixed_16_16(1);
+
+       if (!crtc_state->base.enable)
+               return pipe_downscale;
+
+       if (crtc_state->pch_pfit.enabled) {
+               uint32_t src_w, src_h, dst_w, dst_h;
+               uint32_t pfit_size = crtc_state->pch_pfit.size;
+               uint_fixed_16_16_t fp_w_ratio, fp_h_ratio;
+               uint_fixed_16_16_t downscale_h, downscale_w;
+
+               src_w = crtc_state->pipe_src_w;
+               src_h = crtc_state->pipe_src_h;
+               dst_w = pfit_size >> 16;
+               dst_h = pfit_size & 0xffff;
+
+               if (!dst_w || !dst_h)
+                       return pipe_downscale;
+
+               fp_w_ratio = fixed_16_16_div(src_w, dst_w);
+               fp_h_ratio = fixed_16_16_div(src_h, dst_h);
+               downscale_w = max_fixed_16_16(fp_w_ratio, u32_to_fixed_16_16(1));
+               downscale_h = max_fixed_16_16(fp_h_ratio, u32_to_fixed_16_16(1));
+
+               pipe_downscale = mul_fixed16(downscale_w, downscale_h);
+       }
+
+       return pipe_downscale;
+}
+
+int skl_check_pipe_max_pixel_rate(struct intel_crtc *intel_crtc,
+                                 struct intel_crtc_state *cstate)
+{
+       struct drm_crtc_state *crtc_state = &cstate->base;
+       struct drm_atomic_state *state = crtc_state->state;
+       struct drm_plane *plane;
+       const struct drm_plane_state *pstate;
+       struct intel_plane_state *intel_pstate;
+       int crtc_clock, cdclk;
+       uint32_t pipe_max_pixel_rate;
+       uint_fixed_16_16_t pipe_downscale;
+       uint_fixed_16_16_t max_downscale = u32_to_fixed_16_16(1);
+
+       if (!cstate->base.enable)
+               return 0;
+
+       drm_atomic_crtc_state_for_each_plane_state(plane, pstate, crtc_state) {
+               uint_fixed_16_16_t plane_downscale;
+               uint_fixed_16_16_t fp_9_div_8 = fixed_16_16_div(9, 8);
+               int bpp;
+
+               if (!intel_wm_plane_visible(cstate,
+                                           to_intel_plane_state(pstate)))
+                       continue;
+
+               if (WARN_ON(!pstate->fb))
+                       return -EINVAL;
+
+               intel_pstate = to_intel_plane_state(pstate);
+               plane_downscale = skl_plane_downscale_amount(cstate,
+                                                            intel_pstate);
+               bpp = pstate->fb->format->cpp[0] * 8;
+               if (bpp == 64)
+                       plane_downscale = mul_fixed16(plane_downscale,
+                                                     fp_9_div_8);
+
+               max_downscale = max_fixed_16_16(plane_downscale, max_downscale);
+       }
+       pipe_downscale = skl_pipe_downscale_amount(cstate);
+
+       pipe_downscale = mul_fixed16(pipe_downscale, max_downscale);
+
+       crtc_clock = crtc_state->adjusted_mode.crtc_clock;
+       cdclk = to_intel_atomic_state(state)->cdclk.logical.cdclk;
+       pipe_max_pixel_rate = div_round_up_u32_fixed16(cdclk, pipe_downscale);
+
+       if (pipe_max_pixel_rate < crtc_clock) {
+               DRM_ERROR("Max supported pixel clock with scaling exceeded\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 static unsigned int
 skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
                             const struct drm_plane_state *pstate,