drm/i915/skl: Correctly align skl_compute_plane_wm() arguments
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_pm.c
index ca2080bf486f923c81060fa5ebbebfa4c2d79522..176e9ef9b2668ec2813f57d0e305a331e6968b2b 100644 (file)
@@ -2285,7 +2285,8 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
 
        if (IS_GEN9(dev)) {
                uint32_t val;
-               int ret;
+               int ret, i;
+               int level, max_level = ilk_wm_max_level(dev);
 
                /* read the first set of memory latencies[0:3] */
                val = 0; /* data0 to be programmed to 0 for first set */
@@ -2328,6 +2329,31 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[8])
                wm[7] = (val >> GEN9_MEM_LATENCY_LEVEL_3_7_SHIFT) &
                                GEN9_MEM_LATENCY_LEVEL_MASK;
 
+               /*
+                * punit doesn't take into account the read latency so we need
+                * to add 2us to the various latency levels we retrieve from
+                * the punit.
+                *   - W0 is a bit special in that it's the only level that
+                *   can't be disabled if we want to have display working, so
+                *   we always add 2us there.
+                *   - For levels >=1, punit returns 0us latency when they are
+                *   disabled, so we respect that and don't add 2us then
+                *
+                * Additionally, if a level n (n > 1) has a 0us latency, all
+                * levels m (m >= n) need to be disabled. We make sure to
+                * sanitize the values out of the punit to satisfy this
+                * requirement.
+                */
+               wm[0] += 2;
+               for (level = 1; level <= max_level; level++)
+                       if (wm[level] != 0)
+                               wm[level] += 2;
+                       else {
+                               for (i = level + 1; i <= max_level; i++)
+                                       wm[i] = 0;
+
+                               break;
+                       }
        } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
@@ -2973,6 +2999,631 @@ static bool ilk_disable_lp_wm(struct drm_device *dev)
        return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
 }
 
+/*
+ * On gen9, we need to allocate Display Data Buffer (DDB) portions to the
+ * different active planes.
+ */
+
+#define SKL_DDB_SIZE           896     /* in blocks */
+
+static void
+skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
+                                  struct drm_crtc *for_crtc,
+                                  const struct intel_wm_config *config,
+                                  const struct skl_pipe_wm_parameters *params,
+                                  struct skl_ddb_entry *alloc /* out */)
+{
+       struct drm_crtc *crtc;
+       unsigned int pipe_size, ddb_size;
+       int nth_active_pipe;
+
+       if (!params->active) {
+               alloc->start = 0;
+               alloc->end = 0;
+               return;
+       }
+
+       ddb_size = SKL_DDB_SIZE;
+
+       ddb_size -= 4; /* 4 blocks for bypass path allocation */
+
+       nth_active_pipe = 0;
+       for_each_crtc(dev, crtc) {
+               if (!intel_crtc_active(crtc))
+                       continue;
+
+               if (crtc == for_crtc)
+                       break;
+
+               nth_active_pipe++;
+       }
+
+       pipe_size = ddb_size / config->num_pipes_active;
+       alloc->start = nth_active_pipe * ddb_size / config->num_pipes_active;
+       alloc->end = alloc->start + pipe_size;
+}
+
+static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
+{
+       if (config->num_pipes_active == 1)
+               return 32;
+
+       return 8;
+}
+
+static void skl_ddb_entry_init_from_hw(struct skl_ddb_entry *entry, u32 reg)
+{
+       entry->start = reg & 0x3ff;
+       entry->end = (reg >> 16) & 0x3ff;
+       if (entry->end)
+               entry->end += 1;
+}
+
+void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
+                         struct skl_ddb_allocation *ddb /* out */)
+{
+       struct drm_device *dev = dev_priv->dev;
+       enum pipe pipe;
+       int plane;
+       u32 val;
+
+       for_each_pipe(dev_priv, pipe) {
+               for_each_plane(pipe, plane) {
+                       val = I915_READ(PLANE_BUF_CFG(pipe, plane));
+                       skl_ddb_entry_init_from_hw(&ddb->plane[pipe][plane],
+                                                  val);
+               }
+
+               val = I915_READ(CUR_BUF_CFG(pipe));
+               skl_ddb_entry_init_from_hw(&ddb->cursor[pipe], val);
+       }
+}
+
+static unsigned int
+skl_plane_relative_data_rate(const struct intel_plane_wm_parameters *p)
+{
+       return p->horiz_pixels * p->vert_pixels * p->bytes_per_pixel;
+}
+
+/*
+ * We don't overflow 32 bits. Worst case is 3 planes enabled, each fetching
+ * a 8192x4096@32bpp framebuffer:
+ *   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)
+{
+       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;
+
+               p = &params->plane[plane];
+               if (!p->enabled)
+                       continue;
+
+               total_data_rate += skl_plane_relative_data_rate(p);
+       }
+
+       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,
+                     struct skl_ddb_allocation *ddb /* out */)
+{
+       struct drm_device *dev = crtc->dev;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       enum pipe pipe = intel_crtc->pipe;
+       struct skl_ddb_entry alloc;
+       uint16_t alloc_size, start, cursor_blocks;
+       unsigned int total_data_rate;
+       int plane;
+
+       skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params, &alloc);
+       alloc_size = skl_ddb_entry_size(&alloc);
+       if (alloc_size == 0) {
+               memset(ddb->plane[pipe], 0, sizeof(ddb->plane[pipe]));
+               memset(&ddb->cursor[pipe], 0, sizeof(ddb->cursor[pipe]));
+               return;
+       }
+
+       cursor_blocks = skl_cursor_allocation(config);
+       ddb->cursor[pipe].start = alloc.end - cursor_blocks;
+       ddb->cursor[pipe].end = alloc.end;
+
+       alloc_size -= cursor_blocks;
+       alloc.end -= cursor_blocks;
+
+       /*
+        * Each active plane get a portion of the remaining space, in
+        * proportion to the amount of data they need to fetch from memory.
+        *
+        * FIXME: we may not allocate every single block here.
+        */
+       total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
+
+       start = alloc.start;
+       for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
+               const struct intel_plane_wm_parameters *p;
+               unsigned int data_rate;
+               uint16_t plane_blocks;
+
+               p = &params->plane[plane];
+               if (!p->enabled)
+                       continue;
+
+               data_rate = skl_plane_relative_data_rate(p);
+
+               /*
+                * promote the expression to 64 bits to avoid overflowing, the
+                * result is < available as data_rate / total_data_rate < 1
+                */
+               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;
+
+               start += plane_blocks;
+       }
+
+}
+
+static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config)
+{
+       /* TODO: Take into account the scalers once we support them */
+       return config->adjusted_mode.crtc_clock;
+}
+
+/*
+ * The max latency should be 257 (max the punit can code is 255 and we add 2us
+ * for the read latency) and bytes_per_pixel should always be <= 8, so that
+ * should allow pixel_rate up to ~2 GHz which seems sufficient since max
+ * 2xcdclk is 1350 MHz and the pixel rate should never exceed that.
+*/
+static uint32_t skl_wm_method1(uint32_t pixel_rate, uint8_t bytes_per_pixel,
+                              uint32_t latency)
+{
+       uint32_t wm_intermediate_val, ret;
+
+       if (latency == 0)
+               return UINT_MAX;
+
+       wm_intermediate_val = latency * pixel_rate * bytes_per_pixel;
+       ret = DIV_ROUND_UP(wm_intermediate_val, 1000);
+
+       return ret;
+}
+
+static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
+                              uint32_t horiz_pixels, uint8_t bytes_per_pixel,
+                              uint32_t latency)
+{
+       uint32_t ret, plane_bytes_per_line, wm_intermediate_val;
+
+       if (latency == 0)
+               return UINT_MAX;
+
+       plane_bytes_per_line = horiz_pixels * bytes_per_pixel;
+       wm_intermediate_val = latency * pixel_rate;
+       ret = DIV_ROUND_UP(wm_intermediate_val, pipe_htotal * 1000) *
+                               plane_bytes_per_line;
+
+       return ret;
+}
+
+static bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
+                                      const struct intel_crtc *intel_crtc)
+{
+       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->cursor[pipe], &cur_ddb->cursor[pipe],
+                   sizeof(new_ddb->cursor[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 += intel_crtc_active(crtc);
+
+       /* 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;
+       int i = 1; /* Index for sprite planes start */
+
+       p->active = intel_crtc_active(crtc);
+       if (p->active) {
+               p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
+               p->pixel_rate = skl_pipe_pixel_rate(&intel_crtc->config);
+
+               /*
+                * For now, assume primary and cursor planes are always enabled.
+                */
+               p->plane[0].enabled = true;
+               p->plane[0].bytes_per_pixel =
+                       crtc->primary->fb->bits_per_pixel / 8;
+               p->plane[0].horiz_pixels = intel_crtc->config.pipe_src_w;
+               p->plane[0].vert_pixels = intel_crtc->config.pipe_src_h;
+
+               p->cursor.enabled = true;
+               p->cursor.bytes_per_pixel = 4;
+               p->cursor.horiz_pixels = intel_crtc->cursor_width ?
+                                        intel_crtc->cursor_width : 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)
+                       p->plane[i++] = intel_plane->wm;
+       }
+}
+
+static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p,
+                                struct intel_plane_wm_parameters *p_params,
+                                uint16_t ddb_allocation,
+                                uint32_t mem_value,
+                                uint16_t *out_blocks, /* out */
+                                uint8_t *out_lines /* out */)
+{
+       uint32_t method1, method2, plane_bytes_per_line, res_blocks, res_lines;
+       uint32_t result_bytes;
+
+       if (mem_value == 0 || !p->active || !p_params->enabled)
+               return false;
+
+       method1 = skl_wm_method1(p->pixel_rate,
+                                p_params->bytes_per_pixel,
+                                mem_value);
+       method2 = skl_wm_method2(p->pixel_rate,
+                                p->pipe_htotal,
+                                p_params->horiz_pixels,
+                                p_params->bytes_per_pixel,
+                                mem_value);
+
+       plane_bytes_per_line = p_params->horiz_pixels *
+                                       p_params->bytes_per_pixel;
+
+       /* For now xtile and linear */
+       if (((ddb_allocation * 512) / plane_bytes_per_line) >= 1)
+               result_bytes = min(method1, method2);
+       else
+               result_bytes = method1;
+
+       res_blocks = DIV_ROUND_UP(result_bytes, 512) + 1;
+       res_lines = DIV_ROUND_UP(result_bytes, plane_bytes_per_line);
+
+       if (res_blocks > ddb_allocation || res_lines > 31)
+               return false;
+
+       *out_blocks = res_blocks;
+       *out_lines = res_lines;
+
+       return true;
+}
+
+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,
+                                int level,
+                                int num_planes,
+                                struct skl_wm_level *result)
+{
+       uint16_t latency = dev_priv->wm.skl_latency[level];
+       uint16_t ddb_blocks;
+       int i;
+
+       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(p, &p->plane[i],
+                                               ddb_blocks,
+                                               latency,
+                                               &result->plane_res_b[i],
+                                               &result->plane_res_l[i]);
+       }
+
+       ddb_blocks = skl_ddb_entry_size(&ddb->cursor[pipe]);
+       result->cursor_en = skl_compute_plane_wm(p, &p->cursor, ddb_blocks,
+                                                latency, &result->cursor_res_b,
+                                                &result->cursor_res_l);
+}
+
+static uint32_t
+skl_compute_linetime_wm(struct drm_crtc *crtc, struct skl_pipe_wm_parameters *p)
+{
+       if (!intel_crtc_active(crtc))
+               return 0;
+
+       return DIV_ROUND_UP(8 * p->pipe_htotal * 1000, p->pixel_rate);
+
+}
+
+static void skl_compute_transition_wm(struct drm_crtc *crtc,
+                                     struct skl_pipe_wm_parameters *params,
+                                     struct skl_wm_level *trans_wm /* out */)
+{
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       int i;
+
+       if (!params->active)
+               return;
+
+       /* Until we know more, just disable transition WMs */
+       for (i = 0; i < intel_num_planes(intel_crtc); i++)
+               trans_wm->plane_en[i] = false;
+       trans_wm->cursor_en = false;
+}
+
+static void skl_compute_pipe_wm(struct drm_crtc *crtc,
+                               struct skl_ddb_allocation *ddb,
+                               struct skl_pipe_wm_parameters *params,
+                               struct skl_pipe_wm *pipe_wm)
+{
+       struct drm_device *dev = 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]);
+       }
+       pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
+
+       skl_compute_transition_wm(crtc, params, &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)
+{
+       int level, max_level = ilk_wm_max_level(dev);
+       enum pipe pipe = intel_crtc->pipe;
+       uint32_t temp;
+       int i;
+
+       for (level = 0; level <= max_level; level++) {
+               for (i = 0; i < intel_num_planes(intel_crtc); i++) {
+                       temp = 0;
+
+                       temp |= p_wm->wm[level].plane_res_l[i] <<
+                                       PLANE_WM_LINES_SHIFT;
+                       temp |= p_wm->wm[level].plane_res_b[i];
+                       if (p_wm->wm[level].plane_en[i])
+                               temp |= PLANE_WM_EN;
+
+                       r->plane[pipe][i][level] = temp;
+               }
+
+               temp = 0;
+
+               temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT;
+               temp |= p_wm->wm[level].cursor_res_b;
+
+               if (p_wm->wm[level].cursor_en)
+                       temp |= PLANE_WM_EN;
+
+               r->cursor[pipe][level] = temp;
+
+       }
+
+       /* transition WMs */
+       for (i = 0; i < intel_num_planes(intel_crtc); i++) {
+               temp = 0;
+               temp |= p_wm->trans_wm.plane_res_l[i] << PLANE_WM_LINES_SHIFT;
+               temp |= p_wm->trans_wm.plane_res_b[i];
+               if (p_wm->trans_wm.plane_en[i])
+                       temp |= PLANE_WM_EN;
+
+               r->plane_trans[pipe][i] = temp;
+       }
+
+       temp = 0;
+       temp |= p_wm->trans_wm.cursor_res_l << PLANE_WM_LINES_SHIFT;
+       temp |= p_wm->trans_wm.cursor_res_b;
+       if (p_wm->trans_wm.cursor_en)
+               temp |= PLANE_WM_EN;
+
+       r->cursor_trans[pipe] = temp;
+
+       r->wm_linetime[pipe] = p_wm->linetime;
+}
+
+static void skl_ddb_entry_write(struct drm_i915_private *dev_priv, uint32_t reg,
+                               const struct skl_ddb_entry *entry)
+{
+       if (entry->end)
+               I915_WRITE(reg, (entry->end - 1) << 16 | entry->start);
+       else
+               I915_WRITE(reg, 0);
+}
+
+static void skl_write_wm_values(struct drm_i915_private *dev_priv,
+                               const struct skl_wm_values *new)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               int i, level, max_level = ilk_wm_max_level(dev);
+               enum pipe pipe = crtc->pipe;
+
+               if (new->dirty[pipe]) {
+                       I915_WRITE(PIPE_WM_LINETIME(pipe),
+                                       new->wm_linetime[pipe]);
+
+                       for (level = 0; level <= max_level; level++) {
+                               for (i = 0; i < intel_num_planes(crtc); i++)
+                                       I915_WRITE(PLANE_WM(pipe, i, level),
+                                               new->plane[pipe][i][level]);
+                               I915_WRITE(CUR_WM(pipe, level),
+                                       new->cursor[pipe][level]);
+                       }
+                       for (i = 0; i < intel_num_planes(crtc); i++)
+                               I915_WRITE(PLANE_WM_TRANS(pipe, i),
+                                               new->plane_trans[pipe][i]);
+                       I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]);
+
+                       for (i = 0; i < intel_num_planes(crtc); i++)
+                               skl_ddb_entry_write(dev_priv,
+                                                   PLANE_BUF_CFG(pipe, i),
+                                                   &new->ddb.plane[pipe][i]);
+
+                       skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
+                                           &new->ddb.cursor[pipe]);
+               }
+       }
+}
+
+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);
+
+       skl_compute_wm_pipe_parameters(crtc, params);
+       skl_allocate_pipe_ddb(crtc, config, params, ddb);
+       skl_compute_pipe_wm(crtc, ddb, params, pipe_wm);
+
+       if (!memcmp(&intel_crtc->wm.skl_active, pipe_wm, sizeof(*pipe_wm)))
+               return false;
+
+       intel_crtc->wm.skl_active = *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;
+       struct intel_crtc *this_crtc = to_intel_crtc(crtc);
+
+       /*
+        * If the WM update hasn't changed the allocation for this_crtc (the
+        * crtc we are currently computing the new WM values for), other
+        * enabled crtcs will keep the same allocation and we don't need to
+        * recompute anything for them.
+        */
+       if (!skl_ddb_allocation_changed(&r->ddb, this_crtc))
+               return;
+
+       /*
+        * 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 = {};
+               struct skl_pipe_wm pipe_wm = {};
+               bool wm_changed;
+
+               if (this_crtc->pipe == intel_crtc->pipe)
+                       continue;
+
+               if (!intel_crtc->active)
+                       continue;
+
+               wm_changed = skl_update_pipe_wm(&intel_crtc->base,
+                                               &params, config,
+                                               &r->ddb, &pipe_wm);
+
+               /*
+                * If we end up re-computing the other pipe WM values, it's
+                * because it was really needed, so we expect the WM values to
+                * be different.
+                */
+               WARN_ON(!wm_changed);
+
+               skl_compute_wm_results(dev, &params, &pipe_wm, r, intel_crtc);
+               r->dirty[intel_crtc->pipe] = true;
+       }
+}
+
+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 = {};
+
+       memset(results, 0, sizeof(*results));
+
+       skl_compute_wm_global_parameters(dev, &config);
+
+       if (!skl_update_pipe_wm(crtc, &params, &config,
+                               &results->ddb, &pipe_wm))
+               return;
+
+       skl_compute_wm_results(dev, &params, &pipe_wm, results, intel_crtc);
+       results->dirty[intel_crtc->pipe] = true;
+
+       skl_update_other_pipe_wm(dev, crtc, &config, results);
+       skl_write_wm_values(dev_priv, results);
+
+       /* store the new configuration */
+       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)
+{
+       struct intel_plane *intel_plane = to_intel_plane(plane);
+
+       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.bytes_per_pixel = pixel_size;
+
+       skl_update_wm(crtc);
+}
+
 static void ilk_update_wm(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -3047,6 +3698,113 @@ ilk_update_sprite_wm(struct drm_plane *plane,
        ilk_update_wm(crtc);
 }
 
+static void skl_pipe_wm_active_state(uint32_t val,
+                                    struct skl_pipe_wm *active,
+                                    bool is_transwm,
+                                    bool is_cursor,
+                                    int i,
+                                    int level)
+{
+       bool is_enabled = (val & PLANE_WM_EN) != 0;
+
+       if (!is_transwm) {
+               if (!is_cursor) {
+                       active->wm[level].plane_en[i] = is_enabled;
+                       active->wm[level].plane_res_b[i] =
+                                       val & PLANE_WM_BLOCKS_MASK;
+                       active->wm[level].plane_res_l[i] =
+                                       (val >> PLANE_WM_LINES_SHIFT) &
+                                               PLANE_WM_LINES_MASK;
+               } else {
+                       active->wm[level].cursor_en = is_enabled;
+                       active->wm[level].cursor_res_b =
+                                       val & PLANE_WM_BLOCKS_MASK;
+                       active->wm[level].cursor_res_l =
+                                       (val >> PLANE_WM_LINES_SHIFT) &
+                                               PLANE_WM_LINES_MASK;
+               }
+       } else {
+               if (!is_cursor) {
+                       active->trans_wm.plane_en[i] = is_enabled;
+                       active->trans_wm.plane_res_b[i] =
+                                       val & PLANE_WM_BLOCKS_MASK;
+                       active->trans_wm.plane_res_l[i] =
+                                       (val >> PLANE_WM_LINES_SHIFT) &
+                                               PLANE_WM_LINES_MASK;
+               } else {
+                       active->trans_wm.cursor_en = is_enabled;
+                       active->trans_wm.cursor_res_b =
+                                       val & PLANE_WM_BLOCKS_MASK;
+                       active->trans_wm.cursor_res_l =
+                                       (val >> PLANE_WM_LINES_SHIFT) &
+                                               PLANE_WM_LINES_MASK;
+               }
+       }
+}
+
+static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
+{
+       struct drm_device *dev = crtc->dev;
+       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;
+       enum pipe pipe = intel_crtc->pipe;
+       int level, i, max_level;
+       uint32_t temp;
+
+       max_level = ilk_wm_max_level(dev);
+
+       hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
+
+       for (level = 0; level <= max_level; level++) {
+               for (i = 0; i < intel_num_planes(intel_crtc); i++)
+                       hw->plane[pipe][i][level] =
+                                       I915_READ(PLANE_WM(pipe, i, level));
+               hw->cursor[pipe][level] = I915_READ(CUR_WM(pipe, level));
+       }
+
+       for (i = 0; i < intel_num_planes(intel_crtc); i++)
+               hw->plane_trans[pipe][i] = I915_READ(PLANE_WM_TRANS(pipe, i));
+       hw->cursor_trans[pipe] = I915_READ(CUR_WM_TRANS(pipe));
+
+       if (!intel_crtc_active(crtc))
+               return;
+
+       hw->dirty[pipe] = true;
+
+       active->linetime = hw->wm_linetime[pipe];
+
+       for (level = 0; level <= max_level; level++) {
+               for (i = 0; i < intel_num_planes(intel_crtc); i++) {
+                       temp = hw->plane[pipe][i][level];
+                       skl_pipe_wm_active_state(temp, active, false,
+                                               false, i, level);
+               }
+               temp = hw->cursor[pipe][level];
+               skl_pipe_wm_active_state(temp, active, false, true, i, level);
+       }
+
+       for (i = 0; i < intel_num_planes(intel_crtc); i++) {
+               temp = hw->plane_trans[pipe][i];
+               skl_pipe_wm_active_state(temp, active, true, false, i, 0);
+       }
+
+       temp = hw->cursor_trans[pipe];
+       skl_pipe_wm_active_state(temp, active, true, true, i, 0);
+}
+
+void skl_wm_get_hw_state(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct skl_ddb_allocation *ddb = &dev_priv->wm.skl_hw.ddb;
+       struct drm_crtc *crtc;
+
+       skl_ddb_get_hw_state(dev_priv, ddb);
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+               skl_pipe_wm_get_hw_state(crtc);
+}
+
 static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -6198,6 +6956,8 @@ void intel_init_pm(struct drm_device *dev)
                skl_setup_wm_latency(dev);
 
                dev_priv->display.init_clock_gating = gen9_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);
 
This page took 0.035245 seconds and 5 git commands to generate.