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

Alex Deucher alexdeucher at gmail.com
Tue Mar 20 08:00:52 PDT 2012


On Tue, Mar 20, 2012 at 10:48 AM, Paulo Zanoni <przanoni at gmail.com> wrote:
> 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".

FWIW, the radeon driver already exposes something similar.  It might
be worthwhile to try and use consistent naming and property options.

We have an "underscan" property:

static struct drm_prop_enum_list radeon_underscan_enum_list[] =
{       { UNDERSCAN_OFF, "off" },
        { UNDERSCAN_ON, "on" },
        { UNDERSCAN_AUTO, "auto" },
};

"off" disables underscan
"on" forces it on
"auto" tries to enable/disable underscan automatically based on EDID
information.  RIght now we just check if the monitor is HDMI and the
mode is an standard HD mode, but IIRC, there is also a CEA extension
block that is supposed to tell you whether the monitor is overscanning
or not.

Then we have "underscan hborder" and "underscan vborder" to adjust the
amount of underscan.  See radeon_display.c in the kernel.

Alex

>
> 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
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list