]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/intel_pm.c
Merge remote-tracking branch 'drm/drm-next'
[karo-tx-linux.git] / drivers / gpu / drm / i915 / intel_pm.c
index f091ad12d694a43ebb0dce69b31089ffd4abe366..5f4b494ec46270af61eaaa5fadee340a08fc41bb 100644 (file)
@@ -32,6 +32,8 @@
 #include <linux/module.h>
 
 /**
+ * DOC: RC6
+ *
  * RC6 is a special power stage which allows the GPU to enter an very
  * low-voltage mode when idle, using down to 0V while at this stage.  This
  * stage is entered automatically when the GPU is idle when RC6 support is
@@ -66,6 +68,14 @@ static void bxt_init_clock_gating(struct drm_device *dev)
         */
        I915_WRITE(GEN8_UCGCTL6, I915_READ(GEN8_UCGCTL6) |
                   GEN8_HDCUNIT_CLOCK_GATE_DISABLE_HDCREQ);
+
+       /*
+        * Wa: Backlight PWM may stop in the asserted state, causing backlight
+        * to stay fully on.
+        */
+       if (IS_BXT_REVID(dev_priv, BXT_REVID_B0, REVID_FOREVER))
+               I915_WRITE(GEN9_CLKGATE_DIS_0, I915_READ(GEN9_CLKGATE_DIS_0) |
+                          PWM1_GATING_DIS | PWM2_GATING_DIS);
 }
 
 static void i915_pineview_get_mem_freq(struct drm_device *dev)
@@ -283,7 +293,7 @@ void intel_set_memory_cxsr(struct drm_i915_private *dev_priv, bool enable)
        struct drm_device *dev = dev_priv->dev;
        u32 val;
 
-       if (IS_VALLEYVIEW(dev)) {
+       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                I915_WRITE(FW_BLC_SELF_VLV, enable ? FW_CSPWRDWNEN : 0);
                POSTING_READ(FW_BLC_SELF_VLV);
                dev_priv->wm.vlv.cxsr = enable;
@@ -1664,6 +1674,9 @@ uint32_t ilk_pipe_pixel_rate(const struct intel_crtc_state *pipe_config)
                if (pipe_h < pfit_h)
                        pipe_h = pfit_h;
 
+               if (WARN_ON(!pfit_w || !pfit_h))
+                       return pixel_rate;
+
                pixel_rate = div_u64((uint64_t) pixel_rate * pipe_w * pipe_h,
                                     pfit_w * pfit_h);
        }
@@ -1695,6 +1708,8 @@ static uint32_t ilk_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
 
        if (WARN(latency == 0, "Latency value missing\n"))
                return UINT_MAX;
+       if (WARN_ON(!pipe_htotal))
+               return UINT_MAX;
 
        ret = (latency * pixel_rate) / (pipe_htotal * 10000);
        ret = (ret + 1) * horiz_pixels * bytes_per_pixel;
@@ -1705,16 +1720,20 @@ static uint32_t ilk_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
 static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
                           uint8_t bytes_per_pixel)
 {
+       /*
+        * Neither of these should be possible since this function shouldn't be
+        * called if the CRTC is off or the plane is invisible.  But let's be
+        * extra paranoid to avoid a potential divide-by-zero if we screw up
+        * elsewhere in the driver.
+        */
+       if (WARN_ON(!bytes_per_pixel))
+               return 0;
+       if (WARN_ON(!horiz_pixels))
+               return 0;
+
        return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
 }
 
-struct skl_pipe_wm_parameters {
-       bool active;
-       uint32_t pipe_htotal;
-       uint32_t pixel_rate; /* in KHz */
-       struct intel_plane_wm_parameters plane[I915_MAX_PLANES];
-};
-
 struct ilk_wm_maximums {
        uint16_t pri;
        uint16_t spr;
@@ -1722,13 +1741,6 @@ struct ilk_wm_maximums {
        uint16_t fbc;
 };
 
-/* used in computing the new watermarks state */
-struct intel_wm_config {
-       unsigned int num_pipes_active;
-       bool sprites_enabled;
-       bool sprites_scaled;
-};
-
 /*
  * For both WM_PIPE and WM_LP.
  * mem_value must be in 0.1us units.
@@ -1789,16 +1801,20 @@ static uint32_t ilk_compute_cur_wm(const struct intel_crtc_state *cstate,
                                   const struct intel_plane_state *pstate,
                                   uint32_t mem_value)
 {
-       int bpp = pstate->base.fb ? pstate->base.fb->bits_per_pixel / 8 : 0;
+       /*
+        * We treat the cursor plane as always-on for the purposes of watermark
+        * calculation.  Until we have two-stage watermark programming merged,
+        * this is necessary to avoid flickering.
+        */
+       int cpp = 4;
+       int width = pstate->visible ? pstate->base.crtc_w : 64;
 
-       if (!cstate->base.active || !pstate->visible)
+       if (!cstate->base.active)
                return 0;
 
        return ilk_wm_method2(ilk_pipe_pixel_rate(cstate),
                              cstate->base.adjusted_mode.crtc_htotal,
-                             drm_rect_width(&pstate->dst),
-                             bpp,
-                             mem_value);
+                             width, cpp, mem_value);
 }
 
 /* Only for WM_LP. */
@@ -1979,9 +1995,11 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
                                 const struct intel_crtc *intel_crtc,
                                 int level,
                                 struct intel_crtc_state *cstate,
+                                struct intel_plane_state *pristate,
+                                struct intel_plane_state *sprstate,
+                                struct intel_plane_state *curstate,
                                 struct intel_wm_level *result)
 {
-       struct intel_plane *intel_plane;
        uint16_t pri_latency = dev_priv->wm.pri_latency[level];
        uint16_t spr_latency = dev_priv->wm.spr_latency[level];
        uint16_t cur_latency = dev_priv->wm.cur_latency[level];
@@ -1993,41 +2011,28 @@ static void ilk_compute_wm_level(const struct drm_i915_private *dev_priv,
                cur_latency *= 5;
        }
 
-       for_each_intel_plane_on_crtc(dev_priv->dev, intel_crtc, intel_plane) {
-               struct intel_plane_state *pstate =
-                       to_intel_plane_state(intel_plane->base.state);
-
-               switch (intel_plane->base.type) {
-               case DRM_PLANE_TYPE_PRIMARY:
-                       result->pri_val = ilk_compute_pri_wm(cstate, pstate,
-                                                            pri_latency,
-                                                            level);
-                       result->fbc_val = ilk_compute_fbc_wm(cstate, pstate,
-                                                            result->pri_val);
-                       break;
-               case DRM_PLANE_TYPE_OVERLAY:
-                       result->spr_val = ilk_compute_spr_wm(cstate, pstate,
-                                                            spr_latency);
-                       break;
-               case DRM_PLANE_TYPE_CURSOR:
-                       result->cur_val = ilk_compute_cur_wm(cstate, pstate,
-                                                            cur_latency);
-                       break;
-               }
-       }
-
+       result->pri_val = ilk_compute_pri_wm(cstate, pristate,
+                                            pri_latency, level);
+       result->spr_val = ilk_compute_spr_wm(cstate, sprstate, spr_latency);
+       result->cur_val = ilk_compute_cur_wm(cstate, curstate, cur_latency);
+       result->fbc_val = ilk_compute_fbc_wm(cstate, pristate, result->pri_val);
        result->enable = true;
 }
 
 static uint32_t
-hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
+hsw_compute_linetime_wm(struct drm_device *dev,
+                       struct intel_crtc_state *cstate)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       const struct drm_display_mode *adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+       const struct drm_display_mode *adjusted_mode =
+               &cstate->base.adjusted_mode;
        u32 linetime, ips_linetime;
 
-       if (!intel_crtc->active)
+       if (!cstate->base.active)
+               return 0;
+       if (WARN_ON(adjusted_mode->crtc_clock == 0))
+               return 0;
+       if (WARN_ON(dev_priv->cdclk_freq == 0))
                return 0;
 
        /* The WM are computed with base on how long it takes to fill a single
@@ -2274,34 +2279,19 @@ static void skl_setup_wm_latency(struct drm_device *dev)
        intel_print_wm_latency(dev, "Gen9 Plane", dev_priv->wm.skl_latency);
 }
 
-static void ilk_compute_wm_config(struct drm_device *dev,
-                                 struct intel_wm_config *config)
-{
-       struct intel_crtc *intel_crtc;
-
-       /* Compute the currently _active_ config */
-       for_each_intel_crtc(dev, intel_crtc) {
-               const struct intel_pipe_wm *wm = &intel_crtc->wm.active;
-
-               if (!wm->pipe_enabled)
-                       continue;
-
-               config->sprites_enabled |= wm->sprites_enabled;
-               config->sprites_scaled |= wm->sprites_scaled;
-               config->num_pipes_active++;
-       }
-}
-
 /* Compute new watermarks for the pipe */
-static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
-                                 struct intel_pipe_wm *pipe_wm)
+static int ilk_compute_pipe_wm(struct intel_crtc *intel_crtc,
+                              struct drm_atomic_state *state)
 {
-       struct drm_crtc *crtc = cstate->base.crtc;
-       struct drm_device *dev = crtc->dev;
+       struct intel_pipe_wm *pipe_wm;
+       struct drm_device *dev = intel_crtc->base.dev;
        const struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *cstate = NULL;
        struct intel_plane *intel_plane;
+       struct drm_plane_state *ps;
+       struct intel_plane_state *pristate = NULL;
        struct intel_plane_state *sprstate = NULL;
+       struct intel_plane_state *curstate = NULL;
        int level, max_level = ilk_wm_max_level(dev);
        /* LP0 watermark maximums depend on this pipe alone */
        struct intel_wm_config config = {
@@ -2309,11 +2299,25 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
        };
        struct ilk_wm_maximums max;
 
+       cstate = intel_atomic_get_crtc_state(state, intel_crtc);
+       if (IS_ERR(cstate))
+               return PTR_ERR(cstate);
+
+       pipe_wm = &cstate->wm.optimal.ilk;
+       memset(pipe_wm, 0, sizeof(*pipe_wm));
+
        for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
-               if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY) {
-                       sprstate = to_intel_plane_state(intel_plane->base.state);
-                       break;
-               }
+               ps = drm_atomic_get_plane_state(state,
+                                               &intel_plane->base);
+               if (IS_ERR(ps))
+                       return PTR_ERR(ps);
+
+               if (intel_plane->base.type == DRM_PLANE_TYPE_PRIMARY)
+                       pristate = to_intel_plane_state(ps);
+               else if (intel_plane->base.type == DRM_PLANE_TYPE_OVERLAY)
+                       sprstate = to_intel_plane_state(ps);
+               else if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+                       curstate = to_intel_plane_state(ps);
        }
 
        config.sprites_enabled = sprstate->visible;
@@ -2322,7 +2326,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
                drm_rect_height(&sprstate->dst) != drm_rect_height(&sprstate->src) >> 16);
 
        pipe_wm->pipe_enabled = cstate->base.active;
-       pipe_wm->sprites_enabled = sprstate->visible;
+       pipe_wm->sprites_enabled = config.sprites_enabled;
        pipe_wm->sprites_scaled = config.sprites_scaled;
 
        /* ILK/SNB: LP2+ watermarks only w/o sprites */
@@ -2333,24 +2337,26 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
        if (config.sprites_scaled)
                max_level = 0;
 
-       ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate, &pipe_wm->wm[0]);
+       ilk_compute_wm_level(dev_priv, intel_crtc, 0, cstate,
+                            pristate, sprstate, curstate, &pipe_wm->wm[0]);
 
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
+               pipe_wm->linetime = hsw_compute_linetime_wm(dev, cstate);
 
        /* LP0 watermarks always use 1/2 DDB partitioning */
        ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
 
        /* At least LP0 must be valid */
        if (!ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]))
-               return false;
+               return -EINVAL;
 
        ilk_compute_wm_reg_maximums(dev, 1, &max);
 
        for (level = 1; level <= max_level; level++) {
                struct intel_wm_level wm = {};
 
-               ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate, &wm);
+               ilk_compute_wm_level(dev_priv, intel_crtc, level, cstate,
+                                    pristate, sprstate, curstate, &wm);
 
                /*
                 * Disable any watermark level that exceeds the
@@ -2363,7 +2369,7 @@ static bool intel_compute_pipe_wm(struct intel_crtc_state *cstate,
                pipe_wm->wm[level] = wm;
        }
 
-       return true;
+       return 0;
 }
 
 /*
@@ -2378,7 +2384,9 @@ static void ilk_merge_wm_level(struct drm_device *dev,
        ret_wm->enable = true;
 
        for_each_intel_crtc(dev, intel_crtc) {
-               const struct intel_pipe_wm *active = &intel_crtc->wm.active;
+               const struct intel_crtc_state *cstate =
+                       to_intel_crtc_state(intel_crtc->base.state);
+               const struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
                const struct intel_wm_level *wm = &active->wm[level];
 
                if (!active->pipe_enabled)
@@ -2449,7 +2457,7 @@ static void ilk_wm_merge(struct drm_device *dev,
         * enabled sometime later.
         */
        if (IS_GEN5(dev) && !merged->fbc_wm_enabled &&
-           intel_fbc_enabled(dev_priv)) {
+           intel_fbc_is_active(dev_priv)) {
                for (level = 2; level <= max_level; level++) {
                        struct intel_wm_level *wm = &merged->wm[level];
 
@@ -2526,14 +2534,15 @@ static void ilk_compute_wm_results(struct drm_device *dev,
 
        /* LP0 register values */
        for_each_intel_crtc(dev, intel_crtc) {
+               const struct intel_crtc_state *cstate =
+                       to_intel_crtc_state(intel_crtc->base.state);
                enum pipe pipe = intel_crtc->pipe;
-               const struct intel_wm_level *r =
-                       &intel_crtc->wm.active.wm[0];
+               const struct intel_wm_level *r = &cstate->wm.optimal.ilk.wm[0];
 
                if (WARN_ON(!r->enable))
                        continue;
 
-               results->wm_linetime[pipe] = intel_crtc->wm.active.linetime;
+               results->wm_linetime[pipe] = cstate->wm.optimal.ilk.linetime;
 
                results->wm_pipe[pipe] =
                        (r->pri_val << WM0_PIPE_PLANE_SHIFT) |
@@ -2755,18 +2764,40 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
 #define SKL_DDB_SIZE           896     /* in blocks */
 #define BXT_DDB_SIZE           512
 
+/*
+ * Return the index of a plane in the SKL DDB and wm result arrays.  Primary
+ * plane is always in slot 0, cursor is always in slot I915_MAX_PLANES-1, and
+ * other universal planes are in indices 1..n.  Note that this may leave unused
+ * indices between the top "sprite" plane and the cursor.
+ */
+static int
+skl_wm_plane_id(const struct intel_plane *plane)
+{
+       switch (plane->base.type) {
+       case DRM_PLANE_TYPE_PRIMARY:
+               return 0;
+       case DRM_PLANE_TYPE_CURSOR:
+               return PLANE_CURSOR;
+       case DRM_PLANE_TYPE_OVERLAY:
+               return plane->plane + 1;
+       default:
+               MISSING_CASE(plane->base.type);
+               return plane->plane;
+       }
+}
+
 static void
 skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
-                                  struct drm_crtc *for_crtc,
+                                  const struct intel_crtc_state *cstate,
                                   const struct intel_wm_config *config,
-                                  const struct skl_pipe_wm_parameters *params,
                                   struct skl_ddb_entry *alloc /* out */)
 {
+       struct drm_crtc *for_crtc = cstate->base.crtc;
        struct drm_crtc *crtc;
        unsigned int pipe_size, ddb_size;
        int nth_active_pipe;
 
-       if (!params->active) {
+       if (!cstate->base.active) {
                alloc->start = 0;
                alloc->end = 0;
                return;
@@ -2837,19 +2868,29 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 }
 
 static unsigned int
-skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
+skl_plane_relative_data_rate(const struct intel_crtc_state *cstate,
+                            const struct drm_plane_state *pstate,
+                            int y)
 {
+       struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+       struct drm_framebuffer *fb = pstate->fb;
 
        /* for planar format */
-       if (p->y_bytes_per_pixel) {
+       if (fb->pixel_format == DRM_FORMAT_NV12) {
                if (y)  /* y-plane data rate */
-                       return p->horiz_pixels * p->vert_pixels * p->y_bytes_per_pixel;
+                       return intel_crtc->config->pipe_src_w *
+                               intel_crtc->config->pipe_src_h *
+                               drm_format_plane_cpp(fb->pixel_format, 0);
                else    /* uv-plane data rate */
-                       return (p->horiz_pixels/2) * (p->vert_pixels/2) * p->bytes_per_pixel;
+                       return (intel_crtc->config->pipe_src_w/2) *
+                               (intel_crtc->config->pipe_src_h/2) *
+                               drm_format_plane_cpp(fb->pixel_format, 1);
        }
 
        /* for packed formats */
-       return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
+       return intel_crtc->config->pipe_src_w *
+               intel_crtc->config->pipe_src_h *
+               drm_format_plane_cpp(fb->pixel_format, 0);
 }
 
 /*
@@ -2858,46 +2899,55 @@ skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p, int y)
  *   3 * 4096 * 8192  * 4 < 2^32
  */
 static unsigned int
-skl_get_total_relative_data_rate(struct intel_crtc *intel_crtc,
-                                const struct skl_pipe_wm_parameters *params)
+skl_get_total_relative_data_rate(const struct intel_crtc_state *cstate)
 {
+       struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+       struct drm_device *dev = intel_crtc->base.dev;
+       const struct intel_plane *intel_plane;
        unsigned int total_data_rate = 0;
-       int plane;
 
-       for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
-               const struct intel_plane_wm_parameters *p;
+       for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+               const struct drm_plane_state *pstate = intel_plane->base.state;
 
-               p = &params->plane[plane];
-               if (!p->enabled)
+               if (pstate->fb == NULL)
                        continue;
 
-               total_data_rate += skl_plane_relative_data_rate(p, 0); /* packed/uv */
-               if (p->y_bytes_per_pixel) {
-                       total_data_rate += skl_plane_relative_data_rate(p, 1); /* y-plane */
-               }
+               if (intel_plane->base.type == DRM_PLANE_TYPE_CURSOR)
+                       continue;
+
+               /* packed/uv */
+               total_data_rate += skl_plane_relative_data_rate(cstate,
+                                                               pstate,
+                                                               0);
+
+               if (pstate->fb->pixel_format == DRM_FORMAT_NV12)
+                       /* y-plane */
+                       total_data_rate += skl_plane_relative_data_rate(cstate,
+                                                                       pstate,
+                                                                       1);
        }
 
        return total_data_rate;
 }
 
 static void
-skl_allocate_pipe_ddb(struct drm_crtc *crtc,
-                     const struct intel_wm_config *config,
-                     const struct skl_pipe_wm_parameters *params,
+skl_allocate_pipe_ddb(struct intel_crtc_state *cstate,
                      struct skl_ddb_allocation *ddb /* out */)
 {
+       struct drm_crtc *crtc = cstate->base.crtc;
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_wm_config *config = &dev_priv->wm.config;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_plane *intel_plane;
        enum pipe pipe = intel_crtc->pipe;
        struct skl_ddb_entry *alloc = &ddb->pipe[pipe];
        uint16_t alloc_size, start, cursor_blocks;
        uint16_t minimum[I915_MAX_PLANES];
        uint16_t y_minimum[I915_MAX_PLANES];
        unsigned int total_data_rate;
-       int plane;
 
-       skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, alloc);
+       skl_ddb_get_pipe_allocation_limits(dev, cstate, config, alloc);
        alloc_size = skl_ddb_entry_size(alloc);
        if (alloc_size == 0) {
                memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
@@ -2914,17 +2964,20 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
        alloc->end -= cursor_blocks;
 
        /* 1. Allocate the mininum required blocks for each active plane */
-       for_each_plane(dev_priv, pipe, plane) {
-               const struct intel_plane_wm_parameters *p;
+       for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+               struct drm_plane *plane = &intel_plane->base;
+               struct drm_framebuffer *fb = plane->state->fb;
+               int id = skl_wm_plane_id(intel_plane);
 
-               p = &params->plane[plane];
-               if (!p->enabled)
+               if (fb == NULL)
+                       continue;
+               if (plane->type == DRM_PLANE_TYPE_CURSOR)
                        continue;
 
-               minimum[plane] = 8;
-               alloc_size -= minimum[plane];
-               y_minimum[plane] = p->y_bytes_per_pixel ? 8 : 0;
-               alloc_size -= y_minimum[plane];
+               minimum[id] = 8;
+               alloc_size -= minimum[id];
+               y_minimum[id] = (fb->pixel_format == DRM_FORMAT_NV12) ? 8 : 0;
+               alloc_size -= y_minimum[id];
        }
 
        /*
@@ -2933,45 +2986,50 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
         *
         * FIXME: we may not allocate every single block here.
         */
-       total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
+       total_data_rate = skl_get_total_relative_data_rate(cstate);
 
        start = alloc->start;
-       for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
-               const struct intel_plane_wm_parameters *p;
+       for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+               struct drm_plane *plane = &intel_plane->base;
+               struct drm_plane_state *pstate = intel_plane->base.state;
                unsigned int data_rate, y_data_rate;
                uint16_t plane_blocks, y_plane_blocks = 0;
+               int id = skl_wm_plane_id(intel_plane);
 
-               p = &params->plane[plane];
-               if (!p->enabled)
+               if (pstate->fb == NULL)
+                       continue;
+               if (plane->type == DRM_PLANE_TYPE_CURSOR)
                        continue;
 
-               data_rate = skl_plane_relative_data_rate(p, 0);
+               data_rate = skl_plane_relative_data_rate(cstate, pstate, 0);
 
                /*
                 * allocation for (packed formats) or (uv-plane part of planar format):
                 * promote the expression to 64 bits to avoid overflowing, the
                 * result is < available as data_rate / total_data_rate < 1
                 */
-               plane_blocks = minimum[plane];
+               plane_blocks = minimum[id];
                plane_blocks += div_u64((uint64_t)alloc_size * data_rate,
                                        total_data_rate);
 
-               ddb->plane[pipe][plane].start = start;
-               ddb->plane[pipe][plane].end = start + plane_blocks;
+               ddb->plane[pipe][id].start = start;
+               ddb->plane[pipe][id].end = start + plane_blocks;
 
                start += plane_blocks;
 
                /*
                 * allocation for y_plane part of planar format:
                 */
-               if (p->y_bytes_per_pixel) {
-                       y_data_rate = skl_plane_relative_data_rate(p, 1);
-                       y_plane_blocks = y_minimum[plane];
+               if (pstate->fb->pixel_format == DRM_FORMAT_NV12) {
+                       y_data_rate = skl_plane_relative_data_rate(cstate,
+                                                                  pstate,
+                                                                  1);
+                       y_plane_blocks = y_minimum[id];
                        y_plane_blocks += div_u64((uint64_t)alloc_size * y_data_rate,
                                                total_data_rate);
 
-                       ddb->y_plane[pipe][plane].start = start;
-                       ddb->y_plane[pipe][plane].end = start + y_plane_blocks;
+                       ddb->y_plane[pipe][id].start = start;
+                       ddb->y_plane[pipe][id].end = start + y_plane_blocks;
 
                        start += y_plane_blocks;
                }
@@ -3041,104 +3099,27 @@ static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
        struct drm_device *dev = intel_crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        const struct skl_ddb_allocation *cur_ddb = &dev_priv->wm.skl_hw.ddb;
-       enum pipe pipe = intel_crtc->pipe;
-
-       if (memcmp(new_ddb->plane[pipe], cur_ddb->plane[pipe],
-                  sizeof(new_ddb->plane[pipe])))
-               return true;
 
-       if (memcmp(&new_ddb->plane[pipe][PLANE_CURSOR], &cur_ddb->plane[pipe][PLANE_CURSOR],
-                   sizeof(new_ddb->plane[pipe][PLANE_CURSOR])))
+       /*
+        * If ddb allocation of pipes changed, it may require recalculation of
+        * watermarks
+        */
+       if (memcmp(new_ddb->pipe, cur_ddb->pipe, sizeof(new_ddb->pipe)))
                return true;
 
        return false;
 }
 
-static void skl_compute_wm_global_parameters(struct drm_device *dev,
-                                            struct intel_wm_config *config)
-{
-       struct drm_crtc *crtc;
-       struct drm_plane *plane;
-
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
-               config->num_pipes_active += to_intel_crtc(crtc)->active;
-
-       /* FIXME: I don't think we need those two global parameters on SKL */
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               struct intel_plane *intel_plane = to_intel_plane(plane);
-
-               config->sprites_enabled |= intel_plane->wm.enabled;
-               config->sprites_scaled |= intel_plane->wm.scaled;
-       }
-}
-
-static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
-                                          struct skl_pipe_wm_parameters *p)
-{
-       struct drm_device *dev = crtc->dev;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       enum pipe pipe = intel_crtc->pipe;
-       struct drm_plane *plane;
-       struct drm_framebuffer *fb;
-       int i = 1; /* Index for sprite planes start */
-
-       p->active = intel_crtc->active;
-       if (p->active) {
-               p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
-               p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
-
-               fb = crtc->primary->state->fb;
-               /* For planar: Bpp is for uv plane, y_Bpp is for y plane */
-               if (fb) {
-                       p->plane[0].enabled = true;
-                       p->plane[0].bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
-                               drm_format_plane_cpp(fb->pixel_format, 1) :
-                               drm_format_plane_cpp(fb->pixel_format, 0);
-                       p->plane[0].y_bytes_per_pixel = fb->pixel_format == DRM_FORMAT_NV12 ?
-                               drm_format_plane_cpp(fb->pixel_format, 0) : 0;
-                       p->plane[0].tiling = fb->modifier[0];
-               } else {
-                       p->plane[0].enabled = false;
-                       p->plane[0].bytes_per_pixel = 0;
-                       p->plane[0].y_bytes_per_pixel = 0;
-                       p->plane[0].tiling = DRM_FORMAT_MOD_NONE;
-               }
-               p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
-               p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
-               p->plane[0].rotation = crtc->primary->state->rotation;
-
-               fb = crtc->cursor->state->fb;
-               p->plane[PLANE_CURSOR].y_bytes_per_pixel = 0;
-               if (fb) {
-                       p->plane[PLANE_CURSOR].enabled = true;
-                       p->plane[PLANE_CURSOR].bytes_per_pixel = fb->bits_per_pixel / 8;
-                       p->plane[PLANE_CURSOR].horiz_pixels = crtc->cursor->state->crtc_w;
-                       p->plane[PLANE_CURSOR].vert_pixels = crtc->cursor->state->crtc_h;
-               } else {
-                       p->plane[PLANE_CURSOR].enabled = false;
-                       p->plane[PLANE_CURSOR].bytes_per_pixel = 0;
-                       p->plane[PLANE_CURSOR].horiz_pixels = 64;
-                       p->plane[PLANE_CURSOR].vert_pixels = 64;
-               }
-       }
-
-       list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
-               struct intel_plane *intel_plane = to_intel_plane(plane);
-
-               if (intel_plane->pipe == pipe &&
-                       plane->type == DRM_PLANE_TYPE_OVERLAY)
-                       p->plane[i++] = intel_plane->wm;
-       }
-}
-
 static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
-                                struct skl_pipe_wm_parameters *p,
-                                struct intel_plane_wm_parameters *p_params,
+                                struct intel_crtc_state *cstate,
+                                struct intel_plane *intel_plane,
                                 uint16_t ddb_allocation,
                                 int level,
                                 uint16_t *out_blocks, /* out */
                                 uint8_t *out_lines /* out */)
 {
+       struct drm_plane *plane = &intel_plane->base;
+       struct drm_framebuffer *fb = plane->state->fb;
        uint32_t latency = dev_priv->wm.skl_latency[level];
        uint32_t method1, method2;
        uint32_t plane_bytes_per_line, plane_blocks_per_line;
@@ -3146,31 +3127,33 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        uint32_t selected_result;
        uint8_t bytes_per_pixel;
 
-       if (latency == 0 || !p->active || !p_params->enabled)
+       if (latency == 0 || !cstate->base.active || !fb)
                return false;
 
-       bytes_per_pixel = p_params->y_bytes_per_pixel ?
-               p_params->y_bytes_per_pixel :
-               p_params->bytes_per_pixel;
-       method1 = skl_wm_method1(p->pixel_rate,
+       bytes_per_pixel = drm_format_plane_cpp(fb->pixel_format, 0);
+       method1 = skl_wm_method1(skl_pipe_pixel_rate(cstate),
                                 bytes_per_pixel,
                                 latency);
-       method2 = skl_wm_method2(p->pixel_rate,
-                                p->pipe_htotal,
-                                p_params->horiz_pixels,
+       method2 = skl_wm_method2(skl_pipe_pixel_rate(cstate),
+                                cstate->base.adjusted_mode.crtc_htotal,
+                                cstate->pipe_src_w,
                                 bytes_per_pixel,
-                                p_params->tiling,
+                                fb->modifier[0],
                                 latency);
 
-       plane_bytes_per_line = p_params->horiz_pixels * bytes_per_pixel;
+       plane_bytes_per_line = cstate->pipe_src_w * bytes_per_pixel;
        plane_blocks_per_line = DIV_ROUND_UP(plane_bytes_per_line, 512);
 
-       if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
-           p_params->tiling == I915_FORMAT_MOD_Yf_TILED) {
+       if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+           fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED) {
                uint32_t min_scanlines = 4;
                uint32_t y_tile_minimum;
-               if (intel_rotation_90_or_270(p_params->rotation)) {
-                       switch (p_params->bytes_per_pixel) {
+               if (intel_rotation_90_or_270(plane->state->rotation)) {
+                       int bpp = (fb->pixel_format == DRM_FORMAT_NV12) ?
+                               drm_format_plane_cpp(fb->pixel_format, 1) :
+                               drm_format_plane_cpp(fb->pixel_format, 0);
+
+                       switch (bpp) {
                        case 1:
                                min_scanlines = 16;
                                break;
@@ -3194,8 +3177,8 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
        res_lines = DIV_ROUND_UP(selected_result, plane_blocks_per_line);
 
        if (level >= 1 && level <= 7) {
-               if (p_params->tiling == I915_FORMAT_MOD_Y_TILED ||
-                   p_params->tiling == I915_FORMAT_MOD_Yf_TILED)
+               if (fb->modifier[0] == I915_FORMAT_MOD_Y_TILED ||
+                   fb->modifier[0] == I915_FORMAT_MOD_Yf_TILED)
                        res_lines += 4;
                else
                        res_blocks++;
@@ -3212,84 +3195,80 @@ static bool skl_compute_plane_wm(const struct drm_i915_private *dev_priv,
 
 static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
                                 struct skl_ddb_allocation *ddb,
-                                struct skl_pipe_wm_parameters *p,
-                                enum pipe pipe,
+                                struct intel_crtc_state *cstate,
                                 int level,
-                                int num_planes,
                                 struct skl_wm_level *result)
 {
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(cstate->base.crtc);
+       struct intel_plane *intel_plane;
        uint16_t ddb_blocks;
-       int i;
+       enum pipe pipe = intel_crtc->pipe;
+
+       for_each_intel_plane_on_crtc(dev, intel_crtc, intel_plane) {
+               int i = skl_wm_plane_id(intel_plane);
 
-       for (i = 0; i < num_planes; i++) {
                ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][i]);
 
                result->plane_en[i] = skl_compute_plane_wm(dev_priv,
-                                               p, &p->plane[i],
+                                               cstate,
+                                               intel_plane,
                                                ddb_blocks,
                                                level,
                                                &result->plane_res_b[i],
                                                &result->plane_res_l[i]);
        }
-
-       ddb_blocks = skl_ddb_entry_size(&ddb->plane[pipe][PLANE_CURSOR]);
-       result->plane_en[PLANE_CURSOR] = skl_compute_plane_wm(dev_priv, p,
-                                                &p->plane[PLANE_CURSOR],
-                                                ddb_blocks, level,
-                                                &result->plane_res_b[PLANE_CURSOR],
-                                                &result->plane_res_l[PLANE_CURSOR]);
 }
 
 static uint32_t
-skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
+skl_compute_linetime_wm(struct intel_crtc_state *cstate)
 {
-       if (!to_intel_crtc(crtc)->active)
+       if (!cstate->base.active)
                return 0;
 
-       if (WARN_ON(p->pixel_rate == 0))
+       if (WARN_ON(skl_pipe_pixel_rate(cstate) == 0))
                return 0;
 
-       return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
+       return DIV_ROUND_UP(8 * cstate->base.adjusted_mode.crtc_htotal * 1000,
+                           skl_pipe_pixel_rate(cstate));
 }
 
-static void skl_compute_transition_wm(struct drm_crtc *crtc,
-                                     struct skl_pipe_wm_parameters *params,
+static void skl_compute_transition_wm(struct intel_crtc_state *cstate,
                                      struct skl_wm_level *trans_wm /* out */)
 {
+       struct drm_crtc *crtc = cstate->base.crtc;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int i;
+       struct intel_plane *intel_plane;
 
-       if (!params->active)
+       if (!cstate->base.active)
                return;
 
        /* Until we know more, just disable transition WMs */
-       for (i = 0; i < intel_num_planes(intel_crtc); i++)
+       for_each_intel_plane_on_crtc(crtc->dev, intel_crtc, intel_plane) {
+               int i = skl_wm_plane_id(intel_plane);
+
                trans_wm->plane_en[i] = false;
-       trans_wm->plane_en[PLANE_CURSOR] = false;
+       }
 }
 
-static void skl_compute_pipe_wm(struct drm_crtc *crtc,
+static void skl_compute_pipe_wm(struct intel_crtc_state *cstate,
                                struct skl_ddb_allocation *ddb,
-                               struct skl_pipe_wm_parameters *params,
                                struct skl_pipe_wm *pipe_wm)
 {
-       struct drm_device *dev = crtc->dev;
+       struct drm_device *dev = cstate->base.crtc->dev;
        const struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int level, max_level = ilk_wm_max_level(dev);
 
        for (level = 0; level <= max_level; level++) {
-               skl_compute_wm_level(dev_priv, ddb, params, intel_crtc->pipe,
-                                    level, intel_num_planes(intel_crtc),
-                                    &pipe_wm->wm[level]);
+               skl_compute_wm_level(dev_priv, ddb, cstate,
+                                    level, &pipe_wm->wm[level]);
        }
-       pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
+       pipe_wm->linetime = skl_compute_linetime_wm(cstate);
 
-       skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
+       skl_compute_transition_wm(cstate, &pipe_wm->trans_wm);
 }
 
 static void skl_compute_wm_results(struct drm_device *dev,
-                                  struct skl_pipe_wm_parameters *p,
                                   struct skl_pipe_wm *p_wm,
                                   struct skl_wm_values *r,
                                   struct intel_crtc *intel_crtc)
@@ -3346,7 +3325,8 @@ static void skl_compute_wm_results(struct drm_device *dev,
        r->wm_linetime[pipe] = p_wm->linetime;
 }
 
-static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg,
+static void skl_ddb_entry_write(struct drm_i915_private *dev_priv,
+                               i915_reg_t reg,
                                const struct skl_ddb_entry *entry)
 {
        if (entry->end)
@@ -3361,7 +3341,7 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
        struct drm_device *dev = dev_priv->dev;
        struct intel_crtc *crtc;
 
-       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+       for_each_intel_crtc(dev, crtc) {
                int i, level, max_level = ilk_wm_max_level(dev);
                enum pipe pipe = crtc->pipe;
 
@@ -3533,28 +3513,25 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
 }
 
 static bool skl_update_pipe_wm(struct drm_crtc *crtc,
-                              struct skl_pipe_wm_parameters *params,
-                              struct intel_wm_config *config,
                               struct skl_ddb_allocation *ddb, /* out */
                               struct skl_pipe_wm *pipe_wm /* out */)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
 
-       skl_compute_wm_pipe_parameters(crtc, params);
-       skl_allocate_pipe_ddb(crtc, config, params, ddb);
-       skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
+       skl_allocate_pipe_ddb(cstate, ddb);
+       skl_compute_pipe_wm(cstate, ddb, pipe_wm);
 
-       if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
+       if (!memcmp(&intel_crtc->wm.active.skl, pipe_wm, sizeof(*pipe_wm)))
                return false;
 
-       intel_crtc->wm.skl_active = *pipe_wm;
+       intel_crtc->wm.active.skl = *pipe_wm;
 
        return true;
 }
 
 static void skl_update_other_pipe_wm(struct drm_device *dev,
                                     struct drm_crtc *crtc,
-                                    struct intel_wm_config *config,
                                     struct skl_wm_values *r)
 {
        struct intel_crtc *intel_crtc;
@@ -3573,9 +3550,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
         * Otherwise, because of this_crtc being freshly enabled/disabled, the
         * other active pipes need new DDB allocation and WM values.
         */
-       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
-                               base.head) {
-               struct skl_pipe_wm_parameters params = {};
+       for_each_intel_crtc(dev, intel_crtc) {
                struct skl_pipe_wm pipe_wm = {};
                bool wm_changed;
 
@@ -3586,7 +3561,6 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
                        continue;
 
                wm_changed = skl_update_pipe_wm(&intel_crtc->base,
-                                               &params, config,
                                                &r->ddb, &pipe_wm);
 
                /*
@@ -3596,7 +3570,7 @@ static void skl_update_other_pipe_wm(struct drm_device *dev,
                 */
                WARN_ON(!wm_changed);
 
-               skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
+               skl_compute_wm_results(dev, &pipe_wm, r, intel_crtc);
                r->dirty[intel_crtc->pipe] = true;
        }
 }
@@ -3626,10 +3600,9 @@ static void skl_update_wm(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct skl_pipe_wm_parameters params = {};
        struct skl_wm_values *results = &dev_priv->wm.skl_results;
-       struct skl_pipe_wm pipe_wm = {};
-       struct intel_wm_config config = {};
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+       struct skl_pipe_wm *pipe_wm = &cstate->wm.optimal.skl;
 
 
        /* Clear all dirty flags */
@@ -3637,16 +3610,13 @@ static void skl_update_wm(struct drm_crtc *crtc)
 
        skl_clear_wm(results, intel_crtc->pipe);
 
-       skl_compute_wm_global_parameters(dev, &config);
-
-       if (!skl_update_pipe_wm(crtc, &params, &config,
-                               &results->ddb, &pipe_wm))
+       if (!skl_update_pipe_wm(crtc, &results->ddb, pipe_wm))
                return;
 
-       skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
+       skl_compute_wm_results(dev, pipe_wm, results, intel_crtc);
        results->dirty[intel_crtc->pipe] = true;
 
-       skl_update_other_pipe_wm(dev, crtc, &config, results);
+       skl_update_other_pipe_wm(dev, crtc, results);
        skl_write_wm_values(dev_priv, results);
        skl_flush_wm_values(dev_priv, results);
 
@@ -3654,60 +3624,34 @@ static void skl_update_wm(struct drm_crtc *crtc)
        dev_priv->wm.skl_hw = *results;
 }
 
-static void
-skl_update_sprite_wm(struct drm_plane *plane, struct drm_crtc *crtc,
-                    uint32_t sprite_width, uint32_t sprite_height,
-                    int pixel_size, bool enabled, bool scaled)
+static void ilk_compute_wm_config(struct drm_device *dev,
+                                 struct intel_wm_config *config)
 {
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-       struct drm_framebuffer *fb = plane->state->fb;
-
-       intel_plane->wm.enabled = enabled;
-       intel_plane->wm.scaled = scaled;
-       intel_plane->wm.horiz_pixels = sprite_width;
-       intel_plane->wm.vert_pixels = sprite_height;
-       intel_plane->wm.tiling = DRM_FORMAT_MOD_NONE;
+       struct intel_crtc *crtc;
 
-       /* For planar: Bpp is for UV plane, y_Bpp is for Y plane */
-       intel_plane->wm.bytes_per_pixel =
-               (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
-               drm_format_plane_cpp(plane->state->fb->pixel_format, 1) : pixel_size;
-       intel_plane->wm.y_bytes_per_pixel =
-               (fb && fb->pixel_format == DRM_FORMAT_NV12) ?
-               drm_format_plane_cpp(plane->state->fb->pixel_format, 0) : 0;
+       /* Compute the currently _active_ config */
+       for_each_intel_crtc(dev, crtc) {
+               const struct intel_pipe_wm *wm = &crtc->wm.active.ilk;
 
-       /*
-        * Framebuffer can be NULL on plane disable, but it does not
-        * matter for watermarks if we assume no tiling in that case.
-        */
-       if (fb)
-               intel_plane->wm.tiling = fb->modifier[0];
-       intel_plane->wm.rotation = plane->state->rotation;
+               if (!wm->pipe_enabled)
+                       continue;
 
-       skl_update_wm(crtc);
+               config->sprites_enabled |= wm->sprites_enabled;
+               config->sprites_scaled |= wm->sprites_scaled;
+               config->num_pipes_active++;
+       }
 }
 
-static void ilk_update_wm(struct drm_crtc *crtc)
+static void ilk_program_watermarks(struct intel_crtc_state *cstate)
 {
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+       struct drm_crtc *crtc = cstate->base.crtc;
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
+       struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
        struct ilk_wm_maximums max;
+       struct intel_wm_config config = {};
        struct ilk_wm_values results = {};
        enum intel_ddb_partitioning partitioning;
-       struct intel_pipe_wm pipe_wm = {};
-       struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
-       struct intel_wm_config config = {};
-
-       WARN_ON(cstate->base.active != intel_crtc->active);
-
-       intel_compute_pipe_wm(cstate, &pipe_wm);
-
-       if (!memcmp(&intel_crtc->wm.active, &pipe_wm, sizeof(pipe_wm)))
-               return;
-
-       intel_crtc->wm.active = pipe_wm;
 
        ilk_compute_wm_config(dev, &config);
 
@@ -3733,14 +3677,12 @@ static void ilk_update_wm(struct drm_crtc *crtc)
        ilk_write_wm_values(dev_priv, &results);
 }
 
-static void
-ilk_update_sprite_wm(struct drm_plane *plane,
-                    struct drm_crtc *crtc,
-                    uint32_t sprite_width, uint32_t sprite_height,
-                    int pixel_size, bool enabled, bool scaled)
+static void ilk_update_wm(struct drm_crtc *crtc)
 {
-       struct drm_device *dev = plane->dev;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+
+       WARN_ON(cstate->base.active != intel_crtc->active);
 
        /*
         * IVB workaround: must disable low power watermarks for at least
@@ -3749,10 +3691,14 @@ ilk_update_sprite_wm(struct drm_plane *plane,
         *
         * WaCxSRDisabledForSpriteScaling:ivb
         */
-       if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
-               intel_wait_for_vblank(dev, intel_plane->pipe);
+       if (cstate->disable_lp_wm) {
+               ilk_disable_lp_wm(crtc->dev);
+               intel_wait_for_vblank(crtc->dev, intel_crtc->pipe);
+       }
+
+       intel_crtc->wm.active.ilk = cstate->wm.optimal.ilk;
 
-       ilk_update_wm(crtc);
+       ilk_program_watermarks(cstate);
 }
 
 static void skl_pipe_wm_active_state(uint32_t val,
@@ -3805,7 +3751,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct skl_wm_values *hw = &dev_priv->wm.skl_hw;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct skl_pipe_wm *active = &intel_crtc->wm.skl_active;
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+       struct skl_pipe_wm *active = &cstate->wm.optimal.skl;
        enum pipe pipe = intel_crtc->pipe;
        int level, i, max_level;
        uint32_t temp;
@@ -3849,6 +3796,8 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 
        temp = hw->plane_trans[pipe][PLANE_CURSOR];
        skl_pipe_wm_active_state(temp, active, true, true, i, 0);
+
+       intel_crtc->wm.active.skl = *active;
 }
 
 void skl_wm_get_hw_state(struct drm_device *dev)
@@ -3868,9 +3817,10 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct ilk_wm_values *hw = &dev_priv->wm.hw;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_pipe_wm *active = &intel_crtc->wm.active;
+       struct intel_crtc_state *cstate = to_intel_crtc_state(crtc->state);
+       struct intel_pipe_wm *active = &cstate->wm.optimal.ilk;
        enum pipe pipe = intel_crtc->pipe;
-       static const unsigned int wm0_pipe_reg[] = {
+       static const i915_reg_t wm0_pipe_reg[] = {
                [PIPE_A] = WM0_PIPEA_ILK,
                [PIPE_B] = WM0_PIPEB_ILK,
                [PIPE_C] = WM0_PIPEC_IVB,
@@ -3907,6 +3857,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
                for (level = 0; level <= max_level; level++)
                        active->wm[level].enable = true;
        }
+
+       intel_crtc->wm.active.ilk = *active;
 }
 
 #define _FW_WM(value, plane) \
@@ -4132,22 +4084,7 @@ void intel_update_watermarks(struct drm_crtc *crtc)
                dev_priv->display.update_wm(crtc);
 }
 
-void intel_update_sprite_watermarks(struct drm_plane *plane,
-                                   struct drm_crtc *crtc,
-                                   uint32_t sprite_width,
-                                   uint32_t sprite_height,
-                                   int pixel_size,
-                                   bool enabled, bool scaled)
-{
-       struct drm_i915_private *dev_priv = plane->dev->dev_private;
-
-       if (dev_priv->display.update_sprite_wm)
-               dev_priv->display.update_sprite_wm(plane, crtc,
-                                                  sprite_width, sprite_height,
-                                                  pixel_size, enabled, scaled);
-}
-
-/**
+/*
  * Lock protecting IPS related data structures
  */
 DEFINE_SPINLOCK(mchdev_lock);
@@ -4414,7 +4351,7 @@ static void gen6_set_rps(struct drm_device *dev, u8 val)
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
-       if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0))
+       if (IS_BXT_REVID(dev, 0, BXT_REVID_A1))
                return;
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
@@ -4515,7 +4452,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
 
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
-               if (IS_VALLEYVIEW(dev))
+               if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
                        vlv_set_rps_idle(dev_priv);
                else
                        gen6_set_rps(dev_priv->dev, dev_priv->rps.idle_freq);
@@ -4568,7 +4505,7 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv,
 
 void intel_set_rps(struct drm_device *dev, u8 val)
 {
-       if (IS_VALLEYVIEW(dev))
+       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev))
                valleyview_set_rps(dev, val);
        else
                gen6_set_rps(dev, val);
@@ -4612,7 +4549,7 @@ static void valleyview_disable_rps(struct drm_device *dev)
 
 static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
 {
-       if (IS_VALLEYVIEW(dev)) {
+       if (IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev)) {
                if (mode & (GEN7_RC_CTL_TO_MODE | GEN6_RC_CTL_EI_MODE(1)))
                        mode = GEN6_RC_CTL_RC6_ENABLE;
                else
@@ -4620,13 +4557,13 @@ static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
        }
        if (HAS_RC6p(dev))
                DRM_DEBUG_KMS("Enabling RC6 states: RC6 %s RC6p %s RC6pp %s\n",
-                             (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off",
-                             (mode & GEN6_RC_CTL_RC6p_ENABLE) ? "on" : "off",
-                             (mode & GEN6_RC_CTL_RC6pp_ENABLE) ? "on" : "off");
+                             onoff(mode & GEN6_RC_CTL_RC6_ENABLE),
+                             onoff(mode & GEN6_RC_CTL_RC6p_ENABLE),
+                             onoff(mode & GEN6_RC_CTL_RC6pp_ENABLE));
 
        else
                DRM_DEBUG_KMS("Enabling RC6 states: RC6 %s\n",
-                             (mode & GEN6_RC_CTL_RC6_ENABLE) ? "on" : "off");
+                             onoff(mode & GEN6_RC_CTL_RC6_ENABLE));
 }
 
 static int sanitize_rc6_option(const struct drm_device *dev, int enable_rc6)
@@ -4689,7 +4626,8 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
        dev_priv->rps.max_freq          = dev_priv->rps.rp0_freq;
 
        dev_priv->rps.efficient_freq = dev_priv->rps.rp1_freq;
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev) || IS_SKYLAKE(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev) ||
+           IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                ret = sandybridge_pcode_read(dev_priv,
                                        HSW_PCODE_DYNAMIC_DUTY_CYCLE_CONTROL,
                                        &ddcc_status);
@@ -4701,7 +4639,7 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
                                        dev_priv->rps.max_freq);
        }
 
-       if (IS_SKYLAKE(dev)) {
+       if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                /* Store the frequency values in 16.66 MHZ units, which is
                   the natural hardware unit for SKL */
                dev_priv->rps.rp0_freq *= GEN9_FREQ_SCALER;
@@ -4738,7 +4676,7 @@ static void gen9_enable_rps(struct drm_device *dev)
        gen6_init_rps_frequencies(dev);
 
        /* WaGsvDisableTurbo: Workaround to disable turbo on BXT A* */
-       if (IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) {
+       if (IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
                return;
        }
@@ -4803,11 +4741,10 @@ static void gen9_enable_rc6(struct drm_device *dev)
        /* 3a: Enable RC6 */
        if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
                rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
-       DRM_INFO("RC6 %s\n", (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
-                       "on" : "off");
+       DRM_INFO("RC6 %s\n", onoff(rc6_mask & GEN6_RC_CTL_RC6_ENABLE));
        /* WaRsUseTimeoutMode */
-       if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_D0) ||
-           (IS_BROXTON(dev) && INTEL_REVID(dev) <= BXT_REVID_A0)) {
+       if (IS_SKL_REVID(dev, 0, SKL_REVID_D0) ||
+           IS_BXT_REVID(dev, 0, BXT_REVID_A1)) {
                I915_WRITE(GEN6_RC6_THRESHOLD, 625); /* 800us */
                I915_WRITE(GEN6_RC_CONTROL, GEN6_RC_CTL_HW_ENABLE |
                           GEN7_RC_CTL_TO_MODE |
@@ -4823,8 +4760,7 @@ static void gen9_enable_rc6(struct drm_device *dev)
         * 3b: Enable Coarse Power Gating only when RC6 is enabled.
         * WaRsDisableCoarsePowerGating:skl,bxt - Render/Media PG need to be disabled with RC6.
         */
-       if ((IS_BROXTON(dev) && (INTEL_REVID(dev) < BXT_REVID_B0)) ||
-           ((IS_SKL_GT3(dev) || IS_SKL_GT4(dev)) && (INTEL_REVID(dev) <= SKL_REVID_F0)))
+       if (NEEDS_WaRsDisableCoarsePowerGating(dev))
                I915_WRITE(GEN9_PG_ENABLE, 0);
        else
                I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ?
@@ -5055,7 +4991,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev)
        /* convert DDR frequency from units of 266.6MHz to bandwidth */
        min_ring_freq = mult_frac(min_ring_freq, 8, 3);
 
-       if (IS_SKYLAKE(dev)) {
+       if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                /* Convert GT frequency to 50 HZ units */
                min_gpu_freq = dev_priv->rps.min_freq / GEN9_FREQ_SCALER;
                max_gpu_freq = dev_priv->rps.max_freq / GEN9_FREQ_SCALER;
@@ -5073,7 +5009,7 @@ static void __gen6_update_ring_freq(struct drm_device *dev)
                int diff = max_gpu_freq - gpu_freq;
                unsigned int ia_freq = 0, ring_freq = 0;
 
-               if (IS_SKYLAKE(dev)) {
+               if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev)) {
                        /*
                         * ring_freq = 2 * GT. ring_freq is in 100MHz units
                         * No floor required for ring frequency on SKL.
@@ -5208,7 +5144,17 @@ static int valleyview_rps_rpe_freq(struct drm_i915_private *dev_priv)
 
 static int valleyview_rps_min_freq(struct drm_i915_private *dev_priv)
 {
-       return vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
+       u32 val;
+
+       val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM) & 0xff;
+       /*
+        * According to the BYT Punit GPU turbo HAS 1.1.6.3 the minimum value
+        * for the minimum frequency in GPLL mode is 0xc1. Contrary to this on
+        * a BYT-M B0 the above register contains 0xbf. Moreover when setting
+        * a frequency Punit will not allow values below 0xc0. Clamp it 0xc0
+        * to make sure it matches what Punit accepts.
+        */
+       return max_t(u32, val, 0xc0);
 }
 
 /* Check that the pctx buffer wasn't move under us. */
@@ -6113,7 +6059,17 @@ static void intel_init_emon(struct drm_device *dev)
 
 void intel_init_gt_powersave(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        i915.enable_rc6 = sanitize_rc6_option(dev, i915.enable_rc6);
+       /*
+        * RPM depends on RC6 to save restore the GT HW context, so make RC6 a
+        * requirement.
+        */
+       if (!i915.enable_rc6) {
+               DRM_INFO("RC6 disabled, disabling runtime PM support\n");
+               intel_runtime_pm_get(dev_priv);
+       }
 
        if (IS_CHERRYVIEW(dev))
                cherryview_init_gt_powersave(dev);
@@ -6123,10 +6079,15 @@ void intel_init_gt_powersave(struct drm_device *dev)
 
 void intel_cleanup_gt_powersave(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
        if (IS_CHERRYVIEW(dev))
                return;
        else if (IS_VALLEYVIEW(dev))
                valleyview_cleanup_gt_powersave(dev);
+
+       if (!i915.enable_rc6)
+               intel_runtime_pm_put(dev_priv);
 }
 
 static void gen6_suspend_rps(struct drm_device *dev)
@@ -6201,7 +6162,7 @@ static void intel_gen6_powersave_work(struct work_struct *work)
        } else if (INTEL_INFO(dev)->gen >= 9) {
                gen9_enable_rc6(dev);
                gen9_enable_rps(dev);
-               if (IS_SKYLAKE(dev))
+               if (IS_SKYLAKE(dev) || IS_KABYLAKE(dev))
                        __gen6_update_ring_freq(dev);
        } else if (IS_BROADWELL(dev)) {
                gen8_enable_rps(dev);
@@ -7057,7 +7018,6 @@ void intel_init_pm(struct drm_device *dev)
                        dev_priv->display.init_clock_gating =
                                bxt_init_clock_gating;
                dev_priv->display.update_wm = skl_update_wm;
-               dev_priv->display.update_sprite_wm = skl_update_sprite_wm;
        } else if (HAS_PCH_SPLIT(dev)) {
                ilk_setup_wm_latency(dev);
 
@@ -7066,7 +7026,8 @@ void intel_init_pm(struct drm_device *dev)
                    (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
                     dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
                        dev_priv->display.update_wm = ilk_update_wm;
-                       dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
+                       dev_priv->display.compute_pipe_wm = ilk_compute_pipe_wm;
+                       dev_priv->display.program_watermarks = ilk_program_watermarks;
                } else {
                        DRM_DEBUG_KMS("Failed to read display plane latency. "
                                      "Disable CxSR\n");
@@ -7331,4 +7292,6 @@ void intel_pm_setup(struct drm_device *dev)
        INIT_LIST_HEAD(&dev_priv->rps.mmioflips.link);
 
        dev_priv->pm.suspended = false;
+       atomic_set(&dev_priv->pm.wakeref_count, 0);
+       atomic_set(&dev_priv->pm.atomic_seq, 0);
 }