[PATCH 5/5] drm/i915: add overscan compensation CRTC properties

Paulo Zanoni przanoni at gmail.com
Tue Mar 20 07:48:32 PDT 2012


From: Paulo Zanoni <paulo.r.zanoni at intel.com>

They're named "underscan x" and "underscan y". The properties accept
values from 0 to 100, where 0 is "don't compensate" and 100 is "shrink
the screen as much as possible".

Signed-off-by: Paulo Zanoni <paulo.r.zanoni at intel.com>
---
 drivers/gpu/drm/i915/i915_drv.h      |    2 +
 drivers/gpu/drm/i915/intel_display.c |  110 +++++++++++++++++++++++++++++++++-
 2 files changed, 111 insertions(+), 1 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 7994c4f..fb9062d 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -781,6 +781,8 @@ typedef struct drm_i915_private {
 	struct drm_property *broadcast_rgb_property;
 	struct drm_property *force_audio_property;
 	struct drm_property *rotation_property;
+	struct drm_property *x_underscan_property;
+	struct drm_property *y_underscan_property;
 } drm_i915_private_t;
 
 enum hdmi_force_audio {
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 4842de8..b36572d 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -5620,6 +5620,77 @@ static int ironlake_get_refclk(struct drm_crtc *crtc)
 	return 120000;
 }
 
+/*
+ * The overscan compensation property (aka underscan property) has values from 0
+ * to 100, where 0 means that the compensation is disabled and 100 means the
+ * screen should shrink as much as possible. The current maximum supported value
+ * (from the specifications) is "src/dst < 1.125".
+ *
+ * In short:
+ * - if val == 0   -> dst = src
+ * - if val == 100 -> dst = src * 8/9
+ * - dst can't be odd
+ * - dst can't be < src * 8 / (double)9
+ * - so the formulae, not considering rounding, should be:
+ *   - dst = 9*src - prop*src/100 / 9
+ */
+static void ironlake_crtc_overscan_compensate(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+	int pipe = intel_crtc->pipe;
+	uint64_t prop_x = 0, prop_y = 0;
+	int tot_x, tot_y, src_x, src_y, dst_x, dst_y, pos_x, pos_y;
+	u32 reg;
+
+	drm_crtc_property_get_value(crtc, dev_priv->x_underscan_property,
+				    &prop_x);
+	drm_crtc_property_get_value(crtc, dev_priv->y_underscan_property,
+				    &prop_y);
+
+	if (prop_x == 0 && prop_y == 0 &&
+	    !(dev_priv->pch_pf_size &&
+	      (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) || HAS_eDP))) {
+		I915_WRITE(PF_CTL(pipe), 0);
+		I915_WRITE(PF_WIN_POS(pipe), 0);
+		I915_WRITE(PF_WIN_SZ(pipe), 0);
+		return;
+	}
+
+	reg = I915_READ(HTOTAL(pipe));
+	tot_x = (reg & 0xFFF) + 1;
+	reg = I915_READ(VTOTAL(pipe));
+	tot_y = (reg & 0xFFF) + 1;
+	reg = I915_READ(PIPESRC(pipe));
+	src_x = ((reg >> 16) & 0xFFF) + 1;
+	src_y = (reg & 0xFFF) + 1;
+
+	dst_x = (src_x * 9 - src_x * prop_x / 100 + 8) / 9;
+	dst_x &= ~1;
+	if (dst_x < ((src_x * 8 + 8) / 9))
+		dst_x += 2;
+
+	dst_y = (src_y * 9 - src_y * prop_y / 100 + 8) / 9;
+	dst_y &= ~1;
+	if (dst_y < ((src_y * 8 + 8) / 9))
+		dst_y += 2;
+
+	pos_x = (tot_x - dst_x) / 2;
+	pos_y = (tot_y - dst_y) / 2;
+
+	if (pos_x == 1)
+		pos_x = 0;
+	reg = I915_READ(PIPECONF(pipe));
+	if ((reg & PIPECONF_INTERLACE_MASK) != PIPECONF_PROGRESSIVE)
+		pos_y &= ~1;
+
+	I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
+	I915_WRITE(PF_WIN_POS(pipe), (pos_x << 16) | pos_y);
+	I915_WRITE(PF_WIN_SZ(pipe), (dst_x << 16) | dst_y);
+}
+
+
 static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 				  struct drm_display_mode *mode,
 				  struct drm_display_mode *adjusted_mode,
@@ -6065,6 +6136,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc,
 
 	intel_update_watermarks(dev);
 
+	ironlake_crtc_overscan_compensate(crtc);
+
 	return ret;
 }
 
@@ -7666,6 +7739,11 @@ static int intel_crtc_set_property(struct drm_crtc *crtc,
 
 	if (property == dev_priv->rotation_property)
 		intel_crtc_set_rotation(crtc, val);
+	if (property == dev_priv->x_underscan_property ||
+	    property == dev_priv->y_underscan_property) {
+		drm_crtc_property_set_value(crtc, property, val);
+		ironlake_crtc_overscan_compensate(crtc);
+	}
 	return 0;
 }
 
@@ -7708,6 +7786,34 @@ static void intel_attach_rotation_property(struct drm_crtc *crtc)
 	drm_crtc_attach_property(crtc, prop, 0);
 }
 
+static void intel_attach_underscan_properties(struct drm_crtc *crtc)
+{
+	struct drm_device *dev = crtc->dev;
+	struct drm_i915_private *dev_priv = dev->dev_private;
+	struct drm_property *prop_x, *prop_y;
+
+	prop_x = dev_priv->x_underscan_property;
+	if (prop_x == NULL) {
+		prop_x = drm_property_create_range(dev, 0, "underscan x",
+						   0, 100);
+		if (prop_x != NULL)
+			dev_priv->x_underscan_property = prop_x;
+	}
+
+	prop_y = dev_priv->y_underscan_property;
+	if (prop_y == NULL) {
+		prop_y = drm_property_create_range(dev, 0, "underscan y",
+						   0, 100);
+		if (prop_y != NULL)
+			dev_priv->y_underscan_property = prop_y;
+	}
+
+	if (prop_x)
+		drm_crtc_attach_property(crtc, prop_x, 0);
+	if (prop_y)
+		drm_crtc_attach_property(crtc, prop_y, 0);
+}
+
 static void intel_crtc_init(struct drm_device *dev, int pipe)
 {
 	drm_i915_private_t *dev_priv = dev->dev_private;
@@ -7727,8 +7833,10 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 		intel_crtc->lut_b[i] = i;
 	}
 
-	if (INTEL_INFO(dev)->gen >= 5)
+	if (INTEL_INFO(dev)->gen >= 5) {
 		intel_attach_rotation_property(&intel_crtc->base);
+		intel_attach_underscan_properties(&intel_crtc->base);
+	}
 
 	/* Swap pipes & planes for FBC on pre-965 */
 	intel_crtc->pipe = pipe;
-- 
1.7.9.1



More information about the dri-devel mailing list