drm/i915: Enable aspect/centering panel fitting for Ironlake.
diff mbox

Message ID 1280930641-24502-1-git-send-email-chris@chris-wilson.co.uk
State Deferred, archived
Headers show

Commit Message

Chris Wilson Aug. 4, 2010, 2:04 p.m. UTC
None

Patch
diff mbox

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index ad8dab5..6da15d8 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -610,6 +610,8 @@  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 07f893f..9b5fab4 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1914,15 +1914,13 @@  static void ironlake_crtc_dpms(struct drm_crtc *crtc, int mode)
 		/* Enable panel fitting for LVDS */
 		if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS)
 		    || HAS_eDP || intel_pch_has_edp(crtc)) {
-			temp = I915_READ(pf_ctl_reg);
-			I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
-
-			/* currently full aspect */
-			I915_WRITE(pf_win_pos, 0);
-
-			I915_WRITE(pf_win_size,
-				   (dev_priv->panel_fixed_mode->hdisplay << 16) |
-				   (dev_priv->panel_fixed_mode->vdisplay));
+			if (dev_priv->pch_pf_size) {
+				temp = I915_READ(pf_ctl_reg);
+				I915_WRITE(pf_ctl_reg, temp | PF_ENABLE | PF_FILTER_MED_3x3);
+				I915_WRITE(pf_win_pos, dev_priv->pch_pf_pos);
+				I915_WRITE(pf_win_size, dev_priv->pch_pf_size);
+			} else
+				I915_WRITE(pf_ctl_reg, temp & ~PF_ENABLE);
 		}
 
 		/* Enable CPU pipe */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 312ac30..abbe32e 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -218,6 +218,68 @@  static inline u32 panel_fitter_scaling(u32 source, u32 target)
 	return (FACTOR * ratio + FACTOR/2) / FACTOR;
 }
 
+static bool
+intel_pch_lvds_mode_fixup(struct intel_lvds *intel_lvds,
+			  struct drm_display_mode *mode,
+			  struct drm_display_mode *adjusted_mode)
+{
+	struct drm_device *dev = intel_lvds->base.enc.dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
+	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 (intel_lvds->fitting_mode) {
+	case DRM_MODE_SCALE_CENTER:
+		width = mode->hdisplay;
+		height = mode->vdisplay;
+		x = (fixed_mode->hdisplay - width + 1)/2;
+		y = (fixed_mode->vdisplay - height + 1)/2;
+		break;
+
+	case DRM_MODE_SCALE_ASPECT:
+		/* Scale but preserve the aspect ratio */
+		{
+			u32 scaled_width = fixed_mode->hdisplay * mode->vdisplay;
+			u32 scaled_height = mode->hdisplay * fixed_mode->vdisplay;
+			if (scaled_width > scaled_height) { /* pillar */
+				width = scaled_height / mode->vdisplay;
+				x = (fixed_mode->hdisplay - width + 1) / 2;
+				y = 0;
+				height = fixed_mode->vdisplay;
+			} else if (scaled_width < scaled_height) { /* letter */
+				height = scaled_width / mode->hdisplay;
+				y = (fixed_mode->vdisplay - height + 1) / 2;
+				x = 0;
+				width = fixed_mode->hdisplay;
+			} else {
+				x = y = 0;
+				width = fixed_mode->hdisplay;
+				height = fixed_mode->vdisplay;
+			}
+		}
+		break;
+
+	default:
+	case DRM_MODE_SCALE_FULLSCREEN:
+		x = y = 0;
+		width = fixed_mode->hdisplay;
+		height = fixed_mode->vdisplay;
+		break;
+	}
+
+done:
+	dev_priv->pch_pf_pos = (x << 16) | y;
+	dev_priv->pch_pf_size = (width << 16) | height;
+	return true;
+}
+
 static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode)
@@ -267,6 +329,10 @@  static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 	adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
 	drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
 
+	if (HAS_PCH_SPLIT(dev))
+		return intel_pch_lvds_mode_fixup(intel_lvds,
+						 mode, adjusted_mode);
+
 	/* Make sure pre-965s set dither correctly */
 	if (!IS_I965G(dev)) {
 		if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
@@ -278,10 +344,6 @@  static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
 	    adjusted_mode->vdisplay == mode->vdisplay)
 		goto out;
 
-	/* full screen scale for now */
-	if (HAS_PCH_SPLIT(dev))
-		goto out;
-
 	/* 965+ wants fuzzy fitting */
 	if (IS_I965G(dev))
 		pfit_control |= ((intel_crtc->pipe << PFIT_PIPE_SHIFT) |