From: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> They're named "underscan hborder" and "underscan vborder". The properties accept values from 0 to 100, where 0 is "don't compensate" and 100 is "shrink the screen as much as possible" (not necessarily 100 pixels). V2: Rename to "underscan hborder" and "underscan vborder" to match the radeon properties. Note that we have a range of 0-100 (not pixels) and radeon has a range of 0-128 (pixels). Fix compilation on 32 bit systems. Signed-off-by: Paulo Zanoni <paulo.r.zanoni@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 2 + drivers/gpu/drm/i915/intel_display.c | 117 +++++++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 1 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 98d7d74..0373723 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -780,6 +780,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 *underscan_hborder_property; + struct drm_property *underscan_vborder_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 d621a54..b80c508 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c @@ -5621,6 +5621,84 @@ 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_64 = 0, prop_y_64 = 0; + uint32_t prop_x, prop_y; + int tot_x, tot_y, src_x, src_y, dst_x, dst_y, pos_x, pos_y; + u32 reg; + + drm_object_property_get_value(&crtc->base, + dev_priv->underscan_hborder_property, + &prop_x_64); + drm_object_property_get_value(&crtc->base, + dev_priv->underscan_vborder_property, + &prop_y_64); + + /* This is needed to avoid 64 bit division later. Values should be + * between 0 and 100, so no problem. */ + prop_x = prop_x_64; + prop_y = prop_y_64; + + 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, @@ -6066,6 +6144,8 @@ static int ironlake_crtc_mode_set(struct drm_crtc *crtc, intel_update_watermarks(dev); + ironlake_crtc_overscan_compensate(crtc); + return ret; } @@ -7667,6 +7747,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->underscan_hborder_property || + property == dev_priv->underscan_vborder_property) { + drm_object_property_set_value(&crtc->base, property, val); + ironlake_crtc_overscan_compensate(crtc); + } return 0; } @@ -7709,6 +7794,34 @@ static void intel_attach_rotation_property(struct drm_crtc *crtc) drm_object_attach_property(&crtc->base, 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_h, *prop_v; + + prop_h = dev_priv->underscan_hborder_property; + if (prop_h == NULL) { + prop_h = drm_property_create_range(dev, 0, "underscan hborder", + 0, 100); + if (prop_h != NULL) + dev_priv->underscan_hborder_property = prop_h; + } + + prop_v = dev_priv->underscan_vborder_property; + if (prop_v == NULL) { + prop_v = drm_property_create_range(dev, 0, "underscan vborder", + 0, 100); + if (prop_v != NULL) + dev_priv->underscan_vborder_property = prop_v; + } + + if (prop_h) + drm_object_attach_property(&crtc->base, prop_h, 0); + if (prop_v) + drm_object_attach_property(&crtc->base, prop_v, 0); +} + static void intel_crtc_init(struct drm_device *dev, int pipe) { drm_i915_private_t *dev_priv = dev->dev_private; @@ -7728,8 +7841,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 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel