drm/i915/skl: Allocate DDB portions for display planes
authorDamien Lespiau <damien.lespiau@intel.com>
Tue, 4 Nov 2014 17:06:43 +0000 (17:06 +0000)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Fri, 7 Nov 2014 17:42:05 +0000 (18:42 +0100)
v2: Fix the 3rd plane/cursor logic (Pradeep Bhat)
v3: Fix one-by-one error in the DDB allocation code
v4: Rebase on top of the skl_pipe_pixel_rate() argument change
v5: Replace the available/start/end output parameters of
    skl_ddb_get_pipe_allocation_limits() by a single ddb entry constify
    a few arguments
    Make nth_active_pipe 0 indexed
    Use sizeof(variable) instead of sizeof(type)
    (Ville)
v6: Use the for_each_crtc() macro instead of list_for_each_entry()

Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/intel_pm.c

index 5500c53..b5c7c4b 100644 (file)
@@ -2973,6 +2973,153 @@ 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 - 1;
+}
+
+static unsigned int skl_cursor_allocation(const struct intel_wm_config *config)
+{
+       if (config->num_pipes_active == 1)
+               return 32;
+
+       return 8;
+}
+
+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 + 1;
+       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 - 1;
+
+               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 */
@@ -3294,6 +3441,7 @@ static bool skl_update_pipe_wm(struct drm_crtc *crtc,
        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)))