drm/i915/gen9: Fix PCODE polling during CDCLK change notification
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / intel_pm.c
index 9bcb15a..90e42e0 100644 (file)
 #define INTEL_RC6p_ENABLE                      (1<<1)
 #define INTEL_RC6pp_ENABLE                     (1<<2)
 
-static void gen9_init_clock_gating(struct drm_device *dev)
+static void gen9_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        /* See Bspec note for PSR2_CTL bit 31, Wa#828:skl,bxt,kbl */
        I915_WRITE(CHICKEN_PAR1_1,
                   I915_READ(CHICKEN_PAR1_1) | SKL_EDP_PSR_FIX_RDWRAP);
@@ -82,11 +80,9 @@ static void gen9_init_clock_gating(struct drm_device *dev)
                   ILK_DPFC_DISABLE_DUMMY0);
 }
 
-static void bxt_init_clock_gating(struct drm_device *dev)
+static void bxt_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       gen9_init_clock_gating(dev);
+       gen9_init_clock_gating(dev_priv);
 
        /* WaDisableSDEUnitClockGating:bxt */
        I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
@@ -108,9 +104,8 @@ static void bxt_init_clock_gating(struct drm_device *dev)
                           PWM1_GATING_DIS | PWM2_GATING_DIS);
 }
 
-static void i915_pineview_get_mem_freq(struct drm_device *dev)
+static void i915_pineview_get_mem_freq(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 tmp;
 
        tmp = I915_READ(CLKCFG);
@@ -147,9 +142,8 @@ static void i915_pineview_get_mem_freq(struct drm_device *dev)
        dev_priv->is_ddr3 = (tmp & CSHRDDR3CTL_DDR3) ? 1 : 0;
 }
 
-static void i915_ironlake_get_mem_freq(struct drm_device *dev)
+static void i915_ironlake_get_mem_freq(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u16 ddrpll, csipll;
 
        ddrpll = I915_READ16(DDRMPLL1);
@@ -320,7 +314,6 @@ static void chv_set_memory_pm5(struct drm_i915_private *dev_priv, bool enable)
 
 void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
 {
-       struct drm_device *dev = &dev_priv->drm;
        u32 val;
 
        if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) {
@@ -330,7 +323,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
        } else if (IS_G4X(dev_priv) || IS_CRESTLINE(dev_priv)) {
                I915_WRITE(FW_BLC_SELF, enable ? FW_BLC_SELF_EN : 0);
                POSTING_READ(FW_BLC_SELF);
-       } else if (IS_PINEVIEW(dev)) {
+       } else if (IS_PINEVIEW(dev_priv)) {
                val = I915_READ(DSPFW3) & ~PINEVIEW_SELF_REFRESH_EN;
                val |= enable ? PINEVIEW_SELF_REFRESH_EN : 0;
                I915_WRITE(DSPFW3, val);
@@ -354,8 +347,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
                return;
        }
 
-       DRM_DEBUG_KMS("memory self-refresh is %s\n",
-                     enable ? "enabled" : "disabled");
+       DRM_DEBUG_KMS("memory self-refresh is %s\n", enableddisabled(enable));
 }
 
 
@@ -378,10 +370,9 @@ static const int pessimal_latency_ns = 5000;
 #define VLV_FIFO_START(dsparb, dsparb2, lo_shift, hi_shift) \
        ((((dsparb) >> (lo_shift)) & 0xff) | ((((dsparb2) >> (hi_shift)) & 0x1) << 8))
 
-static int vlv_get_fifo_size(struct drm_device *dev,
+static int vlv_get_fifo_size(struct drm_i915_private *dev_priv,
                              enum pipe pipe, int plane)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int sprite0_start, sprite1_start, size;
 
        switch (pipe) {
@@ -430,9 +421,8 @@ static int vlv_get_fifo_size(struct drm_device *dev,
        return size;
 }
 
-static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
+static int i9xx_get_fifo_size(struct drm_i915_private *dev_priv, int plane)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dsparb = I915_READ(DSPARB);
        int size;
 
@@ -446,9 +436,8 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
-static int i830_get_fifo_size(struct drm_device *dev, int plane)
+static int i830_get_fifo_size(struct drm_i915_private *dev_priv, int plane)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dsparb = I915_READ(DSPARB);
        int size;
 
@@ -463,9 +452,8 @@ static int i830_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
-static int i845_get_fifo_size(struct drm_device *dev, int plane)
+static int i845_get_fifo_size(struct drm_i915_private *dev_priv, int plane)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dsparb = I915_READ(DSPARB);
        int size;
 
@@ -625,12 +613,12 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
        return wm_size;
 }
 
-static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
+static struct intel_crtc *single_enabled_crtc(struct drm_i915_private *dev_priv)
 {
-       struct drm_crtc *crtc, *enabled = NULL;
+       struct intel_crtc *crtc, *enabled = NULL;
 
-       for_each_crtc(dev, crtc) {
-               if (intel_crtc_active(to_intel_crtc(crtc))) {
+       for_each_intel_crtc(&dev_priv->drm, crtc) {
+               if (intel_crtc_active(crtc)) {
                        if (enabled)
                                return NULL;
                        enabled = crtc;
@@ -642,9 +630,8 @@ static struct drm_crtc *single_enabled_crtc(struct drm_device *dev)
 
 static void pineview_update_wm(struct intel_crtc *unused_crtc)
 {
-       struct drm_device *dev = unused_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_crtc *crtc;
+       struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
+       struct intel_crtc *crtc;
        const struct cxsr_latency *latency;
        u32 reg;
        unsigned long wm;
@@ -659,10 +646,13 @@ static void pineview_update_wm(struct intel_crtc *unused_crtc)
                return;
        }
 
-       crtc = single_enabled_crtc(dev);
+       crtc = single_enabled_crtc(dev_priv);
        if (crtc) {
-               const struct drm_display_mode *adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
-               int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+               const struct drm_display_mode *adjusted_mode =
+                       &crtc->config->base.adjusted_mode;
+               const struct drm_framebuffer *fb =
+                       crtc->base.primary->state->fb;
+               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
                int clock = adjusted_mode->crtc_clock;
 
                /* Display SR */
@@ -709,7 +699,7 @@ static void pineview_update_wm(struct intel_crtc *unused_crtc)
        }
 }
 
-static bool g4x_compute_wm0(struct drm_device *dev,
+static bool g4x_compute_wm0(struct drm_i915_private *dev_priv,
                            int plane,
                            const struct intel_watermark_params *display,
                            int display_latency_ns,
@@ -718,24 +708,26 @@ static bool g4x_compute_wm0(struct drm_device *dev,
                            int *plane_wm,
                            int *cursor_wm)
 {
-       struct drm_crtc *crtc;
+       struct intel_crtc *crtc;
        const struct drm_display_mode *adjusted_mode;
+       const struct drm_framebuffer *fb;
        int htotal, hdisplay, clock, cpp;
        int line_time_us, line_count;
        int entries, tlb_miss;
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       if (!intel_crtc_active(to_intel_crtc(crtc))) {
+       crtc = intel_get_crtc_for_plane(dev_priv, plane);
+       if (!intel_crtc_active(crtc)) {
                *cursor_wm = cursor->guard_size;
                *plane_wm = display->guard_size;
                return false;
        }
 
-       adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
+       adjusted_mode = &crtc->config->base.adjusted_mode;
+       fb = crtc->base.primary->state->fb;
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
-       hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
-       cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+       hdisplay = crtc->config->pipe_src_w;
+       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
        /* Use the small buffer method to calculate plane watermark */
        entries = ((clock * cpp / 1000) * display_latency_ns) / 1000;
@@ -750,7 +742,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
        /* Use the large buffer method to calculate cursor watermark */
        line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (cursor_latency_ns / line_time_us + 1000) / 1000;
-       entries = line_count * crtc->cursor->state->crtc_w * cpp;
+       entries = line_count * crtc->base.cursor->state->crtc_w * cpp;
        tlb_miss = cursor->fifo_size*cursor->cacheline_size - hdisplay * 8;
        if (tlb_miss > 0)
                entries += tlb_miss;
@@ -769,7 +761,7 @@ static bool g4x_compute_wm0(struct drm_device *dev,
  * can be programmed into the associated watermark register, that watermark
  * must be disabled.
  */
-static bool g4x_check_srwm(struct drm_device *dev,
+static bool g4x_check_srwm(struct drm_i915_private *dev_priv,
                           int display_wm, int cursor_wm,
                           const struct intel_watermark_params *display,
                           const struct intel_watermark_params *cursor)
@@ -797,15 +789,16 @@ static bool g4x_check_srwm(struct drm_device *dev,
        return true;
 }
 
-static bool g4x_compute_srwm(struct drm_device *dev,
+static bool g4x_compute_srwm(struct drm_i915_private *dev_priv,
                             int plane,
                             int latency_ns,
                             const struct intel_watermark_params *display,
                             const struct intel_watermark_params *cursor,
                             int *display_wm, int *cursor_wm)
 {
-       struct drm_crtc *crtc;
+       struct intel_crtc *crtc;
        const struct drm_display_mode *adjusted_mode;
+       const struct drm_framebuffer *fb;
        int hdisplay, htotal, cpp, clock;
        unsigned long line_time_us;
        int line_count, line_size;
@@ -817,12 +810,13 @@ static bool g4x_compute_srwm(struct drm_device *dev,
                return false;
        }
 
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
+       crtc = intel_get_crtc_for_plane(dev_priv, plane);
+       adjusted_mode = &crtc->config->base.adjusted_mode;
+       fb = crtc->base.primary->state->fb;
        clock = adjusted_mode->crtc_clock;
        htotal = adjusted_mode->crtc_htotal;
-       hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
-       cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+       hdisplay = crtc->config->pipe_src_w;
+       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
        line_time_us = max(htotal * 1000 / clock, 1);
        line_count = (latency_ns / line_time_us + 1000) / 1000;
@@ -836,11 +830,11 @@ static bool g4x_compute_srwm(struct drm_device *dev,
        *display_wm = entries + display->guard_size;
 
        /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * cpp * crtc->cursor->state->crtc_w;
+       entries = line_count * cpp * crtc->base.cursor->state->crtc_w;
        entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
        *cursor_wm = entries + cursor->guard_size;
 
-       return g4x_check_srwm(dev,
+       return g4x_check_srwm(dev_priv,
                              *display_wm, *cursor_wm,
                              display, cursor);
 }
@@ -940,10 +934,8 @@ static unsigned int vlv_wm_method2(unsigned int pixel_rate,
        return ret;
 }
 
-static void vlv_setup_wm_latency(struct drm_device *dev)
+static void vlv_setup_wm_latency(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /* all latencies in usec */
        dev_priv->wm.pri_latency[VLV_WM_LEVEL_PM2] = 3;
 
@@ -1068,7 +1060,8 @@ static void vlv_invert_wms(struct intel_crtc *crtc)
 
        for (level = 0; level < wm_state->num_levels; level++) {
                struct drm_device *dev = crtc->base.dev;
-               const int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1;
+               const int sr_fifo_size =
+                       INTEL_INFO(to_i915(dev))->num_pipes * 512 - 1;
                struct intel_plane *plane;
 
                wm_state->sr[level].plane = sr_fifo_size - wm_state->sr[level].plane;
@@ -1098,15 +1091,16 @@ static void vlv_invert_wms(struct intel_crtc *crtc)
 static void vlv_compute_wm(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct vlv_wm_state *wm_state = &crtc->wm_state;
        struct intel_plane *plane;
-       int sr_fifo_size = INTEL_INFO(dev)->num_pipes * 512 - 1;
+       int sr_fifo_size = INTEL_INFO(dev_priv)->num_pipes * 512 - 1;
        int level;
 
        memset(wm_state, 0, sizeof(*wm_state));
 
        wm_state->cxsr = crtc->pipe != PIPE_C && crtc->wm.cxsr_allowed;
-       wm_state->num_levels = to_i915(dev)->wm.max_level + 1;
+       wm_state->num_levels = dev_priv->wm.max_level + 1;
 
        wm_state->num_active_planes = 0;
 
@@ -1186,7 +1180,7 @@ static void vlv_compute_wm(struct intel_crtc *crtc)
        }
 
        /* clear any (partially) filled invalid levels */
-       for (level = wm_state->num_levels; level < to_i915(dev)->wm.max_level + 1; level++) {
+       for (level = wm_state->num_levels; level < dev_priv->wm.max_level + 1; level++) {
                memset(&wm_state->wm[level], 0, sizeof(wm_state->wm[level]));
                memset(&wm_state->sr[level], 0, sizeof(wm_state->sr[level]));
        }
@@ -1386,28 +1380,27 @@ static void vlv_update_wm(struct intel_crtc *crtc)
 
 static void g4x_update_wm(struct intel_crtc *crtc)
 {
-       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
        static const int sr_latency_ns = 12000;
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int planea_wm, planeb_wm, cursora_wm, cursorb_wm;
        int plane_sr, cursor_sr;
        unsigned int enabled = 0;
        bool cxsr_enabled;
 
-       if (g4x_compute_wm0(dev, PIPE_A,
+       if (g4x_compute_wm0(dev_priv, PIPE_A,
                            &g4x_wm_info, pessimal_latency_ns,
                            &g4x_cursor_wm_info, pessimal_latency_ns,
                            &planea_wm, &cursora_wm))
                enabled |= 1 << PIPE_A;
 
-       if (g4x_compute_wm0(dev, PIPE_B,
+       if (g4x_compute_wm0(dev_priv, PIPE_B,
                            &g4x_wm_info, pessimal_latency_ns,
                            &g4x_cursor_wm_info, pessimal_latency_ns,
                            &planeb_wm, &cursorb_wm))
                enabled |= 1 << PIPE_B;
 
        if (single_plane_enabled(enabled) &&
-           g4x_compute_srwm(dev, ffs(enabled) - 1,
+           g4x_compute_srwm(dev_priv, ffs(enabled) - 1,
                             sr_latency_ns,
                             &g4x_wm_info,
                             &g4x_cursor_wm_info,
@@ -1444,23 +1437,25 @@ static void g4x_update_wm(struct intel_crtc *crtc)
 
 static void i965_update_wm(struct intel_crtc *unused_crtc)
 {
-       struct drm_device *dev = unused_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_crtc *crtc;
+       struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
+       struct intel_crtc *crtc;
        int srwm = 1;
        int cursor_sr = 16;
        bool cxsr_enabled;
 
        /* Calc sr entries for one plane configs */
-       crtc = single_enabled_crtc(dev);
+       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 = &to_intel_crtc(crtc)->config->base.adjusted_mode;
+               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 = to_intel_crtc(crtc)->config->pipe_src_w;
-               int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+               int hdisplay = crtc->config->pipe_src_w;
+               int cpp = drm_format_plane_cpp(fb->pixel_format, 0);
                unsigned long line_time_us;
                int entries;
 
@@ -1478,7 +1473,7 @@ static void i965_update_wm(struct intel_crtc *unused_crtc)
                              entries, srwm);
 
                entries = (((sr_latency_ns / line_time_us) + 1000) / 1000) *
-                       cpp * crtc->cursor->state->crtc_w;
+                       cpp * crtc->base.cursor->state->crtc_w;
                entries = DIV_ROUND_UP(entries,
                                          i965_cursor_wm_info.cacheline_size);
                cursor_sr = i965_cursor_wm_info.fifo_size -
@@ -1518,32 +1513,36 @@ static void i965_update_wm(struct intel_crtc *unused_crtc)
 
 static void i9xx_update_wm(struct intel_crtc *unused_crtc)
 {
-       struct drm_device *dev = unused_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
        const struct intel_watermark_params *wm_info;
        uint32_t fwater_lo;
        uint32_t fwater_hi;
        int cwm, srwm = 1;
        int fifo_size;
        int planea_wm, planeb_wm;
-       struct drm_crtc *crtc, *enabled = NULL;
+       struct intel_crtc *crtc, *enabled = NULL;
 
-       if (IS_I945GM(dev))
+       if (IS_I945GM(dev_priv))
                wm_info = &i945_wm_info;
        else if (!IS_GEN2(dev_priv))
                wm_info = &i915_wm_info;
        else
                wm_info = &i830_a_wm_info;
 
-       fifo_size = dev_priv->display.get_fifo_size(dev, 0);
-       crtc = intel_get_crtc_for_plane(dev, 0);
-       if (intel_crtc_active(to_intel_crtc(crtc))) {
-               const struct drm_display_mode *adjusted_mode;
-               int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+       fifo_size = dev_priv->display.get_fifo_size(dev_priv, 0);
+       crtc = intel_get_crtc_for_plane(dev_priv, 0);
+       if (intel_crtc_active(crtc)) {
+               const struct drm_display_mode *adjusted_mode =
+                       &crtc->config->base.adjusted_mode;
+               const struct drm_framebuffer *fb =
+                       crtc->base.primary->state->fb;
+               int cpp;
+
                if (IS_GEN2(dev_priv))
                        cpp = 4;
+               else
+                       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
-               adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
                planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                               wm_info, fifo_size, cpp,
                                               pessimal_latency_ns);
@@ -1557,15 +1556,20 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
        if (IS_GEN2(dev_priv))
                wm_info = &i830_bc_wm_info;
 
-       fifo_size = dev_priv->display.get_fifo_size(dev, 1);
-       crtc = intel_get_crtc_for_plane(dev, 1);
-       if (intel_crtc_active(to_intel_crtc(crtc))) {
-               const struct drm_display_mode *adjusted_mode;
-               int cpp = drm_format_plane_cpp(crtc->primary->state->fb->pixel_format, 0);
+       fifo_size = dev_priv->display.get_fifo_size(dev_priv, 1);
+       crtc = intel_get_crtc_for_plane(dev_priv, 1);
+       if (intel_crtc_active(crtc)) {
+               const struct drm_display_mode *adjusted_mode =
+                       &crtc->config->base.adjusted_mode;
+               const struct drm_framebuffer *fb =
+                       crtc->base.primary->state->fb;
+               int cpp;
+
                if (IS_GEN2(dev_priv))
                        cpp = 4;
+               else
+                       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
-               adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
                planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                               wm_info, fifo_size, cpp,
                                               pessimal_latency_ns);
@@ -1584,7 +1588,7 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
        if (IS_I915GM(dev_priv) && enabled) {
                struct drm_i915_gem_object *obj;
 
-               obj = intel_fb_obj(enabled->primary->state->fb);
+               obj = intel_fb_obj(enabled->base.primary->state->fb);
 
                /* self-refresh seems busted with untiled */
                if (!i915_gem_object_is_tiled(obj))
@@ -1600,19 +1604,24 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
        intel_set_memory_cxsr(dev_priv, false);
 
        /* Calc sr entries for one plane configs */
-       if (HAS_FW_BLC(dev) && enabled) {
+       if (HAS_FW_BLC(dev_priv) && enabled) {
                /* self-refresh has much higher latency */
                static const int sr_latency_ns = 6000;
-               const struct drm_display_mode *adjusted_mode = &to_intel_crtc(enabled)->config->base.adjusted_mode;
+               const struct drm_display_mode *adjusted_mode =
+                       &enabled->config->base.adjusted_mode;
+               const struct drm_framebuffer *fb =
+                       enabled->base.primary->state->fb;
                int clock = adjusted_mode->crtc_clock;
                int htotal = adjusted_mode->crtc_htotal;
-               int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w;
-               int cpp = drm_format_plane_cpp(enabled->primary->state->fb->pixel_format, 0);
+               int hdisplay = enabled->config->pipe_src_w;
+               int cpp;
                unsigned long line_time_us;
                int entries;
 
                if (IS_I915GM(dev_priv) || IS_I945GM(dev_priv))
                        cpp = 4;
+               else
+                       cpp = drm_format_plane_cpp(fb->pixel_format, 0);
 
                line_time_us = max(htotal * 1000 / clock, 1);
 
@@ -1651,21 +1660,20 @@ static void i9xx_update_wm(struct intel_crtc *unused_crtc)
 
 static void i845_update_wm(struct intel_crtc *unused_crtc)
 {
-       struct drm_device *dev = unused_crtc->base.dev;
-       struct drm_i915_private *dev_priv = to_i915(dev);
-       struct drm_crtc *crtc;
+       struct drm_i915_private *dev_priv = to_i915(unused_crtc->base.dev);
+       struct intel_crtc *crtc;
        const struct drm_display_mode *adjusted_mode;
        uint32_t fwater_lo;
        int planea_wm;
 
-       crtc = single_enabled_crtc(dev);
+       crtc = single_enabled_crtc(dev_priv);
        if (crtc == NULL)
                return;
 
-       adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
+       adjusted_mode = &crtc->config->base.adjusted_mode;
        planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
                                       &i845_wm_info,
-                                      dev_priv->display.get_fifo_size(dev, 0),
+                                      dev_priv->display.get_fifo_size(dev_priv, 0),
                                       4, pessimal_latency_ns);
        fwater_lo = I915_READ(FW_BLC) & ~0xfff;
        fwater_lo |= (3<<8) | planea_wm;
@@ -1854,23 +1862,25 @@ static uint32_t ilk_compute_fbc_wm(const struct intel_crtc_state *cstate,
        return ilk_wm_fbc(pri_val, drm_rect_width(&pstate->base.dst), cpp);
 }
 
-static unsigned int ilk_display_fifo_size(const struct drm_device *dev)
+static unsigned int
+ilk_display_fifo_size(const struct drm_i915_private *dev_priv)
 {
-       if (INTEL_INFO(dev)->gen >= 8)
+       if (INTEL_GEN(dev_priv) >= 8)
                return 3072;
-       else if (INTEL_INFO(dev)->gen >= 7)
+       else if (INTEL_GEN(dev_priv) >= 7)
                return 768;
        else
                return 512;
 }
 
-static unsigned int ilk_plane_wm_reg_max(const struct drm_device *dev,
-                                        int level, bool is_sprite)
+static unsigned int
+ilk_plane_wm_reg_max(const struct drm_i915_private *dev_priv,
+                    int level, bool is_sprite)
 {
-       if (INTEL_INFO(dev)->gen >= 8)
+       if (INTEL_GEN(dev_priv) >= 8)
                /* BDW primary/sprite plane watermarks */
                return level == 0 ? 255 : 2047;
-       else if (INTEL_INFO(dev)->gen >= 7)
+       else if (INTEL_GEN(dev_priv) >= 7)
                /* IVB/HSW primary/sprite plane watermarks */
                return level == 0 ? 127 : 1023;
        else if (!is_sprite)
@@ -1881,18 +1891,18 @@ static unsigned int ilk_plane_wm_reg_max(const struct drm_device *dev,
                return level == 0 ? 63 : 255;
 }
 
-static unsigned int ilk_cursor_wm_reg_max(const struct drm_device *dev,
-                                         int level)
+static unsigned int
+ilk_cursor_wm_reg_max(const struct drm_i915_private *dev_priv, int level)
 {
-       if (INTEL_INFO(dev)->gen >= 7)
+       if (INTEL_GEN(dev_priv) >= 7)
                return level == 0 ? 63 : 255;
        else
                return level == 0 ? 31 : 63;
 }
 
-static unsigned int ilk_fbc_wm_reg_max(const struct drm_device *dev)
+static unsigned int ilk_fbc_wm_reg_max(const struct drm_i915_private *dev_priv)
 {
-       if (INTEL_INFO(dev)->gen >= 8)
+       if (INTEL_GEN(dev_priv) >= 8)
                return 31;
        else
                return 15;
@@ -1905,7 +1915,8 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
                                     enum intel_ddb_partitioning ddb_partitioning,
                                     bool is_sprite)
 {
-       unsigned int fifo_size = ilk_display_fifo_size(dev);
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       unsigned int fifo_size = ilk_display_fifo_size(dev_priv);
 
        /* if sprites aren't enabled, sprites get nothing */
        if (is_sprite && !config->sprites_enabled)
@@ -1913,14 +1924,14 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
 
        /* HSW allows LP1+ watermarks even with multiple pipes */
        if (level == 0 || config->num_pipes_active > 1) {
-               fifo_size /= INTEL_INFO(dev)->num_pipes;
+               fifo_size /= INTEL_INFO(dev_priv)->num_pipes;
 
                /*
                 * For some reason the non self refresh
                 * FIFO size is only half of the self
                 * refresh FIFO size on ILK/SNB.
                 */
-               if (INTEL_INFO(dev)->gen <= 6)
+               if (INTEL_GEN(dev_priv) <= 6)
                        fifo_size /= 2;
        }
 
@@ -1936,7 +1947,7 @@ static unsigned int ilk_plane_wm_max(const struct drm_device *dev,
        }
 
        /* clamp to max that the registers can hold */
-       return min(fifo_size, ilk_plane_wm_reg_max(dev, level, is_sprite));
+       return min(fifo_size, ilk_plane_wm_reg_max(dev_priv, level, is_sprite));
 }
 
 /* Calculate the maximum cursor plane watermark */
@@ -1949,7 +1960,7 @@ static unsigned int ilk_cursor_wm_max(const struct drm_device *dev,
                return 64;
 
        /* otherwise just report max that registers can hold */
-       return ilk_cursor_wm_reg_max(dev, level);
+       return ilk_cursor_wm_reg_max(to_i915(dev), level);
 }
 
 static void ilk_compute_wm_maximums(const struct drm_device *dev,
@@ -1961,17 +1972,17 @@ static void ilk_compute_wm_maximums(const struct drm_device *dev,
        max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false);
        max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true);
        max->cur = ilk_cursor_wm_max(dev, level, config);
-       max->fbc = ilk_fbc_wm_reg_max(dev);
+       max->fbc = ilk_fbc_wm_reg_max(to_i915(dev));
 }
 
-static void ilk_compute_wm_reg_maximums(struct drm_device *dev,
+static void ilk_compute_wm_reg_maximums(const struct drm_i915_private *dev_priv,
                                        int level,
                                        struct ilk_wm_maximums *max)
 {
-       max->pri = ilk_plane_wm_reg_max(dev, level, false);
-       max->spr = ilk_plane_wm_reg_max(dev, level, true);
-       max->cur = ilk_cursor_wm_reg_max(dev, level);
-       max->fbc = ilk_fbc_wm_reg_max(dev);
+       max->pri = ilk_plane_wm_reg_max(dev_priv, level, false);
+       max->spr = ilk_plane_wm_reg_max(dev_priv, level, true);
+       max->cur = ilk_cursor_wm_reg_max(dev_priv, level);
+       max->fbc = ilk_fbc_wm_reg_max(dev_priv);
 }
 
 static bool ilk_validate_wm_level(int level,
@@ -2078,10 +2089,9 @@ hsw_compute_linetime_wm(const struct intel_crtc_state *cstate)
               PIPE_WM_LINETIME_TIME(linetime);
 }
 
-static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
+static void intel_read_wm_latency(struct drm_i915_private *dev_priv,
+                                 uint16_t wm[8])
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        if (IS_GEN9(dev_priv)) {
                uint32_t val;
                int ret, i;
@@ -2167,14 +2177,14 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
                wm[2] = (sskpd >> 12) & 0xFF;
                wm[3] = (sskpd >> 20) & 0x1FF;
                wm[4] = (sskpd >> 32) & 0x1FF;
-       } else if (INTEL_INFO(dev)->gen >= 6) {
+       } else if (INTEL_GEN(dev_priv) >= 6) {
                uint32_t sskpd = I915_READ(MCH_SSKPD);
 
                wm[0] = (sskpd >> SSKPD_WM0_SHIFT) & SSKPD_WM_MASK;
                wm[1] = (sskpd >> SSKPD_WM1_SHIFT) & SSKPD_WM_MASK;
                wm[2] = (sskpd >> SSKPD_WM2_SHIFT) & SSKPD_WM_MASK;
                wm[3] = (sskpd >> SSKPD_WM3_SHIFT) & SSKPD_WM_MASK;
-       } else if (INTEL_INFO(dev)->gen >= 5) {
+       } else if (INTEL_GEN(dev_priv) >= 5) {
                uint32_t mltr = I915_READ(MLTR_ILK);
 
                /* ILK primary LP0 latency is 700 ns */
@@ -2262,9 +2272,8 @@ static bool ilk_increase_wm_latency(struct drm_i915_private *dev_priv,
        return true;
 }
 
-static void snb_wm_latency_quirk(struct drm_device *dev)
+static void snb_wm_latency_quirk(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        bool changed;
 
        /*
@@ -2284,11 +2293,9 @@ static void snb_wm_latency_quirk(struct drm_device *dev)
        intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
 }
 
-static void ilk_setup_wm_latency(struct drm_device *dev)
+static void ilk_setup_wm_latency(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       intel_read_wm_latency(dev, dev_priv->wm.pri_latency);
+       intel_read_wm_latency(dev_priv, dev_priv->wm.pri_latency);
 
        memcpy(dev_priv->wm.spr_latency, dev_priv->wm.pri_latency,
               sizeof(dev_priv->wm.pri_latency));
@@ -2303,14 +2310,12 @@ static void ilk_setup_wm_latency(struct drm_device *dev)
        intel_print_wm_latency(dev_priv, "Cursor", dev_priv->wm.cur_latency);
 
        if (IS_GEN6(dev_priv))
-               snb_wm_latency_quirk(dev);
+               snb_wm_latency_quirk(dev_priv);
 }
 
-static void skl_setup_wm_latency(struct drm_device *dev)
+static void skl_setup_wm_latency(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       intel_read_wm_latency(dev, dev_priv->wm.skl_latency);
+       intel_read_wm_latency(dev_priv, dev_priv->wm.skl_latency);
        intel_print_wm_latency(dev_priv, "Gen9 Plane", dev_priv->wm.skl_latency);
 }
 
@@ -2381,7 +2386,7 @@ static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate)
        usable_level = max_level;
 
        /* ILK/SNB: LP2+ watermarks only w/o sprites */
-       if (INTEL_INFO(dev)->gen <= 6 && pipe_wm->sprites_enabled)
+       if (INTEL_GEN(dev_priv) <= 6 && pipe_wm->sprites_enabled)
                usable_level = 1;
 
        /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
@@ -2400,7 +2405,7 @@ static int ilk_compute_pipe_wm(struct intel_crtc_state *cstate)
        if (!ilk_validate_pipe_wm(dev, pipe_wm))
                return -EINVAL;
 
-       ilk_compute_wm_reg_maximums(dev, 1, &max);
+       ilk_compute_wm_reg_maximums(dev_priv, 1, &max);
 
        for (level = 1; level <= max_level; level++) {
                struct intel_wm_level *wm = &pipe_wm->raw_wm[level];
@@ -2529,7 +2534,7 @@ static void ilk_wm_merge(struct drm_device *dev,
                last_enabled_level = 0;
 
        /* ILK: FBC WM must be disabled always */
-       merged->fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6;
+       merged->fbc_wm_enabled = INTEL_GEN(dev_priv) >= 6;
 
        /* merge each WM1+ level */
        for (level = 1; level <= max_level; level++) {
@@ -2592,6 +2597,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
                                   enum intel_ddb_partitioning partitioning,
                                   struct ilk_wm_values *results)
 {
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_crtc *intel_crtc;
        int level, wm_lp;
 
@@ -2618,7 +2624,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
                if (r->enable)
                        results->wm_lp[wm_lp - 1] |= WM1_LP_SR_EN;
 
-               if (INTEL_INFO(dev)->gen >= 8)
+               if (INTEL_GEN(dev_priv) >= 8)
                        results->wm_lp[wm_lp - 1] |=
                                r->fbc_val << WM1_LP_FBC_SHIFT_BDW;
                else
@@ -2629,7 +2635,7 @@ static void ilk_compute_wm_results(struct drm_device *dev,
                 * Always set WM1S_LP_EN when spr_val != 0, even if the
                 * level is disabled. Doing otherwise could cause underruns.
                 */
-               if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) {
+               if (INTEL_GEN(dev_priv) <= 6 && r->spr_val) {
                        WARN_ON(wm_lp != 1);
                        results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val;
                } else
@@ -2779,7 +2785,6 @@ static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
 static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
                                struct ilk_wm_values *results)
 {
-       struct drm_device *dev = &dev_priv->drm;
        struct ilk_wm_values *previous = &dev_priv->wm.hw;
        unsigned int dirty;
        uint32_t val;
@@ -2835,7 +2840,7 @@ static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
            previous->wm_lp_spr[0] != results->wm_lp_spr[0])
                I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
 
-       if (INTEL_INFO(dev)->gen >= 7) {
+       if (INTEL_GEN(dev_priv) >= 7) {
                if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
                        I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
                if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
@@ -3041,7 +3046,7 @@ bool intel_can_enable_sagv(struct drm_atomic_state *state)
 
        /* Since we're now guaranteed to only have one active CRTC... */
        pipe = ffs(intel_state->active_crtcs) - 1;
-       crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
+       crtc = intel_get_crtc_for_pipe(dev_priv, pipe);
        cstate = to_intel_crtc_state(crtc->base.state);
 
        if (crtc->base.state->adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
@@ -3117,7 +3122,11 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
         * we currently hold.
         */
        if (!intel_state->active_pipe_changes) {
-               *alloc = to_intel_crtc(for_crtc)->hw_ddb;
+               /*
+                * alloc may be cleared by clear_intel_crtc_state,
+                * copy from old state to be sure
+                */
+               *alloc = to_intel_crtc_state(for_crtc->state)->wm.skl.ddb;
                return;
        }
 
@@ -3623,6 +3632,9 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
                y_min_scanlines = 4;
        }
 
+       if (apply_memory_bw_wa)
+               y_min_scanlines *= 2;
+
        plane_bytes_per_line = width * cpp;
        if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
            fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
@@ -3643,8 +3655,6 @@ static int skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
                                 plane_blocks_per_line);
 
        y_tile_minimum = plane_blocks_per_line * y_min_scanlines;
-       if (apply_memory_bw_wa)
-               y_tile_minimum *= 2;
 
        if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
            fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
@@ -3841,10 +3851,10 @@ static void skl_write_wm_level(struct drm_i915_private *dev_priv,
        I915_WRITE(reg, val);
 }
 
-void skl_write_plane_wm(struct intel_crtc *intel_crtc,
-                       const struct skl_plane_wm *wm,
-                       const struct skl_ddb_allocation *ddb,
-                       int plane)
+static void skl_write_plane_wm(struct intel_crtc *intel_crtc,
+                              const struct skl_plane_wm *wm,
+                              const struct skl_ddb_allocation *ddb,
+                              int plane)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
@@ -3865,9 +3875,9 @@ void skl_write_plane_wm(struct intel_crtc *intel_crtc,
                            &ddb->y_plane[pipe][plane]);
 }
 
-void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
-                        const struct skl_plane_wm *wm,
-                        const struct skl_ddb_allocation *ddb)
+static void skl_write_cursor_wm(struct intel_crtc *intel_crtc,
+                               const struct skl_plane_wm *wm,
+                               const struct skl_ddb_allocation *ddb)
 {
        struct drm_crtc *crtc = &intel_crtc->base;
        struct drm_device *dev = crtc->dev;
@@ -3905,25 +3915,16 @@ static inline bool skl_ddb_entries_overlap(const struct skl_ddb_entry *a,
        return a->start < b->end && b->start < a->end;
 }
 
-bool skl_ddb_allocation_overlaps(struct drm_atomic_state *state,
-                                struct intel_crtc *intel_crtc)
+bool skl_ddb_allocation_overlaps(const struct skl_ddb_entry **entries,
+                                const struct skl_ddb_entry *ddb,
+                                int ignore)
 {
-       struct drm_crtc *other_crtc;
-       struct drm_crtc_state *other_cstate;
-       struct intel_crtc *other_intel_crtc;
-       const struct skl_ddb_entry *ddb =
-               &to_intel_crtc_state(intel_crtc->base.state)->wm.skl.ddb;
        int i;
 
-       for_each_crtc_in_state(state, other_crtc, other_cstate, i) {
-               other_intel_crtc = to_intel_crtc(other_crtc);
-
-               if (other_intel_crtc == intel_crtc)
-                       continue;
-
-               if (skl_ddb_entries_overlap(ddb, &other_intel_crtc->hw_ddb))
+       for (i = 0; i < I915_MAX_PIPES; i++)
+               if (i != ignore && entries[i] &&
+                   skl_ddb_entries_overlap(ddb, entries[i]))
                        return true;
-       }
 
        return false;
 }
@@ -4192,14 +4193,35 @@ skl_compute_wm(struct drm_atomic_state *state)
        return 0;
 }
 
-static void skl_update_wm(struct intel_crtc *intel_crtc)
+static void skl_atomic_update_crtc_wm(struct intel_atomic_state *state,
+                                     struct intel_crtc_state *cstate)
+{
+       struct intel_crtc *crtc = to_intel_crtc(cstate->base.crtc);
+       struct drm_i915_private *dev_priv = to_i915(state->base.dev);
+       struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
+       const struct skl_ddb_allocation *ddb = &state->wm_results.ddb;
+       enum pipe pipe = crtc->pipe;
+       int plane;
+
+       if (!(state->wm_results.dirty_pipes & drm_crtc_mask(&crtc->base)))
+               return;
+
+       I915_WRITE(PIPE_WM_LINETIME(pipe), pipe_wm->linetime);
+
+       for_each_universal_plane(dev_priv, pipe, plane)
+               skl_write_plane_wm(crtc, &pipe_wm->planes[plane], ddb, plane);
+
+       skl_write_cursor_wm(crtc, &pipe_wm->planes[PLANE_CURSOR], ddb);
+}
+
+static void skl_initial_wm(struct intel_atomic_state *state,
+                          struct intel_crtc_state *cstate)
 {
+       struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = to_i915(dev);
-       struct skl_wm_values *results = &dev_priv->wm.skl_results;
+       struct skl_wm_values *results = &state->wm_results;
        struct skl_wm_values *hw_vals = &dev_priv->wm.skl_hw;
-       struct intel_crtc_state *cstate = to_intel_crtc_state(intel_crtc->base.state);
-       struct skl_pipe_wm *pipe_wm = &cstate->wm.skl.optimal;
        enum pipe pipe = intel_crtc->pipe;
 
        if ((results->dirty_pipes & drm_crtc_mask(&intel_crtc->base)) == 0)
@@ -4207,27 +4229,11 @@ static void skl_update_wm(struct intel_crtc *intel_crtc)
 
        mutex_lock(&dev_priv->wm.wm_mutex);
 
-       /*
-        * If this pipe isn't active already, we're going to be enabling it
-        * very soon. Since it's safe to update a pipe's ddb allocation while
-        * the pipe's shut off, just do so here. Already active pipes will have
-        * their watermarks updated once we update their planes.
-        */
-       if (intel_crtc->base.state->active_changed) {
-               int plane;
-
-               for_each_universal_plane(dev_priv, pipe, plane)
-                       skl_write_plane_wm(intel_crtc, &pipe_wm->planes[plane],
-                                          &results->ddb, plane);
-
-               skl_write_cursor_wm(intel_crtc, &pipe_wm->planes[PLANE_CURSOR],
-                                   &results->ddb);
-       }
+       if (cstate->base.active_changed)
+               skl_atomic_update_crtc_wm(state, cstate);
 
        skl_copy_wm_for_pipe(hw_vals, results, pipe);
 
-       intel_crtc->hw_ddb = cstate->wm.skl.ddb;
-
        mutex_unlock(&dev_priv->wm.wm_mutex);
 }
 
@@ -4264,7 +4270,7 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
        ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
 
        /* 5/6 split only in single pipe config on IVB+ */
-       if (INTEL_INFO(dev)->gen >= 7 &&
+       if (INTEL_GEN(dev_priv) >= 7 &&
            config.num_pipes_active == 1 && config.sprites_enabled) {
                ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
                ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
@@ -4282,7 +4288,8 @@ static void ilk_program_watermarks(struct drm_i915_private *dev_priv)
        ilk_write_wm_values(dev_priv, &results);
 }
 
-static void ilk_initial_watermarks(struct intel_crtc_state *cstate)
+static void ilk_initial_watermarks(struct intel_atomic_state *state,
+                                  struct intel_crtc_state *cstate)
 {
        struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
@@ -4293,7 +4300,8 @@ static void ilk_initial_watermarks(struct intel_crtc_state *cstate)
        mutex_unlock(&dev_priv->wm.wm_mutex);
 }
 
-static void ilk_optimize_watermarks(struct intel_crtc_state *cstate)
+static void ilk_optimize_watermarks(struct intel_atomic_state *state,
+                                   struct intel_crtc_state *cstate)
 {
        struct drm_i915_private *dev_priv = to_i915(cstate->base.crtc->dev);
        struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
@@ -4535,11 +4543,11 @@ void vlv_wm_get_hw_state(struct drm_device *dev)
                        plane->wm.fifo_size = 63;
                        break;
                case DRM_PLANE_TYPE_PRIMARY:
-                       plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, 0);
+                       plane->wm.fifo_size = vlv_get_fifo_size(dev_priv, plane->pipe, 0);
                        break;
                case DRM_PLANE_TYPE_OVERLAY:
                        sprite = plane->plane;
-                       plane->wm.fifo_size = vlv_get_fifo_size(dev, plane->pipe, sprite + 1);
+                       plane->wm.fifo_size = vlv_get_fifo_size(dev_priv, plane->pipe, sprite + 1);
                        break;
                }
        }
@@ -4604,7 +4612,7 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
        hw->wm_lp[2] = I915_READ(WM3_LP_ILK);
 
        hw->wm_lp_spr[0] = I915_READ(WM1S_LP_ILK);
-       if (INTEL_INFO(dev)->gen >= 7) {
+       if (INTEL_GEN(dev_priv) >= 7) {
                hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
                hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
        }
@@ -6844,10 +6852,8 @@ void intel_autoenable_gt_powersave(struct drm_i915_private *dev_priv)
        }
 }
 
-static void ibx_init_clock_gating(struct drm_device *dev)
+static void ibx_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /*
         * On Ibex Peak and Cougar Point, we need to disable clock
         * gating for the panel power sequencer or it will fail to
@@ -6856,9 +6862,8 @@ static void ibx_init_clock_gating(struct drm_device *dev)
        I915_WRITE(SOUTH_DSPCLK_GATE_D, PCH_DPLSUNIT_CLOCK_GATE_DISABLE);
 }
 
-static void g4x_disable_trickle_feed(struct drm_device *dev)
+static void g4x_disable_trickle_feed(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        enum pipe pipe;
 
        for_each_pipe(dev_priv, pipe) {
@@ -6871,10 +6876,8 @@ static void g4x_disable_trickle_feed(struct drm_device *dev)
        }
 }
 
-static void ilk_init_lp_watermarks(struct drm_device *dev)
+static void ilk_init_lp_watermarks(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN);
        I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN);
        I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
@@ -6885,9 +6888,8 @@ static void ilk_init_lp_watermarks(struct drm_device *dev)
         */
 }
 
-static void ironlake_init_clock_gating(struct drm_device *dev)
+static void ironlake_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
 
        /*
@@ -6919,7 +6921,7 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
                   (I915_READ(DISP_ARB_CTL) |
                    DISP_FBC_WM_DIS));
 
-       ilk_init_lp_watermarks(dev);
+       ilk_init_lp_watermarks(dev_priv);
 
        /*
         * Based on the document from hardware guys the following bits
@@ -6954,14 +6956,13 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
        /* WaDisable_RenderCache_OperationalFlush:ilk */
        I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 
-       g4x_disable_trickle_feed(dev);
+       g4x_disable_trickle_feed(dev_priv);
 
-       ibx_init_clock_gating(dev);
+       ibx_init_clock_gating(dev_priv);
 }
 
-static void cpt_init_clock_gating(struct drm_device *dev)
+static void cpt_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        int pipe;
        uint32_t val;
 
@@ -6996,9 +6997,8 @@ static void cpt_init_clock_gating(struct drm_device *dev)
        }
 }
 
-static void gen6_check_mch_setup(struct drm_device *dev)
+static void gen6_check_mch_setup(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t tmp;
 
        tmp = I915_READ(MCH_SSKPD);
@@ -7007,9 +7007,8 @@ static void gen6_check_mch_setup(struct drm_device *dev)
                              tmp);
 }
 
-static void gen6_init_clock_gating(struct drm_device *dev)
+static void gen6_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dspclk_gate = ILK_VRHUNIT_CLOCK_GATE_DISABLE;
 
        I915_WRITE(ILK_DSPCLK_GATE_D, dspclk_gate);
@@ -7036,7 +7035,7 @@ static void gen6_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN6_GT_MODE,
                   _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
 
-       ilk_init_lp_watermarks(dev);
+       ilk_init_lp_watermarks(dev_priv);
 
        I915_WRITE(CACHE_MODE_0,
                   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
@@ -7097,11 +7096,11 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                   ILK_DPARBUNIT_CLOCK_GATE_ENABLE  |
                   ILK_DPFDUNIT_CLOCK_GATE_ENABLE);
 
-       g4x_disable_trickle_feed(dev);
+       g4x_disable_trickle_feed(dev_priv);
 
-       cpt_init_clock_gating(dev);
+       cpt_init_clock_gating(dev_priv);
 
-       gen6_check_mch_setup(dev);
+       gen6_check_mch_setup(dev_priv);
 }
 
 static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
@@ -7122,10 +7121,8 @@ static void gen7_setup_fixed_func_scheduler(struct drm_i915_private *dev_priv)
        I915_WRITE(GEN7_FF_THREAD_MODE, reg);
 }
 
-static void lpt_init_clock_gating(struct drm_device *dev)
+static void lpt_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /*
         * TODO: this bit should only be enabled when really needed, then
         * disabled when not needed anymore in order to save power.
@@ -7141,10 +7138,8 @@ static void lpt_init_clock_gating(struct drm_device *dev)
                   TRANS_CHICKEN1_DP0UNIT_GC_DISABLE);
 }
 
-static void lpt_suspend_hw(struct drm_device *dev)
+static void lpt_suspend_hw(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        if (HAS_PCH_LPT_LP(dev_priv)) {
                uint32_t val = I915_READ(SOUTH_DSPCLK_GATE_D);
 
@@ -7176,11 +7171,9 @@ static void gen8_set_l3sqc_credits(struct drm_i915_private *dev_priv,
        I915_WRITE(GEN7_MISCCPCTL, misccpctl);
 }
 
-static void kabylake_init_clock_gating(struct drm_device *dev)
+static void kabylake_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       gen9_init_clock_gating(dev);
+       gen9_init_clock_gating(dev_priv);
 
        /* WaDisableSDEUnitClockGating:kbl */
        if (IS_KBL_REVID(dev_priv, 0, KBL_REVID_B0))
@@ -7197,11 +7190,9 @@ static void kabylake_init_clock_gating(struct drm_device *dev)
                   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
 }
 
-static void skylake_init_clock_gating(struct drm_device *dev)
+static void skylake_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       gen9_init_clock_gating(dev);
+       gen9_init_clock_gating(dev_priv);
 
        /* WAC6entrylatency:skl */
        I915_WRITE(FBC_LLC_READ_CTRL, I915_READ(FBC_LLC_READ_CTRL) |
@@ -7212,12 +7203,11 @@ static void skylake_init_clock_gating(struct drm_device *dev)
                   ILK_DPFC_NUKE_ON_ANY_MODIFICATION);
 }
 
-static void broadwell_init_clock_gating(struct drm_device *dev)
+static void broadwell_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        enum pipe pipe;
 
-       ilk_init_lp_watermarks(dev);
+       ilk_init_lp_watermarks(dev_priv);
 
        /* WaSwitchSolVfFArbitrationPriority:bdw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
@@ -7260,14 +7250,12 @@ static void broadwell_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CHICKEN_PAR2_1, I915_READ(CHICKEN_PAR2_1)
                   | KVM_CONFIG_CHANGE_NOTIFICATION_SELECT);
 
-       lpt_init_clock_gating(dev);
+       lpt_init_clock_gating(dev_priv);
 }
 
-static void haswell_init_clock_gating(struct drm_device *dev)
+static void haswell_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       ilk_init_lp_watermarks(dev);
+       ilk_init_lp_watermarks(dev_priv);
 
        /* L3 caching of data atomics doesn't work -- disable it. */
        I915_WRITE(HSW_SCRATCH1, HSW_SCRATCH1_L3_DATA_ATOMICS_DISABLE);
@@ -7316,15 +7304,14 @@ static void haswell_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CHICKEN_PAR1_1,
                   I915_READ(CHICKEN_PAR1_1) | FORCE_ARB_IDLE_PLANES);
 
-       lpt_init_clock_gating(dev);
+       lpt_init_clock_gating(dev_priv);
 }
 
-static void ivybridge_init_clock_gating(struct drm_device *dev)
+static void ivybridge_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t snpcr;
 
-       ilk_init_lp_watermarks(dev);
+       ilk_init_lp_watermarks(dev_priv);
 
        I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
 
@@ -7381,7 +7368,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
                        I915_READ(GEN7_SQ_CHICKEN_MBCUNIT_CONFIG) |
                        GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB);
 
-       g4x_disable_trickle_feed(dev);
+       g4x_disable_trickle_feed(dev_priv);
 
        gen7_setup_fixed_func_scheduler(dev_priv);
 
@@ -7412,15 +7399,13 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
 
        if (!HAS_PCH_NOP(dev_priv))
-               cpt_init_clock_gating(dev);
+               cpt_init_clock_gating(dev_priv);
 
-       gen6_check_mch_setup(dev);
+       gen6_check_mch_setup(dev_priv);
 }
 
-static void valleyview_init_clock_gating(struct drm_device *dev)
+static void valleyview_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /* WaDisableEarlyCull:vlv */
        I915_WRITE(_3D_CHICKEN3,
                   _MASKED_BIT_ENABLE(_3D_CHICKEN_SF_DISABLE_OBJEND_CULL));
@@ -7499,10 +7484,8 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(VLV_GUNIT_CLOCK_GATE, GCFG_DIS);
 }
 
-static void cherryview_init_clock_gating(struct drm_device *dev)
+static void cherryview_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        /* WaVSRefCountFullforceMissDisable:chv */
        /* WaDSRefCountFullforceMissDisable:chv */
        I915_WRITE(GEN7_FF_THREAD_MODE,
@@ -7535,9 +7518,8 @@ static void cherryview_init_clock_gating(struct drm_device *dev)
        I915_WRITE(HSW_GTT_CACHE_EN, GTT_CACHE_EN_ALL);
 }
 
-static void g4x_init_clock_gating(struct drm_device *dev)
+static void g4x_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        uint32_t dspclk_gate;
 
        I915_WRITE(RENCLK_GATE_D1, 0);
@@ -7559,13 +7541,11 @@ static void g4x_init_clock_gating(struct drm_device *dev)
        /* WaDisable_RenderCache_OperationalFlush:g4x */
        I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 
-       g4x_disable_trickle_feed(dev);
+       g4x_disable_trickle_feed(dev_priv);
 }
 
-static void crestline_init_clock_gating(struct drm_device *dev)
+static void crestline_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        I915_WRITE(RENCLK_GATE_D1, I965_RCC_CLOCK_GATE_DISABLE);
        I915_WRITE(RENCLK_GATE_D2, 0);
        I915_WRITE(DSPCLK_GATE_D, 0);
@@ -7578,10 +7558,8 @@ static void crestline_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 }
 
-static void broadwater_init_clock_gating(struct drm_device *dev)
+static void broadwater_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        I915_WRITE(RENCLK_GATE_D1, I965_RCZ_CLOCK_GATE_DISABLE |
                   I965_RCC_CLOCK_GATE_DISABLE |
                   I965_RCPB_CLOCK_GATE_DISABLE |
@@ -7595,16 +7573,15 @@ static void broadwater_init_clock_gating(struct drm_device *dev)
        I915_WRITE(CACHE_MODE_0, _MASKED_BIT_DISABLE(RC_OP_FLUSH_ENABLE));
 }
 
-static void gen3_init_clock_gating(struct drm_device *dev)
+static void gen3_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
        u32 dstate = I915_READ(D_STATE);
 
        dstate |= DSTATE_PLL_D3_OFF | DSTATE_GFX_CLOCK_GATING |
                DSTATE_DOT_CLOCK_GATING;
        I915_WRITE(D_STATE, dstate);
 
-       if (IS_PINEVIEW(dev))
+       if (IS_PINEVIEW(dev_priv))
                I915_WRITE(ECOSKPD, _MASKED_BIT_ENABLE(ECO_GATING_CX_ONLY));
 
        /* IIR "flip pending" means done if this bit is set */
@@ -7620,10 +7597,8 @@ static void gen3_init_clock_gating(struct drm_device *dev)
                   _MASKED_BIT_ENABLE(MI_ARB_DISPLAY_TRICKLE_FEED_DISABLE));
 }
 
-static void i85x_init_clock_gating(struct drm_device *dev)
+static void i85x_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        I915_WRITE(RENCLK_GATE_D1, SV_CLOCK_GATE_DISABLE);
 
        /* interrupts should cause a wake up from C3 */
@@ -7634,10 +7609,8 @@ static void i85x_init_clock_gating(struct drm_device *dev)
                   _MASKED_BIT_ENABLE(MEM_DISPLAY_TRICKLE_FEED_DISABLE));
 }
 
-static void i830_init_clock_gating(struct drm_device *dev)
+static void i830_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        I915_WRITE(DSPCLK_GATE_D, OVRUNIT_CLOCK_GATE_DISABLE);
 
        I915_WRITE(MEM_MODE,
@@ -7645,20 +7618,18 @@ static void i830_init_clock_gating(struct drm_device *dev)
                   _MASKED_BIT_ENABLE(MEM_DISPLAY_B_TRICKLE_FEED_DISABLE));
 }
 
-void intel_init_clock_gating(struct drm_device *dev)
+void intel_init_clock_gating(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
-       dev_priv->display.init_clock_gating(dev);
+       dev_priv->display.init_clock_gating(dev_priv);
 }
 
-void intel_suspend_hw(struct drm_device *dev)
+void intel_suspend_hw(struct drm_i915_private *dev_priv)
 {
-       if (HAS_PCH_LPT(to_i915(dev)))
-               lpt_suspend_hw(dev);
+       if (HAS_PCH_LPT(dev_priv))
+               lpt_suspend_hw(dev_priv);
 }
 
-static void nop_init_clock_gating(struct drm_device *dev)
+static void nop_init_clock_gating(struct drm_i915_private *dev_priv)
 {
        DRM_DEBUG_KMS("No clock gating settings or workarounds applied.\n");
 }
@@ -7713,25 +7684,24 @@ void intel_init_clock_gating_hooks(struct drm_i915_private *dev_priv)
 }
 
 /* Set up chip specific power management-related functions */
-void intel_init_pm(struct drm_device *dev)
+void intel_init_pm(struct drm_i915_private *dev_priv)
 {
-       struct drm_i915_private *dev_priv = to_i915(dev);
-
        intel_fbc_init(dev_priv);
 
        /* For cxsr */
-       if (IS_PINEVIEW(dev))
-               i915_pineview_get_mem_freq(dev);
+       if (IS_PINEVIEW(dev_priv))
+               i915_pineview_get_mem_freq(dev_priv);
        else if (IS_GEN5(dev_priv))
-               i915_ironlake_get_mem_freq(dev);
+               i915_ironlake_get_mem_freq(dev_priv);
 
        /* For FIFO watermark updates */
-       if (INTEL_INFO(dev)->gen >= 9) {
-               skl_setup_wm_latency(dev);
-               dev_priv->display.update_wm = skl_update_wm;
+       if (INTEL_GEN(dev_priv) >= 9) {
+               skl_setup_wm_latency(dev_priv);
+               dev_priv->display.initial_watermarks = skl_initial_wm;
+               dev_priv->display.atomic_update_watermarks = skl_atomic_update_crtc_wm;
                dev_priv->display.compute_global_watermarks = skl_compute_wm;
        } else if (HAS_PCH_SPLIT(dev_priv)) {
-               ilk_setup_wm_latency(dev);
+               ilk_setup_wm_latency(dev_priv);
 
                if ((IS_GEN5(dev_priv) && dev_priv->wm.pri_latency[1] &&
                     dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
@@ -7749,12 +7719,12 @@ void intel_init_pm(struct drm_device *dev)
                                      "Disable CxSR\n");
                }
        } else if (IS_CHERRYVIEW(dev_priv)) {
-               vlv_setup_wm_latency(dev);
+               vlv_setup_wm_latency(dev_priv);
                dev_priv->display.update_wm = vlv_update_wm;
        } else if (IS_VALLEYVIEW(dev_priv)) {
-               vlv_setup_wm_latency(dev);
+               vlv_setup_wm_latency(dev_priv);
                dev_priv->display.update_wm = vlv_update_wm;
-       } else if (IS_PINEVIEW(dev)) {
+       } else if (IS_PINEVIEW(dev_priv)) {
                if (!intel_get_cxsr_latency(IS_PINEVIEW_G(dev_priv),
                                            dev_priv->is_ddr3,
                                            dev_priv->fsb_freq,
@@ -7777,7 +7747,7 @@ void intel_init_pm(struct drm_device *dev)
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
        } else if (IS_GEN2(dev_priv)) {
-               if (INTEL_INFO(dev)->num_pipes == 1) {
+               if (INTEL_INFO(dev_priv)->num_pipes == 1) {
                        dev_priv->display.update_wm = i845_update_wm;
                        dev_priv->display.get_fifo_size = i845_get_fifo_size;
                } else {
@@ -7920,6 +7890,81 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv,
        return 0;
 }
 
+static bool skl_pcode_try_request(struct drm_i915_private *dev_priv, u32 mbox,
+                                 u32 request, u32 reply_mask, u32 reply,
+                                 u32 *status)
+{
+       u32 val = request;
+
+       *status = sandybridge_pcode_read(dev_priv, mbox, &val);
+
+       return *status || ((val & reply_mask) == reply);
+}
+
+/**
+ * skl_pcode_request - send PCODE request until acknowledgment
+ * @dev_priv: device private
+ * @mbox: PCODE mailbox ID the request is targeted for
+ * @request: request ID
+ * @reply_mask: mask used to check for request acknowledgment
+ * @reply: value used to check for request acknowledgment
+ * @timeout_base_ms: timeout for polling with preemption enabled
+ *
+ * Keep resending the @request to @mbox until PCODE acknowledges it, PCODE
+ * reports an error or an overall timeout of @timeout_base_ms+10 ms expires.
+ * The request is acknowledged once the PCODE reply dword equals @reply after
+ * applying @reply_mask. Polling is first attempted with preemption enabled
+ * for @timeout_base_ms and if this times out for another 10 ms with
+ * preemption disabled.
+ *
+ * Returns 0 on success, %-ETIMEDOUT in case of a timeout, <0 in case of some
+ * other error as reported by PCODE.
+ */
+int skl_pcode_request(struct drm_i915_private *dev_priv, u32 mbox, u32 request,
+                     u32 reply_mask, u32 reply, int timeout_base_ms)
+{
+       u32 status;
+       int ret;
+
+       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
+
+#define COND skl_pcode_try_request(dev_priv, mbox, request, reply_mask, reply, \
+                                  &status)
+
+       /*
+        * Prime the PCODE by doing a request first. Normally it guarantees
+        * that a subsequent request, at most @timeout_base_ms later, succeeds.
+        * _wait_for() doesn't guarantee when its passed condition is evaluated
+        * first, so send the first request explicitly.
+        */
+       if (COND) {
+               ret = 0;
+               goto out;
+       }
+       ret = _wait_for(COND, timeout_base_ms * 1000, 10);
+       if (!ret)
+               goto out;
+
+       /*
+        * The above can time out if the number of requests was low (2 in the
+        * worst case) _and_ PCODE was busy for some reason even after a
+        * (queued) request and @timeout_base_ms delay. As a workaround retry
+        * the poll with preemption disabled to maximize the number of
+        * requests. Increase the timeout from @timeout_base_ms to 10ms to
+        * account for interrupts that could reduce the number of these
+        * requests.
+        */
+       DRM_DEBUG_KMS("PCODE timeout, retrying with preemption disabled\n");
+       WARN_ON_ONCE(timeout_base_ms > 3);
+       preempt_disable();
+       ret = wait_for_atomic(COND, 10);
+       preempt_enable();
+
+out:
+       return ret ? ret : status;
+#undef COND
+}
+
 static int byt_gpu_freq(struct drm_i915_private *dev_priv, int val)
 {
        /*