[PATCH 48/89] drm/i915/skl: Allocate DDB portions for display planes

Damien Lespiau
2014-09-04T11:28:42Z

v2: Fix the 3rd plane/cursor logic (Pradeep Bhat)
v3: Fix one-by-one error in the DDB allocation code

Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
---
drivers/gpu/drm/i915/intel_pm.c | 150 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 150 insertions(+)

diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index 4ee90b6..0ddcbad 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -2937,6 +2937,155 @@ 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,
+ struct intel_wm_config *config,
+ struct skl_pipe_wm_parameters *params,
+ uint16_t *available,
+ uint16_t *start,
+ uint16_t *end)
+{
+ struct drm_crtc *crtc;
+ unsigned int ddb_size;
+ int nth_active_pipe;
+
+ if (!params->active) {
+ *available = 0;
+ *start = 0;
+ *end = 0;
+ return;
+ }
+
+ ddb_size = SKL_DDB_SIZE;
+
+ ddb_size -= 4; /* 4 blocks for bypass path allocation */
+
+ nth_active_pipe = 1;
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+ if (!intel_crtc_active(crtc))
+ continue;
+
+ if (crtc == for_crtc)
+ break;
+
+ nth_active_pipe++;
+ }
+
+ *available = ddb_size / config->num_pipes_active;
+ *start = (nth_active_pipe - 1) * ddb_size / config->num_pipes_active;
+ *end = *start + *available - 1;
+}
+
+static unsigned int skl_cursor_allocation(struct intel_wm_config *config)
+{
+ if (config->num_pipes_active == 1)
+ return 32;
+
+ return 8;
+}
+
+static unsigned int
+skl_plane_relative_data_rate(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,
+ struct skl_pipe_wm_parameters *params)
+{
+ unsigned int total_data_rate = 0;
+ int plane;
+
+ for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
+ struct intel_plane_wm_parameters *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,
+ struct intel_wm_config *config,
+ 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;
+ uint16_t available, start, end, cursor_blocks;
+ unsigned int total_data_rate;
+ int plane;
+
+ skl_ddb_get_pipe_allocation_limits(dev, crtc, config, params,
+ &available, &start, &end);
+ if (available == 0) {
+ const size_t size = ARRAY_SIZE(ddb->plane[pipe]) *
+ sizeof(struct skl_ddb_entry);
+
+ memset(ddb->plane[pipe], 0, size);
+ memset(&ddb->cursor[pipe], 0, sizeof(struct skl_ddb_entry));
+ return;
+ }
+
+ cursor_blocks = skl_cursor_allocation(config);
+ ddb->cursor[pipe].start = end - cursor_blocks + 1;
+ ddb->cursor[pipe].end = end;
+
+ available -= cursor_blocks;
+ 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 don't always allocate every single block here.
+ */
+ total_data_rate = skl_get_total_relative_data_rate(intel_crtc, params);
+
+ for (plane = 0; plane < intel_num_planes(intel_crtc); plane++) {
+ struct intel_plane_wm_parameters *p = &params->plane[plane];
+ unsigned int data_rate;
+ uint16_t plane_blocks;
+
+ 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)available * 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(struct drm_device *dev,
struct drm_crtc *crtc)
{
@@ -3259,6 +3408,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)))
--
1.8.3.1