[Intel-gfx] [PATCH] drm/i915: Enable panel-fitter for any mode != adjusted mode

Chris Wilson chris at chris-wilson.co.uk
Thu Dec 16 22:10:07 CET 2010


Continuing the Libretto W100 saga, in order to use a non-native mode on
the SDVO panel, I need to engage the panel fitter for that pipe. So try
to do so in a generic fashion such that we use the panel fitter to fixup
any input (adjusted) mode that is not equal to the output mode.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 -
 drivers/gpu/drm/i915/intel_display.c |   69 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/i915/intel_dp.c      |    2 -
 drivers/gpu/drm/i915/intel_drv.h     |   20 ++++++++--
 drivers/gpu/drm/i915/intel_lvds.c    |    6 +--
 drivers/gpu/drm/i915/intel_panel.c   |   61 ------------------------------
 6 files changed, 82 insertions(+), 78 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 30780f2..80a243e 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -644,8 +644,6 @@ typedef struct drm_i915_private {
 	struct sdvo_device_mapping sdvo_mappings[2];
 	/* indicate whether the LVDS_BORDER should be enabled or not */
 	unsigned int lvds_border_bits;
-	/* Panel fitter placement and size for Ironlake+ */
-	u32 pch_pf_pos, pch_pf_size;
 
 	struct drm_crtc *plane_to_crtc_mapping[2];
 	struct drm_crtc *pipe_to_crtc_mapping[2];
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8645a97..2b2c010 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2024,6 +2024,63 @@ static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 		   atomic_read(&obj->pending_flip) == 0);
 }
 
+static bool pch_pf_enable(struct intel_crtc *crtc,
+			  int *x, int *y, int *width, int *height)
+{
+	struct drm_device *dev = crtc->base.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	int htotal = I915_READ(HTOTAL(crtc->pipe)) & 0xffff;
+	int vtotal = I915_READ(VTOTAL(crtc->pipe)) & 0xffff;
+	int src = I915_READ(PIPESRC(crtc->pipe));
+	int src_width, src_height;
+	int dst_width, dst_height;
+
+	/* Native modes don't need fitting */
+	if ((htotal << 16 | vtotal) == src)
+		return false;
+
+	src_width = (src >> 16) + 1;
+	src_height = (src & 0xffff) + 1;
+	dst_width = (htotal & 0xffff) + 1;
+	dst_height = (vtotal & 0xffff) + 1;
+
+	switch (crtc->fitting_mode) {
+	case DRM_MODE_SCALE_CENTER:
+		*width = src_width;
+		*height = src_height;
+		*x = (dst_width - src_width + 1)/2;
+		*y = (dst_height - src_height + 1)/2;
+		break;
+
+	default:
+	case DRM_MODE_SCALE_ASPECT:
+		/* Scale but preserve the aspect ratio */
+		{
+			u32 scaled_width = dst_width * src_height;
+			u32 scaled_height = src_width * dst_height;
+			if (scaled_width > scaled_height) { /* pillar */
+				*width = scaled_height / src_height;
+				*x = (dst_width - *width + 1) / 2;
+				*y = 0;
+				*height = dst_height;
+			} else if (scaled_width < scaled_height) { /* letter */
+				*height = scaled_width / src_width;
+				*y = (dst_height - *height + 1) / 2;
+				*x = 0;
+				*width = dst_width;
+			} else {
+			case DRM_MODE_SCALE_FULLSCREEN:
+				*x = *y = 0;
+				*width = dst_width;
+				*height = dst_height;
+			}
+		}
+		break;
+	}
+
+	return true;
+}
+
 static void ironlake_crtc_enable(struct drm_crtc *crtc)
 {
 	struct drm_device *dev = crtc->dev;
@@ -2031,6 +2088,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	int pipe = intel_crtc->pipe;
 	int plane = intel_crtc->plane;
+	int x, y, width, height;
 	u32 reg, temp;
 
 	if (intel_crtc->active)
@@ -2047,9 +2105,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
 	ironlake_fdi_enable(crtc);
 
-	/* Enable panel fitting for LVDS */
-	if (dev_priv->pch_pf_size &&
-	    (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP)) {
+	if (pch_pf_enable(intel_crtc, &x, &y, &width, &height)) {
 		/* Force use of hard-coded filter coefficients
 		 * as some pre-programmed values are broken,
 		 * e.g. x201.
@@ -2057,9 +2113,9 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 		I915_WRITE(pipe ? PFB_CTL_1 : PFA_CTL_1,
 			   PF_ENABLE | PF_FILTER_MED_3x3);
 		I915_WRITE(pipe ? PFB_WIN_POS : PFA_WIN_POS,
-			   dev_priv->pch_pf_pos);
+			   x << 16 | y);
 		I915_WRITE(pipe ? PFB_WIN_SZ : PFA_WIN_SZ,
-			   dev_priv->pch_pf_size);
+			   width << 16 | height);
 	}
 
 	/* Enable CPU pipe */
@@ -2631,6 +2687,9 @@ static bool intel_crtc_mode_fixup(struct drm_crtc *crtc,
 	if (adjusted_mode->crtc_htotal == 0)
 		drm_mode_set_crtcinfo(adjusted_mode, 0);
 
+	to_intel_crtc(crtc)->fitting_mode =
+		intel_mode_get_panel_fitting(adjusted_mode);
+
 	return true;
 }
 
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 1dc6040..f452714 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -598,8 +598,6 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
 
 	if (is_edp(intel_dp) && dev_priv->panel_fixed_mode) {
 		intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
-		intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
-					mode, adjusted_mode);
 		/*
 		 * the mode->clock is used to calculate the Data&Link M/N
 		 * of the pipe. For the eDP the fixed clock should be used.
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index acdea65..8b29fce 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -110,6 +110,8 @@
 /* drm_display_mode->private_flags */
 #define INTEL_MODE_PIXEL_MULTIPLIER_SHIFT (0x0)
 #define INTEL_MODE_PIXEL_MULTIPLIER_MASK (0xf << INTEL_MODE_PIXEL_MULTIPLIER_SHIFT)
+#define INTEL_MODE_PANEL_FITTING_SHIFT (0x4)
+#define INTEL_MODE_PANEL_FITTING_MASK (0xf << INTEL_MODE_PANEL_FITTING_SHIFT)
 
 static inline void
 intel_mode_set_pixel_multiplier(struct drm_display_mode *mode,
@@ -125,6 +127,19 @@ intel_mode_get_pixel_multiplier(const struct drm_display_mode *mode)
 	return (mode->private_flags & INTEL_MODE_PIXEL_MULTIPLIER_MASK) >> INTEL_MODE_PIXEL_MULTIPLIER_SHIFT;
 }
 
+static inline void
+intel_mode_set_panel_fitting(struct drm_display_mode *mode,
+			     int pf_mode)
+{
+	mode->private_flags |= pf_mode << INTEL_MODE_PANEL_FITTING_SHIFT;
+}
+
+static inline int
+intel_mode_get_panel_fitting(const struct drm_display_mode *mode)
+{
+	return (mode->private_flags & INTEL_MODE_PANEL_FITTING_MASK)>> INTEL_MODE_PANEL_FITTING_SHIFT;
+}
+
 struct intel_framebuffer {
 	struct drm_framebuffer base;
 	struct drm_i915_gem_object *obj;
@@ -158,6 +173,7 @@ struct intel_crtc {
 	enum plane plane;
 	u8 lut_r[256], lut_g[256], lut_b[256];
 	int dpms_mode;
+	int fitting_mode;
 	bool active; /* is the crtc on? independent of the dpms mode */
 	bool busy; /* is scanout buffer being updated frequently? */
 	struct timer_list idle_timer;
@@ -250,10 +266,6 @@ extern bool intel_encoder_is_pch_edp(struct drm_encoder *encoder);
 /* intel_panel.c */
 extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 				   struct drm_display_mode *adjusted_mode);
-extern void intel_pch_panel_fitting(struct drm_device *dev,
-				    int fitting_mode,
-				    struct drm_display_mode *mode,
-				    struct drm_display_mode *adjusted_mode);
 extern u32 intel_panel_get_max_backlight(struct drm_device *dev);
 extern u32 intel_panel_get_backlight(struct drm_device *dev);
 extern void intel_panel_set_backlight(struct drm_device *dev, u32 level);
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index aa23070..55c9ac3 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -255,12 +255,10 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 	 * of the original mode.
 	 */
 	intel_fixed_panel_mode(intel_lvds->fixed_mode, adjusted_mode);
+	intel_mode_set_panel_fitting(adjusted_mode, intel_lvds->fitting_mode);
 
-	if (HAS_PCH_SPLIT(dev)) {
-		intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
-					mode, adjusted_mode);
+	if (HAS_PCH_SPLIT(dev))
 		return true;
-	}
 
 	/* Make sure pre-965s set dither correctly */
 	if (INTEL_INFO(dev)->gen < 4) {
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 7350ec2..4dda915 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -51,67 +51,6 @@ intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
 	drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
 }
 
-/* adjusted_mode has been preset to be the panel's fixed mode */
-void
-intel_pch_panel_fitting(struct drm_device *dev,
-			int fitting_mode,
-			struct drm_display_mode *mode,
-			struct drm_display_mode *adjusted_mode)
-{
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	int x, y, width, height;
-
-	x = y = width = height = 0;
-
-	/* Native modes don't need fitting */
-	if (adjusted_mode->hdisplay == mode->hdisplay &&
-	    adjusted_mode->vdisplay == mode->vdisplay)
-		goto done;
-
-	switch (fitting_mode) {
-	case DRM_MODE_SCALE_CENTER:
-		width = mode->hdisplay;
-		height = mode->vdisplay;
-		x = (adjusted_mode->hdisplay - width + 1)/2;
-		y = (adjusted_mode->vdisplay - height + 1)/2;
-		break;
-
-	case DRM_MODE_SCALE_ASPECT:
-		/* Scale but preserve the aspect ratio */
-		{
-			u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
-			u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
-			if (scaled_width > scaled_height) { /* pillar */
-				width = scaled_height / mode->vdisplay;
-				x = (adjusted_mode->hdisplay - width + 1) / 2;
-				y = 0;
-				height = adjusted_mode->vdisplay;
-			} else if (scaled_width < scaled_height) { /* letter */
-				height = scaled_width / mode->hdisplay;
-				y = (adjusted_mode->vdisplay - height + 1) / 2;
-				x = 0;
-				width = adjusted_mode->hdisplay;
-			} else {
-				x = y = 0;
-				width = adjusted_mode->hdisplay;
-				height = adjusted_mode->vdisplay;
-			}
-		}
-		break;
-
-	default:
-	case DRM_MODE_SCALE_FULLSCREEN:
-		x = y = 0;
-		width = adjusted_mode->hdisplay;
-		height = adjusted_mode->vdisplay;
-		break;
-	}
-
-done:
-	dev_priv->pch_pf_pos = (x << 16) | y;
-	dev_priv->pch_pf_size = (width << 16) | height;
-}
-
 static int is_backlight_combination_mode(struct drm_device *dev)
 {
 	struct drm_i915_private *dev_priv = dev->dev_private;
-- 
1.7.2.3




More information about the Intel-gfx mailing list