drm/i915/skl: Correctly align skl_compute_plane_wm() arguments
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_pm.c
index 09a81b3a754dc70abb0554e87c81f1e210157814..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);
 
@@ -3014,7 +3040,7 @@ skl_ddb_get_pipe_allocation_limits(struct drm_device *dev,
 
        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 - 1;
+       alloc->end = alloc->start + pipe_size;
 }
 
 static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
@@ -3025,6 +3051,34 @@ static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
        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)
 {
@@ -3079,7 +3133,7 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
        }
 
        cursor_blocks = skl_cursor_allocation(config);
-       ddb->cursor[pipe].start = alloc.end - cursor_blocks + 1;
+       ddb->cursor[pipe].start = alloc.end - cursor_blocks;
        ddb->cursor[pipe].end = alloc.end;
 
        alloc_size -= cursor_blocks;
@@ -3113,7 +3167,7 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
                                       total_data_rate);
 
                ddb->plane[pipe][plane].start = start;
-               ddb->plane[pipe][plane].end = start + plane_blocks - 1;
+               ddb->plane[pipe][plane].end = start + plane_blocks;
 
                start += plane_blocks;
        }
@@ -3163,28 +3217,6 @@ static uint32_t skl_wm_method2(uint32_t pixel_rate, uint32_t pipe_htotal,
        return ret;
 }
 
-static void skl_compute_transition_wm(struct drm_crtc *crtc,
-                                 struct skl_pipe_wm_parameters *params,
-                                 struct skl_pipe_wm *pipe_wm)
-{
-       /*
-        * For now it is suggested to use the LP0 wm val of corresponding
-        * plane as transition wm val. This is done while computing results.
-        */
-       if (!params->active)
-               return;
-}
-
-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 bool skl_ddb_allocation_changed(const struct skl_ddb_allocation *new_ddb,
                                       const struct intel_crtc *intel_crtc)
 {
@@ -3260,16 +3292,16 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
 }
 
 static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p,
-                                  struct intel_plane_wm_parameters *p_params,
-                                  uint16_t max_page_buff_alloc,
-                                  uint32_t mem_value,
-                                  uint16_t *res_blocks, /* out */
-                                  uint8_t *res_lines /* out */)
+                                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;
+       uint32_t method1, method2, plane_bytes_per_line, res_blocks, res_lines;
        uint32_t result_bytes;
 
-       if (!p->active || !p_params->enabled)
+       if (mem_value == 0 || !p->active || !p_params->enabled)
                return false;
 
        method1 = skl_wm_method1(p->pixel_rate,
@@ -3285,13 +3317,19 @@ static bool skl_compute_plane_wm(struct skl_pipe_wm_parameters *p,
                                        p_params->bytes_per_pixel;
 
        /* For now xtile and linear */
-       if (((max_page_buff_alloc * 512) / plane_bytes_per_line) >= 1)
+       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);
+       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;
 }
@@ -3324,6 +3362,32 @@ static void skl_compute_wm_level(const struct drm_i915_private *dev_priv,
                                                 &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,
@@ -3341,7 +3405,7 @@ static void skl_compute_pipe_wm(struct drm_crtc *crtc,
        }
        pipe_wm->linetime = skl_compute_linetime_wm(crtc, params);
 
-       skl_compute_transition_wm(crtc, params, pipe_wm);
+       skl_compute_transition_wm(crtc, params, &pipe_wm->trans_wm);
 }
 
 static void skl_compute_wm_results(struct drm_device *dev,
@@ -3352,19 +3416,12 @@ static void skl_compute_wm_results(struct drm_device *dev,
 {
        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++) {
-               uint16_t ddb_blocks;
-               uint32_t temp;
-               int i;
-
                for (i = 0; i < intel_num_planes(intel_crtc); i++) {
                        temp = 0;
-                       ddb_blocks = skl_ddb_entry_size(&r->ddb.plane[pipe][i]);
-
-                       if ((p_wm->wm[level].plane_res_b[i] > ddb_blocks) ||
-                               (p_wm->wm[level].plane_res_l[i] > 31))
-                               p_wm->wm[level].plane_en[i] = false;
 
                        temp |= p_wm->wm[level].plane_res_l[i] <<
                                        PLANE_WM_LINES_SHIFT;
@@ -3373,17 +3430,9 @@ static void skl_compute_wm_results(struct drm_device *dev,
                                temp |= PLANE_WM_EN;
 
                        r->plane[pipe][i][level] = temp;
-                       /* Use the LP0 WM value for transition WM for now. */
-                       if (level == 0)
-                               r->plane_trans[pipe][i] = temp;
                }
 
                temp = 0;
-               ddb_blocks = skl_ddb_entry_size(&r->ddb.cursor[pipe]);
-
-               if ((p_wm->wm[level].cursor_res_b > ddb_blocks) ||
-                       (p_wm->wm[level].cursor_res_l > 31))
-                       p_wm->wm[level].cursor_en = false;
 
                temp |= p_wm->wm[level].cursor_res_l << PLANE_WM_LINES_SHIFT;
                temp |= p_wm->wm[level].cursor_res_b;
@@ -3392,15 +3441,40 @@ static void skl_compute_wm_results(struct drm_device *dev,
                        temp |= PLANE_WM_EN;
 
                r->cursor[pipe][level] = temp;
-               /* Use the LP0 WM value for transition WM for now. */
-               if (level == 0)
-                       r->cursor_trans[pipe] = 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)
 {
@@ -3428,17 +3502,14 @@ static void skl_write_wm_values(struct drm_i915_private *dev_priv,
                        I915_WRITE(CUR_WM_TRANS(pipe), new->cursor_trans[pipe]);
 
                        for (i = 0; i < intel_num_planes(crtc); i++)
-                               I915_WRITE(PLANE_BUF_CFG(pipe, i),
-                                          new->ddb.plane[pipe][i].end << 16 |
-                                          new->ddb.plane[pipe][i].start);
+                               skl_ddb_entry_write(dev_priv,
+                                                   PLANE_BUF_CFG(pipe, i),
+                                                   &new->ddb.plane[pipe][i]);
 
-                       I915_WRITE(CUR_BUF_CFG(pipe),
-                                  new->ddb.cursor[pipe].end << 16 |
-                                  new->ddb.cursor[pipe].start);
+                       skl_ddb_entry_write(dev_priv, CUR_BUF_CFG(pipe),
+                                           &new->ddb.cursor[pipe]);
                }
        }
-
-       dev_priv->wm.skl_hw = *new;
 }
 
 static bool skl_update_pipe_wm(struct drm_crtc *crtc,
@@ -3532,6 +3603,9 @@ static void skl_update_wm(struct drm_crtc *crtc)
 
        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
@@ -3722,8 +3796,11 @@ static void skl_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 
 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);
 }
This page took 0.051843 seconds and 5 git commands to generate.