[Intel-gfx] [PATCH v2] drm/i915: Enable second dbuf slice for ICL

Stanislav Lisovskiy stanislav.lisovskiy at intel.com
Wed Oct 9 07:39:08 UTC 2019


Also implemented algorithm for choosing DBuf slice configuration
based on active pipes, pipe ratio as stated in BSpec 12716.

Now pipe allocation still stays proportional to pipe width as before,
however within allowed DBuf slice for this particular configuration.

v2: Remove unneeded check from commit as ddb enabled slices might
    now differ from hw state.

Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c |   6 -
 drivers/gpu/drm/i915/intel_pm.c              | 208 ++++++++++++++++++-
 2 files changed, 202 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 1a533ccdb54f..4683731ac1ca 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -12989,12 +12989,6 @@ static void verify_wm_state(struct intel_crtc *crtc,
 	skl_ddb_get_hw_state(dev_priv, &hw->ddb);
 	sw_ddb = &dev_priv->wm.skl_hw.ddb;
 
-	if (INTEL_GEN(dev_priv) >= 11 &&
-	    hw->ddb.enabled_slices != sw_ddb->enabled_slices)
-		DRM_ERROR("mismatch in DBUF Slices (expected %u, got %u)\n",
-			  sw_ddb->enabled_slices,
-			  hw->ddb.enabled_slices);
-
 	/* planes */
 	for_each_universal_plane(dev_priv, pipe, plane) {
 		struct skl_plane_wm *hw_plane_wm, *sw_plane_wm;
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index bfcf03ab5245..0fbeea61299f 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3616,7 +3616,7 @@ static u8 intel_enabled_dbuf_slices_num(struct drm_i915_private *dev_priv)
 	 * only that 1 slice enabled until we have a proper way for on-demand
 	 * toggling of the second slice.
 	 */
-	if (0 && I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE)
+	if (I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE)
 		enabled_slices++;
 
 	return enabled_slices;
@@ -3821,7 +3821,7 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
 	 * - plane straddling both slices is illegal in multi-pipe scenarios
 	 * - should validate we stay within the hw bandwidth limits
 	 */
-	if (0 && (num_active > 1 || total_data_bw >= GBps(12))) {
+	if ((num_active > 1 || total_data_bw >= GBps(12))) {
 		ddb->enabled_slices = 2;
 	} else {
 		ddb->enabled_slices = 1;
@@ -3831,6 +3831,35 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
 	return ddb_size;
 }
 
+/*
+ * Calculate initial DBuf slice offset, based on slice size
+ * and mask(i.e if slice size is 1024 and second slice is enabled
+ * offset would be 1024)
+ */
+static u32 skl_get_first_dbuf_slice_offset(u32 dbuf_slice_mask,
+					   u32 slice_size, u32 ddb_size)
+{
+	u32 offset = 0;
+
+	if (!dbuf_slice_mask)
+		return 0;
+
+	while (!(dbuf_slice_mask & 1)) {
+		dbuf_slice_mask >>= 1;
+		offset += slice_size;
+		if (offset >= ddb_size)
+			break;
+	}
+	return offset;
+}
+
+static u32 i915_get_allowed_dbuf_mask(struct drm_i915_private *dev_priv,
+				      int pipe, u32 active_pipes,
+				      uint_fixed_16_16_t pipe_ratio);
+
+static uint_fixed_16_16_t
+skl_get_pipe_ratio(const struct intel_crtc_state *crtc_state);
+
 static void
 skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 				   const struct intel_crtc_state *crtc_state,
@@ -3846,7 +3875,13 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 	u32 pipe_width = 0, total_width = 0, width_before_pipe = 0;
 	enum pipe for_pipe = to_intel_crtc(for_crtc)->pipe;
 	u16 ddb_size;
+	u16 ddb_range_size;
 	u32 i;
+	u32 dbuf_slice_mask;
+	u32 active_pipes;
+	u32 offset;
+	u32 slice_size;
+	uint_fixed_16_16_t pipe_ratio;
 
 	if (WARN_ON(!state) || !crtc_state->base.active) {
 		alloc->start = 0;
@@ -3855,14 +3890,23 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 		return;
 	}
 
-	if (intel_state->active_pipe_changes)
+	if (intel_state->active_pipe_changes) {
 		*num_active = hweight8(intel_state->active_pipes);
-	else
+		active_pipes = intel_state->active_pipes;
+	} else {
 		*num_active = hweight8(dev_priv->active_pipes);
+		active_pipes = dev_priv->active_pipes;
+	}
 
 	ddb_size = intel_get_ddb_size(dev_priv, crtc_state, total_data_rate,
 				      *num_active, ddb);
 
+	DRM_DEBUG_KMS("Got total ddb size %d\n", ddb_size);
+
+	slice_size = ddb_size / ddb->enabled_slices;
+
+	DRM_DEBUG_KMS("Got DBuf slice size %d\n", slice_size);
+
 	/*
 	 * If the state doesn't change the active CRTC's or there is no
 	 * modeset request, then there's no need to recalculate;
@@ -3880,6 +3924,39 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 		return;
 	}
 
+	/*
+	 * Calculate pipe ratio as stated in BSpec 28692
+	 */
+	pipe_ratio = skl_get_pipe_ratio(crtc_state);
+
+	/*
+	 * Get allowed DBuf slices for correspondent pipe and platform.
+	 */
+	dbuf_slice_mask = i915_get_allowed_dbuf_mask(dev_priv, for_pipe,
+						     active_pipes, pipe_ratio);
+
+	DRM_DEBUG_KMS("DBuf slice mask %x pipe %d active pipes %x\n",
+		      dbuf_slice_mask,
+		      for_pipe, active_pipes);
+
+	/*
+	 * Figure out at which DBuf slice we start, i.e if we start at Dbuf S2
+	 * and slice size is 1024, the offset would be 1024
+	 */
+	offset = skl_get_first_dbuf_slice_offset(dbuf_slice_mask,
+						 slice_size, ddb_size);
+
+	/*
+	 * Figure out total size of allowed DBuf slices, which is basically
+	 * a number of allowed slices for that pipe multiplied by slice size.
+	 * We might still have some dbuf slices disabled in case if those
+	 * are not needed based on bandwidth requirements and num_active pipes,
+	 * so stick to real ddb size if it happens to be less. Inside of this
+	 * range ddb entries are still allocated in proportion to display width.
+	 */
+	ddb_range_size = min(hweight8(dbuf_slice_mask) * slice_size,
+			     (unsigned int)ddb_size);
+
 	/*
 	 * Watermark/ddb requirement highly depends upon width of the
 	 * framebuffer, So instead of allocating DDB equally among pipes
@@ -3890,10 +3967,23 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 			&crtc_state->base.adjusted_mode;
 		enum pipe pipe = crtc->pipe;
 		int hdisplay, vdisplay;
+		uint_fixed_16_16_t ratio = skl_get_pipe_ratio(crtc_state);
+		u32 pipe_dbuf_slice_mask = i915_get_allowed_dbuf_mask(dev_priv,
+								      pipe,
+								      active_pipes,
+								      ratio);
 
 		if (!crtc_state->base.enable)
 			continue;
 
+		/*
+		 * According to BSpec pipe can share one dbuf slice with another pipes or pipe can use
+		 * multiple dbufs, in both cases we account for other pipes only if they have
+		 * exactly same mask.
+		 */
+		if (dbuf_slice_mask != pipe_dbuf_slice_mask)
+			continue;
+
 		drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay);
 		total_width += hdisplay;
 
@@ -3903,8 +3993,11 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 			pipe_width = hdisplay;
 	}
 
-	alloc->start = ddb_size * width_before_pipe / total_width;
-	alloc->end = ddb_size * (width_before_pipe + pipe_width) / total_width;
+	alloc->start = offset + ddb_range_size * width_before_pipe / total_width;
+	alloc->end = offset + ddb_range_size * (width_before_pipe + pipe_width) / total_width;
+
+	DRM_DEBUG_KMS("Pipe %d ddb %d-%d\n", for_pipe,
+		      alloc->start, alloc->end);
 }
 
 static int skl_compute_wm_params(const struct intel_crtc_state *crtc_state,
@@ -4255,6 +4348,109 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
 	return total_data_rate;
 }
 
+uint_fixed_16_16_t
+skl_get_pipe_ratio(const struct intel_crtc_state *crtc_state)
+{
+	struct drm_plane *plane;
+	const struct drm_plane_state *drm_plane_state;
+	uint_fixed_16_16_t pipe_downscale;
+	uint_fixed_16_16_t max_downscale = u32_to_fixed16(1);
+
+	if (!crtc_state->base.enable)
+		return max_downscale;
+
+	drm_atomic_crtc_state_for_each_plane_state(plane, drm_plane_state, &crtc_state->base) {
+		uint_fixed_16_16_t plane_downscale;
+		const struct intel_plane_state *plane_state =
+			to_intel_plane_state(drm_plane_state);
+
+		if (!intel_wm_plane_visible(crtc_state, plane_state))
+			continue;
+
+		plane_downscale = skl_plane_downscale_amount(crtc_state, plane_state);
+
+		max_downscale = max_fixed16(plane_downscale, max_downscale);
+	}
+
+	pipe_downscale = skl_pipe_downscale_amount(crtc_state);
+
+	pipe_downscale = mul_fixed16(pipe_downscale, max_downscale);
+
+	return pipe_downscale;
+}
+
+#define DBUF_S1_BIT 1
+#define DBUF_S2_BIT 2
+
+struct dbuf_slice_conf_entry {
+	u32 dbuf_mask[I915_MAX_PIPES];
+	u32 active_pipes;
+};
+
+
+/*
+ * Table taken from Bspec 12716
+ * Pipes do have some preferred DBuf slice affinity,
+ * plus there are some hardcoded requirements on how
+ * those should be distributed for multipipe scenarios.
+ * For more DBuf slices algorithm can get even more messy
+ * and less readable, so decided to use a table almost
+ * as is from BSpec itself - that way it is at least easier
+ * to compare, change and check.
+ */
+struct dbuf_slice_conf_entry icl_allowed_dbufs[] = {
+{ { 0, 0, 0, 0 }, 0 },
+{ { DBUF_S1_BIT | DBUF_S2_BIT, 0, 0, 0 }, BIT(PIPE_A) },
+{ { DBUF_S1_BIT, 0, 0, 0 }, BIT(PIPE_A) },
+{ { 0, DBUF_S1_BIT | DBUF_S2_BIT, 0, 0 }, BIT(PIPE_B) },
+{ { 0, DBUF_S1_BIT, 0, 0 }, BIT(PIPE_B) },
+{ { 0, 0, DBUF_S1_BIT | DBUF_S2_BIT }, BIT(PIPE_C) },
+{ { 0, 0, DBUF_S2_BIT, 0 }, BIT(PIPE_C) },
+{ { DBUF_S1_BIT, DBUF_S2_BIT, 0, 0 }, BIT(PIPE_A) | BIT(PIPE_B) },
+{ { DBUF_S1_BIT, 0, DBUF_S2_BIT, 0 }, BIT(PIPE_A) | BIT(PIPE_C) },
+{ { 0, DBUF_S1_BIT, DBUF_S2_BIT, 0 }, BIT(PIPE_B) | BIT(PIPE_C) },
+{ { DBUF_S1_BIT, DBUF_S1_BIT, DBUF_S2_BIT, 0 }, BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) },
+};
+
+/*
+ * This function finds an entry with same enabled pipe configuration and
+ * returns correspondent DBuf slice mask as stated in BSpec for particular
+ * platform.
+ */
+static u32 icl_get_allowed_dbuf_mask(int pipe,
+				     u32 active_pipes,
+				     uint_fixed_16_16_t pipe_ratio)
+{
+	int i;
+	for (i = 0; i < ARRAY_SIZE(icl_allowed_dbufs); i++) {
+		if (icl_allowed_dbufs[i].active_pipes == active_pipes) {
+			/*
+			 * According to BSpec 12716: if pipe_ratio >= 88.8
+			 * use single pipe, even if two are accessible.
+			 */
+			if (pipe_ratio.val >= div_fixed16(888, 10).val)
+				++i;
+			return icl_allowed_dbufs[i].dbuf_mask[pipe];
+		}
+	}
+	return 0;
+}
+
+u32 i915_get_allowed_dbuf_mask(struct drm_i915_private *dev_priv,
+				      int pipe, u32 active_pipes,
+				      uint_fixed_16_16_t pipe_ratio)
+{
+	if (IS_GEN(dev_priv, 11))
+		return icl_get_allowed_dbuf_mask(pipe,
+						 active_pipes,
+						 pipe_ratio);
+	/*
+	 * For anything else just return one slice yet.
+	 * Should be extended for other platforms.
+	 */
+	return DBUF_S1_BIT;
+}
+
 static u64
 icl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
 				 u64 *plane_data_rate)
-- 
2.17.1



More information about the Intel-gfx mailing list