[PATCH v3] drm/i915: Enable second dbuf slice for ICL and TGL

Stanislav Lisovskiy stanislav.lisovskiy at intel.com
Mon Oct 21 10:58:17 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.

v3: - Added new field "supported_slices" to ddb to separate max
      supported slices vs currently enabled, to avoid confusion.
    - Removed obsolete comments and code related to DBuf(Matthew Roper).
    - Some code style and long line removal(Matthew Roper).
    - Added WARN_ON to new ddb range offset calc function(Matthew Roper).
    - Removed platform specific call to calc pipe ratio from ddb
      allocation function and fixed the return value(Matthew Roper)
    - Refactored DBUF slice allocation table to improve readability
    - Added DBUF slice allocation for TGL as well.
    - ICL(however not TGL) seems to voluntarily enable second DBuf slice
      after pm suspend/resume causing a mismatch failure, because we
      update DBuf slices only if we do a modeset, however this check
      is done always. Fixed it to be done only when modeset for ICL.

Signed-off-by: Stanislav Lisovskiy <stanislav.lisovskiy at intel.com>
Cc: Matthew Roper <matthew.d.roper at intel.com>
Cc: Ville Syrjälä <ville.syrjala at intel.com>
Cc: James Ausmus <james.ausmus at intel.com>
---
 drivers/gpu/drm/i915/display/intel_display.c  |   5 +-
 .../drm/i915/display/intel_display_power.c    |  11 +
 .../drm/i915/display/intel_display_power.h    |   1 +
 drivers/gpu/drm/i915/i915_drv.c               |   5 +
 drivers/gpu/drm/i915/i915_drv.h               |   3 +-
 drivers/gpu/drm/i915/intel_pm.c               | 335 ++++++++++++++++--
 6 files changed, 334 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c
index 3cf39fc153b3..21688e3c0251 100644
--- a/drivers/gpu/drm/i915/display/intel_display.c
+++ b/drivers/gpu/drm/i915/display/intel_display.c
@@ -12958,7 +12958,8 @@ static void verify_wm_state(struct intel_crtc *crtc,
 	sw_ddb = &dev_priv->wm.skl_hw.ddb;
 
 	if (INTEL_GEN(dev_priv) >= 11 &&
-	    hw->ddb.enabled_slices != sw_ddb->enabled_slices)
+	    hw->ddb.enabled_slices != sw_ddb->enabled_slices &&
+	    needs_modeset(new_crtc_state))
 		DRM_ERROR("mismatch in DBUF Slices (expected %u, got %u)\n",
 			  sw_ddb->enabled_slices,
 			  hw->ddb.enabled_slices);
@@ -13894,6 +13895,8 @@ static void skl_commit_modeset_enables(struct intel_atomic_state *state)
 		if (new_crtc_state->base.active)
 			entries[i] = old_crtc_state->wm.skl.ddb;
 
+	DRM_DEBUG_KMS("DBuf req slices %d hw slices %d\n", required_slices, hw_enabled_slices);
+
 	/* If 2nd DBuf slice required, enable it here */
 	if (INTEL_GEN(dev_priv) >= 11 && required_slices > hw_enabled_slices)
 		icl_dbuf_slices_update(dev_priv, required_slices);
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.c b/drivers/gpu/drm/i915/display/intel_display_power.c
index 6f9e7927e248..01027f67b148 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.c
+++ b/drivers/gpu/drm/i915/display/intel_display_power.c
@@ -4259,6 +4259,15 @@ static u8 intel_dbuf_max_slices(struct drm_i915_private *dev_priv)
 	return 2;
 }
 
+void icl_dbuf_slices_restore(struct drm_i915_private *dev_priv)
+{
+	const u8 hw_enabled_slices = dev_priv->wm.skl_hw.ddb.enabled_slices;
+	if (hw_enabled_slices > 1)
+		ret = intel_dbuf_slice_set(dev_priv, DBUF_CTL_S2, true);
+	else
+		ret = intel_dbuf_slice_set(dev_priv, DBUF_CTL_S2, false);
+}
+
 void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
 			    u8 req_slices)
 {
@@ -4273,6 +4282,8 @@ void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
 	if (req_slices == hw_enabled_slices || req_slices == 0)
 		return;
 
+	DRM_DEBUG_KMS("Updating dbuf slices from %d to %d\n", hw_enabled_slices, req_slices);
+
 	if (req_slices > hw_enabled_slices)
 		ret = intel_dbuf_slice_set(dev_priv, DBUF_CTL_S2, true);
 	else
diff --git a/drivers/gpu/drm/i915/display/intel_display_power.h b/drivers/gpu/drm/i915/display/intel_display_power.h
index 1da04f3e0fb3..6fcf0853aa39 100644
--- a/drivers/gpu/drm/i915/display/intel_display_power.h
+++ b/drivers/gpu/drm/i915/display/intel_display_power.h
@@ -313,6 +313,7 @@ intel_display_power_put_async(struct drm_i915_private *i915,
 
 void icl_dbuf_slices_update(struct drm_i915_private *dev_priv,
 			    u8 req_slices);
+void icl_dbuf_slices_restore(struct drm_i915_private *dev_priv);
 
 void chv_phy_powergate_lanes(struct intel_encoder *encoder,
 			     bool override, unsigned int mask);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index f02a34722217..4caefc8a963e 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -51,6 +51,7 @@
 #include "display/intel_bw.h"
 #include "display/intel_cdclk.h"
 #include "display/intel_display_types.h"
+#include "display/intel_display_power.h"
 #include "display/intel_dp.h"
 #include "display/intel_fbdev.h"
 #include "display/intel_hotplug.h"
@@ -2575,6 +2576,10 @@ static int intel_runtime_resume(struct device *kdev)
 	if (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv))
 		ret = vlv_resume_prepare(dev_priv, true);
 
+	/* Weird hack to fix ICL hardware bug, as it resets DBUF slices reg */
+	if (INTEL_GEN(dev_priv) == 11)
+		icl_dbuf_slices_restore(dev_priv);
+
 	intel_uncore_runtime_resume(&dev_priv->uncore);
 
 	intel_runtime_pm_enable_interrupts(dev_priv);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c46b339064c0..3c7bf2daff9e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -898,7 +898,8 @@ static inline bool skl_ddb_entry_equal(const struct skl_ddb_entry *e1,
 }
 
 struct skl_ddb_allocation {
-	u8 enabled_slices; /* GEN11 has configurable 2 slices */
+	u8 enabled_slices;   /* Number of currently enabled DBuf slices */
+	u8 supported_slices; /* GEN 11 supports 2 slices, however this might change */
 };
 
 struct skl_ddb_values {
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index b306e2338f5a..ec48890828ec 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -3607,12 +3607,8 @@ static u8 intel_enabled_dbuf_slices_num(struct drm_i915_private *dev_priv)
 	if (INTEL_GEN(dev_priv) < 11)
 		return enabled_slices;
 
-	/*
-	 * FIXME: for now we'll only ever use 1 slice; pretend that we have
-	 * 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)
+	/* Check if second DBuf slice is enabled */
+	if (I915_READ(DBUF_CTL_S2) & DBUF_POWER_STATE)
 		enabled_slices++;
 
 	return enabled_slices;
@@ -3827,6 +3823,7 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
 	u16 ddb_size = INTEL_INFO(dev_priv)->ddb_size;
 
 	WARN_ON(ddb_size == 0);
+	ddb->supported_slices = 1;
 
 	if (INTEL_GEN(dev_priv) < 11)
 		return ddb_size - 4; /* 4 blocks for bypass path allocation */
@@ -3834,24 +3831,39 @@ static u16 intel_get_ddb_size(struct drm_i915_private *dev_priv,
 	adjusted_mode = &crtc_state->base.adjusted_mode;
 	total_data_bw = total_data_rate * drm_mode_vrefresh(adjusted_mode);
 
-	/*
-	 * 12GB/s is maximum BW supported by single DBuf slice.
-	 *
-	 * FIXME dbuf slice code is broken:
-	 * - must wait for planes to stop using the slice before powering it off
-	 * - 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))) {
-		ddb->enabled_slices = 2;
-	} else {
-		ddb->enabled_slices = 1;
-		ddb_size /= 2;
-	}
+	if (INTEL_GEN(dev_priv) >= 11)
+		ddb->supported_slices = 2;
 
 	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;
+	}
+	WARN_ON(offset >= ddb_size);
+	return offset;
+}
+
+static u32 i915_get_allowed_dbuf_mask(struct drm_i915_private *dev_priv,
+				      int pipe, u32 active_pipes,
+				      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,
@@ -3867,7 +3879,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;
+	u32 total_slice_mask;
 
 	if (WARN_ON(!state) || !crtc_state->base.active) {
 		alloc->start = 0;
@@ -3876,14 +3894,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->supported_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;
@@ -3901,20 +3928,73 @@ skl_ddb_get_pipe_allocation_limits(struct drm_i915_private *dev_priv,
 		return;
 	}
 
+	/*
+	 * Get allowed DBuf slices for correspondent pipe and platform.
+	 */
+	dbuf_slice_mask = i915_get_allowed_dbuf_mask(dev_priv, for_pipe,
+						     active_pipes, crtc_state);
+
+	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
 	 * distribute DDB based on resolution/width of the display.
 	 */
+	total_slice_mask = dbuf_slice_mask;
 	for_each_new_intel_crtc_in_state(intel_state, crtc, crtc_state, i) {
 		const struct drm_display_mode *adjusted_mode =
 			&crtc_state->base.adjusted_mode;
 		enum pipe pipe = crtc->pipe;
 		int hdisplay, vdisplay;
+		u32 pipe_dbuf_slice_mask = \
+			i915_get_allowed_dbuf_mask(dev_priv,
+						pipe,
+						active_pipes,
+						crtc_state);
 
 		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.
+		 * However we need to account how many slices we should enable
+		 * in total.
+		 */
+		total_slice_mask |= pipe_dbuf_slice_mask;
+
+		/*
+		 * Do not account pipes using other slice sets
+		 * luckily as of current BSpec slice sets do not partially
+		 * intersect(pipes share either same one slice or same slice set
+		 * i.e no partial intersection), so it is enough to check for
+		 * equality for now.
+		 */
+		if (dbuf_slice_mask != pipe_dbuf_slice_mask)
+			continue;
+
 		drm_mode_get_hv_timing(adjusted_mode, &hdisplay, &vdisplay);
 		total_width += hdisplay;
 
@@ -3924,8 +4004,16 @@ 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;
+	ddb->enabled_slices = hweight8(total_slice_mask);
+
+	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);
+	DRM_DEBUG_KMS("Enabled ddb slices %d supported %d\n",
+		      ddb->enabled_slices,
+		      ddb->supported_slices);
 }
 
 static int skl_compute_wm_params(const struct intel_crtc_state *crtc_state,
@@ -4047,6 +4135,7 @@ void skl_ddb_get_hw_state(struct drm_i915_private *dev_priv,
 			  struct skl_ddb_allocation *ddb /* out */)
 {
 	ddb->enabled_slices = intel_enabled_dbuf_slices_num(dev_priv);
+	DRM_DEBUG_KMS("Got hw dbuf slices %d\n", ddb->enabled_slices);
 }
 
 /*
@@ -4261,6 +4350,204 @@ skl_get_total_relative_data_rate(struct intel_crtc_state *crtc_state,
 	return total_data_rate;
 }
 
+uint_fixed_16_16_t
+icl_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);
+
+	/* Convert result to percentage */
+	return u32_to_fixed16(100 * div_round_up_u32_fixed16(1, 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;
+};
+
+
+#define ICL_PIPE_A_DBUF_SLICES(DBuf1)  \
+	{ { DBuf1, 0, 0, 0 }, BIT(PIPE_A) }
+#define ICL_PIPE_B_DBUF_SLICES(DBuf1)  \
+	{ { 0, DBuf1, 0, 0 }, BIT(PIPE_B) }
+#define ICL_PIPE_C_DBUF_SLICES(DBuf1)  \
+	{ { 0, 0, DBuf1, 0 }, BIT(PIPE_C) }
+#define ICL_PIPE_D_DBUF_SLICES(DBuf1)  \
+	{ { 0, 0, 0, DBuf1 }, BIT(PIPE_D) }
+#define ICL_PIPE_AB_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { DBuf1, DBuf2, 0, 0 }, BIT(PIPE_A) | BIT(PIPE_B) }
+#define ICL_PIPE_BC_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { 0, DBuf1, DBuf2, 0 }, BIT(PIPE_B) | BIT(PIPE_C) }
+#define ICL_PIPE_BD_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { 0, DBuf1, 0, DBuf2 }, BIT(PIPE_B) | BIT(PIPE_D) }
+#define ICL_PIPE_AC_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { DBuf1, 0, DBuf2, 0 }, BIT(PIPE_A) | BIT(PIPE_C) }
+#define ICL_PIPE_AD_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { DBuf1, 0, 0, DBuf2 }, BIT(PIPE_A) | BIT(PIPE_D) }
+#define ICL_PIPE_CD_DBUF_SLICES(DBuf1, DBuf2)   \
+	{ { 0, 0, DBuf1, DBuf2 }, BIT(PIPE_C) | BIT(PIPE_D) }
+#define ICL_PIPE_ABC_DBUF_SLICES(DBuf1, DBuf2, DBuf3)  \
+	{ { DBuf1, DBuf2, DBuf3, 0 }, BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) }
+#define ICL_PIPE_ACD_DBUF_SLICES(DBuf1, DBuf2, DBuf3)  \
+	{ { DBuf1, 0, DBuf2, DBuf3 }, BIT(PIPE_A) | BIT(PIPE_C) | BIT(PIPE_D) }
+#define ICL_PIPE_BCD_DBUF_SLICES(DBuf1, DBuf2, DBuf3)  \
+	{ { 0, DBuf1, DBuf2, DBuf3 }, BIT(PIPE_B) | BIT(PIPE_C) | BIT(PIPE_D) }
+#define ICL_PIPE_ABD_DBUF_SLICES(DBuf1, DBuf2, DBuf3)  \
+	{ { DBuf1, DBuf2, 0, DBuf3 }, BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_D) }
+#define ICL_PIPE_ABC_DBUF_SLICES(DBuf1, DBuf2, DBuf3)  \
+	{ { DBuf1, DBuf2, DBuf3, 0 }, BIT(PIPE_A) | BIT(PIPE_B) | BIT(PIPE_C) }
+#define ICL_PIPE_ABCD_DBUF_SLICES(DBuf1, DBuf2, DBuf3, DBuf4)  \
+	{ { DBuf1, DBuf2, DBuf3, DBuf4 }, BIT(PIPE_A) | BIT(PIPE_B) | \
+					  BIT(PIPE_C) | BIT(PIPE_D) }
+
+/*
+ * 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 },
+ICL_PIPE_A_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),  /* pipe ratio < 88.8 */
+ICL_PIPE_A_DBUF_SLICES(DBUF_S1_BIT),                /* for pipe ratio >= 88.8 */
+ICL_PIPE_B_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),  /* pipe ratio < 88.8 */
+ICL_PIPE_B_DBUF_SLICES(DBUF_S1_BIT),                /* for pipe ratio >= 88.8 */
+ICL_PIPE_C_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),  /* pipe ratio < 88.8 */
+ICL_PIPE_C_DBUF_SLICES(DBUF_S2_BIT),                /* for pipe ratio >= 88.8 */
+ICL_PIPE_AB_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_AC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_BC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_ABC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S1_BIT, DBUF_S2_BIT),
+};
+
+/*
+ * Table taken from Bspec 49255
+ * 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 tgl_allowed_dbufs[] = {
+{ { 0, 0, 0, 0 }, 0 },
+ICL_PIPE_A_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),
+ICL_PIPE_B_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),
+ICL_PIPE_C_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),
+ICL_PIPE_D_DBUF_SLICES(DBUF_S1_BIT | DBUF_S2_BIT),
+ICL_PIPE_AB_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_AC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_BC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_AD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_BD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_CD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_ABD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_ABC_DBUF_SLICES(DBUF_S1_BIT, DBUF_S1_BIT, DBUF_S2_BIT),
+ICL_PIPE_ACD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT, DBUF_S2_BIT),
+ICL_PIPE_BCD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S2_BIT, DBUF_S2_BIT),
+ICL_PIPE_ABCD_DBUF_SLICES(DBUF_S1_BIT, DBUF_S1_BIT, DBUF_S2_BIT, DBUF_S2_BIT),
+};
+
+/*
+ * 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,
+				     const struct intel_crtc_state *crtc_state)
+{
+	int i;
+	uint_fixed_16_16_t pipe_ratio;
+
+	/*
+	 * Calculate pipe ratio as stated in BSpec 28692
+	 */
+	pipe_ratio = icl_get_pipe_ratio(crtc_state);
+
+	for (i = 0; i < ARRAY_SIZE(icl_allowed_dbufs); i++) {
+		if (icl_allowed_dbufs[i].active_pipes == active_pipes) {
+			if (hweight32(active_pipes) == 1) {
+				/*
+				 * According to BSpec 12716: if pipe_ratio >= 88.8
+				 * use single dbuf slice, 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;
+}
+
+/*
+ * 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 tgl_get_allowed_dbuf_mask(int pipe,
+				     u32 active_pipes,
+				     const struct intel_crtc_state *crtc_state)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(tgl_allowed_dbufs); i++) {
+		if (tgl_allowed_dbufs[i].active_pipes == active_pipes)
+			return tgl_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,
+				      const struct intel_crtc_state *crtc_state)
+{
+	if (IS_GEN(dev_priv, 11))
+		return icl_get_allowed_dbuf_mask(pipe,
+						 active_pipes,
+						 crtc_state);
+	else if (IS_GEN(dev_priv, 12))
+		return tgl_get_allowed_dbuf_mask(pipe,
+						 active_pipes,
+						 crtc_state);
+	/*
+	 * 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-trybot mailing list