[Intel-gfx] [RFC PATCH 1/2] drm/i915: Calculate self-refresh watermark by using one unique algorithm on g4x/965/9xx platform

yakui.zhao at intel.com yakui.zhao at intel.com
Fri Dec 4 16:01:04 CET 2009


From: Zhao Yakui <yakui.zhao at intel.com>

Use one unique algorithm to calucate the self-refresh watermark on g4x/965/9xx
platform, which is done by calling the function of intel_calculate_wm.
   In this function it will calculate the requried minimum fifo size firstly
and then get the expected watermark.

According to the spec the fifo entry size is 512 instead of 128 on the 965gm/
g4x platform when using self-refresh mode. So we will use the 512 fifo size
on 965gm/g4x platform to calculate the self-refresh watermark.

We also use the function of intel_calculate_wm to calculate self-refresh
watermark on 9xx platform.

We will configure the cursor self-refresh watermark on 965 platform.

Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
---
 drivers/gpu/drm/i915/i915_reg.h      |    7 ++
 drivers/gpu/drm/i915/intel_display.c |  179 +++++++++++++++++++++-------------
 2 files changed, 116 insertions(+), 70 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 6b59602..5ed7ceb 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -1842,6 +1842,13 @@
 #define IGD_CURSOR_DFT_WM	0
 #define IGD_CURSOR_GUARD_WM	5
 
+/* define the Fifo definition in self-refresh state */
+#define	I965_DISPLAY_FIFO	512
+#define	I965_MAX_WM		0x1ff
+#define	I965_DFT_WM		0x3f
+#define	I965_GUARD_WM		8
+#define	I965_FIFO_LINE_SIZE	64
+
 /*
  * The two pipe frame counter registers are not synchronized, so
  * reading a stable value is somewhat tricky. The following code
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 65b76ff..fa7531f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2191,6 +2191,12 @@ struct intel_watermark_params {
 	unsigned long default_wm;
 	unsigned long guard_size;
 	unsigned long cacheline_size;
+	/* indicate whether the required entry is treated as the watermark.
+	 * If it is 1, it will use the required entries to set the watermark.
+	 * Otherwise we will subtract the required entry from the total size
+	 * to get the watermark.
+	 */
+	int	watermark_flag;
 };
 
 /* IGD has different values for various configs */
@@ -2226,9 +2232,30 @@ static struct intel_watermark_params g4x_wm_info = {
 	G4X_FIFO_SIZE,
 	G4X_MAX_WM,
 	G4X_MAX_WM,
-	2,
+	I965_GUARD_WM,
 	G4X_FIFO_LINE_SIZE,
+	1,
 };
+
+/* the Fifo definition for self-refresh on g4x platform */
+static struct intel_watermark_params g4x_wm_self_info = {
+	I965_DISPLAY_FIFO,
+	I965_MAX_WM,
+	I965_DFT_WM,
+	I965_GUARD_WM,
+	I965_FIFO_LINE_SIZE,
+	1,
+};
+
+/* the Fifo definition for self-refresh on 965gm platform */
+static struct intel_watermark_params gm965_wm_self_info = {
+	I965_DISPLAY_FIFO,
+	I965_MAX_WM,
+	I965_DFT_WM,
+	I965_GUARD_WM,
+	I965_FIFO_LINE_SIZE,
+};
+
 static struct intel_watermark_params i945_wm_info = {
 	I945_FIFO_SIZE,
 	I915_MAX_WM,
@@ -2281,7 +2308,8 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
 					int pixel_size,
 					unsigned long latency_ns)
 {
-	long entries_required, wm_size;
+	long entries_required;
+	int sr_entries, wm_size;
 
 	/*
 	 * Note: we need to make sure we don't overflow for various clock &
@@ -2291,18 +2319,29 @@ static unsigned long intel_calculate_wm(unsigned long clock_in_khz,
 	 */
 	entries_required = ((clock_in_khz / 1000) * pixel_size * latency_ns) /
 		1000;
-	entries_required /= wm->cacheline_size;
+	/* Round up to the next cacheline boundary */
+	sr_entries = DIV_ROUND_UP(entries_required, wm->cacheline_size);
 
-	DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", entries_required);
+	DRM_DEBUG_KMS("FIFO entries required for mode: %d\n", sr_entries);
 
-	wm_size = wm->fifo_size - (entries_required + wm->guard_size);
+	/*
+	 * When the watermark flag is non-zero, the required entry size will
+	 * be treated as the watermark.
+	 * Otherwise we will subtract the required entry size from the total
+	 * size to get the watermark.
+	 */
+	if (wm->watermark_flag)
+		wm_size = sr_entries + wm->guard_size;
+	else
+		wm_size = wm->fifo_size - (sr_entries + wm->guard_size);
 
 	DRM_DEBUG_KMS("FIFO watermark level: %d\n", wm_size);
 
 	/* Don't promote wm_size to unsigned... */
 	if (wm_size > (long)wm->max_wm)
 		wm_size = wm->max_wm;
-	if (wm_size <= 0)
+	/* If the watermark is below the default threshold, use the default */
+	if (wm_size < wm->default_wm)
 		wm_size = wm->default_wm;
 	return wm_size;
 }
@@ -2524,18 +2563,8 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 			  int planeb_clock, int sr_hdisplay, int pixel_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	int total_size, cacheline_size;
 	int planea_wm, planeb_wm, cursora_wm, cursorb_wm, cursor_sr;
-	struct intel_watermark_params planea_params, planeb_params;
-	unsigned long line_time_us;
-	int sr_clock, sr_entries = 0, entries_required;
-
-	/* Create copies of the base settings for each pipe */
-	planea_params = planeb_params = g4x_wm_info;
-
-	/* Grab a couple of global values before we overwrite them */
-	total_size = planea_params.fifo_size;
-	cacheline_size = planea_params.cacheline_size;
+	int sr_clock, srwm = 8;
 
 	/*
 	 * Note: we need to make sure we don't overflow for various clock &
@@ -2543,20 +2572,31 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 	 * clocks go from a few thousand to several hundred thousand.
 	 * latency is usually a few thousand
 	 */
-	entries_required = ((planea_clock / 1000) * pixel_size * latency_ns) /
-		1000;
-	entries_required /= G4X_FIFO_LINE_SIZE;
-	planea_wm = entries_required + planea_params.guard_size;
+	/*
+	 * When the display clock is effective, we will calculate the
+	 * watermark for display plane by using intel_calculate_wm.
+	 * Otherwise we will use the default value
+	 */
+	if (planea_clock)
+		planea_wm = intel_calculate_wm(planea_clock, &g4x_wm_info,
+						pixel_size, latency_ns);
+	else
+		planea_wm = 15;
 
-	entries_required = ((planeb_clock / 1000) * pixel_size * latency_ns) /
-		1000;
-	entries_required /= G4X_FIFO_LINE_SIZE;
-	planeb_wm = entries_required + planeb_params.guard_size;
+	if (planeb_clock)
+		planeb_wm = intel_calculate_wm(planeb_clock, &g4x_wm_info,
+						pixel_size, latency_ns);
+	else
+		planeb_wm = 15;
 
-	cursora_wm = cursorb_wm = 16;
+	/*
+	 * The cursor self-refresh watermark is 32.
+	 * The cursor A/B watermark is 8.
+	 */
+	cursora_wm = cursorb_wm = 8;
 	cursor_sr = 32;
 
-	DRM_DEBUG("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
+	DRM_DEBUG_KMS("FIFO watermarks - A: %d, B: %d\n", planea_wm, planeb_wm);
 
 	/* Calc sr entries for one plane configs */
 	if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
@@ -2564,26 +2604,22 @@ static void g4x_update_wm(struct drm_device *dev,  int planea_clock,
 		const static int sr_latency_ns = 12000;
 
 		sr_clock = planea_clock ? planea_clock : planeb_clock;
-		line_time_us = ((sr_hdisplay * 1000) / sr_clock);
 
-		/* Use ns/us then divide to preserve precision */
-		sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-			      pixel_size * sr_hdisplay) / 1000;
-		sr_entries = roundup(sr_entries / cacheline_size, 1);
-		DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
+		srwm = intel_calculate_wm(sr_clock, &g4x_wm_self_info,
+						pixel_size, sr_latency_ns);
+
+		DRM_DEBUG_KMS("self-refresh watermark: %d\n", srwm);
 		I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 	}
 
-	DRM_DEBUG("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
-		  planea_wm, planeb_wm, sr_entries);
+	DRM_DEBUG_KMS("Setting FIFO watermarks - A: %d, B: %d, SR %d\n",
+		  planea_wm, planeb_wm, srwm);
 
-	planea_wm &= 0x3f;
-	planeb_wm &= 0x3f;
-
-	I915_WRITE(DSPFW1, (sr_entries << DSPFW_SR_SHIFT) |
+	I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) |
 		   (cursorb_wm << DSPFW_CURSORB_SHIFT) |
 		   (planeb_wm << DSPFW_PLANEB_SHIFT) | planea_wm);
-	I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & DSPFW_CURSORA_MASK) |
+	/* Only update the cursor A watermark bits in FW2 */
+	I915_WRITE(DSPFW2, (I915_READ(DSPFW2) & ~DSPFW_CURSORA_MASK) |
 		   (cursora_wm << DSPFW_CURSORA_SHIFT));
 	/* HPLL off in SR has some issues on G4x... disable it */
 	I915_WRITE(DSPFW3, (I915_READ(DSPFW3) & ~DSPFW_HPLL_SR_EN) |
@@ -2594,26 +2630,29 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
 			   int planeb_clock, int sr_hdisplay, int pixel_size)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-	unsigned long line_time_us;
-	int sr_clock, sr_entries, srwm = 1;
+	int sr_clock, srwm = 8, cursor_srwm;
+	struct intel_watermark_params sr_params;
 
+	cursor_srwm = 32;
 	/* Calc sr entries for one plane configs */
 	if (sr_hdisplay && (!planea_clock || !planeb_clock)) {
 		/* self-refresh has much higher latency */
 		const static int sr_latency_ns = 12000;
 
 		sr_clock = planea_clock ? planea_clock : planeb_clock;
-		line_time_us = ((sr_hdisplay * 1000) / sr_clock);
-
-		/* Use ns/us then divide to preserve precision */
-		sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-			      pixel_size * sr_hdisplay) / 1000;
-		sr_entries = roundup(sr_entries / I915_FIFO_LINE_SIZE, 1);
-		DRM_DEBUG("self-refresh entries: %d\n", sr_entries);
-		srwm = I945_FIFO_SIZE - sr_entries;
-		if (srwm < 0)
-			srwm = 1;
-		srwm &= 0x3f;
+		if (IS_I965GM(dev))
+			sr_params = gm965_wm_self_info;
+		else {
+			sr_params = i945_wm_info;
+			sr_params.guard_size = 8;
+			sr_params.default_wm = 32;
+		}
+
+		srwm = intel_calculate_wm(sr_clock, &sr_params,
+					pixel_size, sr_latency_ns);
+
+		DRM_DEBUG_KMS("self-refresh watermark: %d\n", srwm);
+
 		I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN);
 	}
 
@@ -2624,6 +2663,8 @@ static void i965_update_wm(struct drm_device *dev, int planea_clock,
 	I915_WRITE(DSPFW1, (srwm << DSPFW_SR_SHIFT) | (8 << 16) | (8 << 8) |
 		   (8 << 0));
 	I915_WRITE(DSPFW2, (8 << 8) | (8 << 0));
+	/* Write the cursor self-refresh watermark */
+	I915_WRITE(DSPFW3, (cursor_srwm << 24));
 }
 
 static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
@@ -2632,11 +2673,10 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	uint32_t fwater_lo;
 	uint32_t fwater_hi;
-	int total_size, cacheline_size, cwm, srwm = 1;
+	int cwm, srwm = 1;
 	int planea_wm, planeb_wm;
-	struct intel_watermark_params planea_params, planeb_params;
-	unsigned long line_time_us;
-	int sr_clock, sr_entries = 0;
+	struct intel_watermark_params planea_params, planeb_params, sr_params;
+	int sr_clock;
 
 	/* Create copies of the base settings for each pipe */
 	if (IS_I965GM(dev) || IS_I945GM(dev))
@@ -2646,13 +2686,14 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 	else
 		planea_params = planeb_params = i855_wm_info;
 
-	/* Grab a couple of global values before we overwrite them */
-	total_size = planea_params.fifo_size;
-	cacheline_size = planea_params.cacheline_size;
+	sr_params = planea_params;
 
 	/* Update per-plane FIFO sizes */
 	planea_params.fifo_size = dev_priv->display.get_fifo_size(dev, 0);
 	planeb_params.fifo_size = dev_priv->display.get_fifo_size(dev, 1);
+	/* update the max watermark for per-plane */
+	planea_params.max_wm = planea_params.fifo_size / 2;
+	planeb_params.max_wm = planeb_params.fifo_size / 2;
 
 	planea_wm = intel_calculate_wm(planea_clock, &planea_params,
 				       pixel_size, latency_ns);
@@ -2672,16 +2713,14 @@ static void i9xx_update_wm(struct drm_device *dev, int planea_clock,
 		const static int sr_latency_ns = 6000;
 
 		sr_clock = planea_clock ? planea_clock : planeb_clock;
-		line_time_us = ((sr_hdisplay * 1000) / sr_clock);
-
-		/* Use ns/us then divide to preserve precision */
-		sr_entries = (((sr_latency_ns / line_time_us) + 1) *
-			      pixel_size * sr_hdisplay) / 1000;
-		sr_entries = roundup(sr_entries / cacheline_size, 1);
-		DRM_DEBUG_KMS("self-refresh entries: %d\n", sr_entries);
-		srwm = total_size - sr_entries;
-		if (srwm < 0)
-			srwm = 1;
+
+		sr_params.default_wm = 32;
+		sr_params.guard_size = 8;
+
+		srwm = intel_calculate_wm(sr_clock, &sr_params,
+						pixel_size,
+						sr_latency_ns);
+		DRM_DEBUG_KMS("self-refresh watermark: %d\n", srwm);
 		I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN | (srwm & 0x3f));
 	}
 
-- 
1.5.4.5




More information about the Intel-gfx mailing list