[Intel-gfx] [Resend] [Patch_v2] DRM/I915: Sync the LVDS panel fitting property with 2D driver

yakui_zhao yakui.zhao at intel.com
Tue May 26 08:12:04 CEST 2009


On Thu, 2009-05-21 at 14:45 +0800, yakui_zhao wrote:
> This covers:
>      a. create the scaling mode property and attach it to LVDS
>      b. add the support of panel fitting property for LVDS
>      c. update the display mode according to the panel fitting mode
> 
>      v2: the drm_calloc/drm_free is replaced by kzalloc/kfree based
> on Eric's suggestion.
Hi, Eric
    How about this patch?
    If this patch is not applied, there is no panel fitting property in
KMS mode.
	Even when we can add some modes for LVDS output device, we still can't
use the effect of panel fitting after changing the different mode.

Best regards
	Yakui
> 
> Signed-off-by: Zhao Yakui <yakui.zhao at intel.com>
> ---
>  drivers/gpu/drm/i915/i915_reg.h   |   16 ++
>  drivers/gpu/drm/i915/intel_lvds.c |  282 +++++++++++++++++++++++++++++++++++---
>  2 files changed, 277 insertions(+), 21 deletions(-)
> 
> Index: linux-2.6/drivers/gpu/drm/i915/i915_reg.h
> ===================================================================
> --- linux-2.6.orig/drivers/gpu/drm/i915/i915_reg.h      2009-05-18 10:55:09.000000000 +0800
> +++ linux-2.6/drivers/gpu/drm/i915/i915_reg.h   2009-05-21 09:14:46.000000000 +0800
> @@ -820,9 +820,25 @@
>  #define   HORIZ_INTERP_MASK    (3 << 6)
>  #define   HORIZ_AUTO_SCALE     (1 << 5)
>  #define   PANEL_8TO6_DITHER_ENABLE (1 << 3)
> +#define   PFIT_FILTER_FUZZY    (0 << 24)
> +#define   PFIT_SCALING_AUTO    (0 << 26)
> +#define   PFIT_SCALING_PROGRAMMED (1 << 26)
> +#define   PFIT_SCALING_PILLAR  (2 << 26)
> +#define   PFIT_SCALING_LETTER  (3 << 26)
>  #define PFIT_PGM_RATIOS        0x61234
>  #define   PFIT_VERT_SCALE_MASK                 0xfff00000
>  #define   PFIT_HORIZ_SCALE_MASK                        0x0000fff0
> +/* Pre-965 */
> +#define                PFIT_VERT_SCALE_SHIFT           20
> +#define                PFIT_VERT_SCALE_MASK            0xfff00000
> +#define                PFIT_HORIZ_SCALE_SHIFT          4
> +#define                PFIT_HORIZ_SCALE_MASK           0x0000fff0
> +/* 965+ */
> +#define                PFIT_VERT_SCALE_SHIFT_965       16
> +#define                PFIT_VERT_SCALE_MASK_965        0x1fff0000
> +#define                PFIT_HORIZ_SCALE_SHIFT_965      0
> +#define                PFIT_HORIZ_SCALE_MASK_965       0x00001fff
> +
>  #define PFIT_AUTO_RATIOS 0x61238
> 
>  /* Backlight control */
> Index: linux-2.6/drivers/gpu/drm/i915/intel_lvds.c
> ===================================================================
> --- linux-2.6.orig/drivers/gpu/drm/i915/intel_lvds.c    2009-05-18 10:55:09.000000000 +0800
> +++ linux-2.6/drivers/gpu/drm/i915/intel_lvds.c 2009-05-21 09:14:46.000000000 +0800
> @@ -37,6 +37,21 @@
>  #include "i915_drm.h"
>  #include "i915_drv.h"
> 
> +/*
> + * the following four scaling options are defined.
> + * #define DRM_MODE_SCALE_NON_GPU      0
> + * #define DRM_MODE_SCALE_FULLSCREEN   1
> + * #define DRM_MODE_SCALE_NO_SCALE     2
> + * #define DRM_MODE_SCALE_ASPECT       3
> + */
> +
> +/* Private structure for the integrated LVDS support */
> +struct intel_lvds_priv {
> +       int fitting_mode;
> +       u32 pfit_control;
> +       u32 pfit_pgm_ratios;
> +};
> +
>  /**
>   * Sets the backlight level.
>   *
> @@ -160,10 +175,24 @@
>                                   struct drm_display_mode *mode,
>                                   struct drm_display_mode *adjusted_mode)
>  {
> +       /*
> +        * float point operation is not supported . So the PANEL_RATIO_FACTOR
> +        * is defined, which can avoid the float point computation when
> +        * calculating the panel ratio.
> +        */
> +#define PANEL_RATIO_FACTOR 8192
>         struct drm_device *dev = encoder->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
>         struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
>         struct drm_encoder *tmp_encoder;
> +       struct intel_output *intel_output = enc_to_intel_output(encoder);
> +       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
> +       u32 pfit_control = 0, pfit_pgm_ratios = 0;
> +       int left_border = 0, right_border = 0, top_border = 0;
> +       int bottom_border = 0;
> +       bool border = 0;
> +       int panel_ratio, desired_ratio, vert_scale, horiz_scale;
> +       int horiz_ratio, vert_ratio;
> 
>         /* Should never happen!! */
>         if (!IS_I965G(dev) && intel_crtc->pipe == 0) {
> @@ -179,7 +208,9 @@
>                         return false;
>                 }
>         }
> -
> +       /* If we don't have a panel mode, there is nothing we can do */
> +       if (dev_priv->panel_fixed_mode == NULL)
> +               return true;
>         /*
>          * If we have timings from the BIOS for the panel, put them in
>          * to the adjusted mode.  The CRTC will be set up for this mode,
> @@ -203,6 +234,191 @@
>                 drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
>         }
> 
> +       /* Make sure pre-965s set dither correctly */
> +       if (!IS_I965G(dev)) {
> +               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
> +                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> +       }
> +
> +       /* Native modes don't need fitting */
> +       if (adjusted_mode->hdisplay == mode->hdisplay &&
> +                       adjusted_mode->vdisplay == mode->vdisplay) {
> +               pfit_pgm_ratios = 0;
> +               border = 0;
> +               goto out;
> +       }
> +
> +       /* 965+ wants fuzzy fitting */
> +       if (IS_I965G(dev))
> +               pfit_control |= (intel_crtc->pipe << PFIT_PIPE_SHIFT) |
> +                                       PFIT_FILTER_FUZZY;
> +
> +       /*
> +        * Deal with panel fitting options. Figure out how to stretch the
> +        * image based on its aspect ratio & the current panel fitting mode.
> +        */
> +       panel_ratio = adjusted_mode->hdisplay * PANEL_RATIO_FACTOR /
> +                               adjusted_mode->vdisplay;
> +       desired_ratio = mode->hdisplay * PANEL_RATIO_FACTOR /
> +                               mode->vdisplay;
> +       /*
> +        * Enable automatic panel scaling for non-native modes so that they fill
> +        * the screen.  Should be enabled before the pipe is enabled, according
> +        * to register description and PRM.
> +        * Change the value here to see the borders for debugging
> +        */
> +       I915_WRITE(BCLRPAT_A, 0);
> +       I915_WRITE(BCLRPAT_B, 0);
> +
> +       switch (lvds_priv->fitting_mode) {
> +       case DRM_MODE_SCALE_NO_SCALE:
> +               /*
> +                * For centered modes, we have to calculate border widths &
> +                * heights and modify the values programmed into the CRTC.
> +                */
> +               left_border = (adjusted_mode->hdisplay - mode->hdisplay) / 2;
> +               right_border = left_border;
> +               if (mode->hdisplay & 1)
> +                       right_border++;
> +               top_border = (adjusted_mode->vdisplay - mode->vdisplay) / 2;
> +               bottom_border = top_border;
> +               if (mode->vdisplay & 1)
> +                       bottom_border++;
> +               /* Set active & border values */
> +               adjusted_mode->crtc_hdisplay = mode->hdisplay;
> +               adjusted_mode->crtc_hblank_start = mode->hdisplay +
> +                                               right_border - 1;
> +               adjusted_mode->crtc_hblank_end = adjusted_mode->crtc_htotal -
> +                                               left_border - 1;
> +               adjusted_mode->crtc_hsync_start =
> +                               adjusted_mode->crtc_hblank_start;
> +               adjusted_mode->crtc_hsync_end =
> +                               adjusted_mode->crtc_hblank_end;
> +               adjusted_mode->crtc_vdisplay = mode->vdisplay;
> +               adjusted_mode->crtc_vblank_start = mode->vdisplay +
> +                                               bottom_border - 1;
> +               adjusted_mode->crtc_vblank_end = adjusted_mode->crtc_vtotal -
> +                                               top_border - 1;
> +               adjusted_mode->crtc_vsync_start =
> +                               adjusted_mode->crtc_vblank_start;
> +               adjusted_mode->crtc_vsync_end =
> +                               adjusted_mode->crtc_vblank_end;
> +               border = 1;
> +               break;
> +       case DRM_MODE_SCALE_ASPECT:
> +               /* Scale but preserve the spect ratio */
> +               pfit_control |= PFIT_ENABLE;
> +               if (IS_I965G(dev)) {
> +                       /* 965+ is easy, it does everything in hw */
> +                       if (panel_ratio > desired_ratio)
> +                               pfit_control |= PFIT_SCALING_PILLAR;
> +                       else if (panel_ratio < desired_ratio)
> +                               pfit_control |= PFIT_SCALING_LETTER;
> +                       else
> +                               pfit_control |= PFIT_SCALING_AUTO;
> +               } else {
> +                       /*
> +                        * For earlier chips we have to calculate the scaling
> +                        * ratio by hand and program it into the
> +                        * PFIT_PGM_RATIO register
> +                        */
> +                       u32 horiz_bits, vert_bits, bits = 12;
> +                       horiz_ratio = mode->hdisplay * PANEL_RATIO_FACTOR/
> +                                               adjusted_mode->hdisplay;
> +                       vert_ratio = mode->vdisplay * PANEL_RATIO_FACTOR/
> +                                               adjusted_mode->vdisplay;
> +                       horiz_scale = adjusted_mode->hdisplay *
> +                                       PANEL_RATIO_FACTOR / mode->hdisplay;
> +                       vert_scale = adjusted_mode->vdisplay *
> +                                       PANEL_RATIO_FACTOR / mode->vdisplay;
> +
> +                       /* retain aspect ratio */
> +                       if (panel_ratio > desired_ratio) { /* Pillar */
> +                               u32 scaled_width;
> +                               scaled_width = mode->hdisplay * vert_scale /
> +                                               PANEL_RATIO_FACTOR;
> +                               horiz_ratio = vert_ratio;
> +                               pfit_control |= (VERT_AUTO_SCALE |
> +                                                VERT_INTERP_BILINEAR |
> +                                                HORIZ_INTERP_BILINEAR);
> +                               /* Pillar will have left/right borders */
> +                               left_border = (adjusted_mode->hdisplay -
> +                                               scaled_width) / 2;
> +                               right_border = left_border;
> +                               if (mode->hdisplay & 1) /* odd resolutions */
> +                                       right_border++;
> +                               adjusted_mode->crtc_hdisplay = scaled_width;
> +                               adjusted_mode->crtc_hblank_start =
> +                                       scaled_width + right_border - 1;
> +                               adjusted_mode->crtc_hblank_end =
> +                                adjusted_mode->crtc_htotal - left_border - 1;
> +                               adjusted_mode->crtc_hsync_start =
> +                                       adjusted_mode->crtc_hblank_start;
> +                               adjusted_mode->crtc_hsync_end =
> +                                       adjusted_mode->crtc_hblank_end;
> +                               border = 1;
> +                       } else if (panel_ratio < desired_ratio) { /* letter */
> +                               u32 scaled_height = mode->vdisplay *
> +                                       horiz_scale / PANEL_RATIO_FACTOR;
> +                               vert_ratio = horiz_ratio;
> +                               pfit_control |= (HORIZ_AUTO_SCALE |
> +                                                VERT_INTERP_BILINEAR |
> +                                                HORIZ_INTERP_BILINEAR);
> +                               /* Letterbox will have top/bottom border */
> +                               top_border = (adjusted_mode->vdisplay -
> +                                       scaled_height) / 2;
> +                               bottom_border = top_border;
> +                               if (mode->vdisplay & 1)
> +                                       bottom_border++;
> +                               adjusted_mode->crtc_vdisplay = scaled_height;
> +                               adjusted_mode->crtc_vblank_start =
> +                                       scaled_height + bottom_border - 1;
> +                               adjusted_mode->crtc_vblank_end =
> +                                adjusted_mode->crtc_vtotal - top_border - 1;
> +                               adjusted_mode->crtc_vsync_start =
> +                                       adjusted_mode->crtc_vblank_start;
> +                               adjusted_mode->crtc_vsync_end =
> +                                       adjusted_mode->crtc_vblank_end;
> +                               border = 1;
> +                       } else {
> +                       /* Aspects match, Let hw scale both directions */
> +                               pfit_control |= (VERT_AUTO_SCALE |
> +                                                HORIZ_AUTO_SCALE |
> +                                                VERT_INTERP_BILINEAR |
> +                                                HORIZ_INTERP_BILINEAR);
> +                       }
> +                       horiz_bits = (1 << bits) * horiz_ratio /
> +                                       PANEL_RATIO_FACTOR;
> +                       vert_bits = (1 << bits) * vert_ratio /
> +                                       PANEL_RATIO_FACTOR;
> +                       pfit_pgm_ratios =
> +                               ((vert_bits << PFIT_VERT_SCALE_SHIFT) &
> +                                               PFIT_VERT_SCALE_MASK) |
> +                               ((horiz_bits << PFIT_HORIZ_SCALE_SHIFT) &
> +                                               PFIT_HORIZ_SCALE_MASK);
> +               }
> +               break;
> +
> +       case DRM_MODE_SCALE_FULLSCREEN:
> +               /*
> +                * Full scaling, even if it changes the aspect ratio.
> +                * Fortunately this is all done for us in hw.
> +                */
> +               pfit_control |= PFIT_ENABLE;
> +               if (IS_I965G(dev))
> +                       pfit_control |= PFIT_SCALING_AUTO;
> +               else
> +                       pfit_control |= (VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
> +                                        VERT_INTERP_BILINEAR |
> +                                        HORIZ_INTERP_BILINEAR);
> +               break;
> +       default:
> +               break;
> +       }
> +
> +out:
> +       lvds_priv->pfit_control = pfit_control;
> +       lvds_priv->pfit_pgm_ratios = pfit_pgm_ratios;
>         /*
>          * XXX: It would be nice to support lower refresh rates on the
>          * panels to reduce power consumption, and perhaps match the
> @@ -242,8 +458,8 @@
>  {
>         struct drm_device *dev = encoder->dev;
>         struct drm_i915_private *dev_priv = dev->dev_private;
> -       struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
> -       u32 pfit_control;
> +       struct intel_output *intel_output = enc_to_intel_output(encoder);
> +       struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
> 
>         /*
>          * The LVDS pin pair will already have been turned on in the
> @@ -256,22 +472,8 @@
>          * screen.  Should be enabled before the pipe is enabled, according to
>          * register description and PRM.
>          */
> -       if (mode->hdisplay != adjusted_mode->hdisplay ||
> -           mode->vdisplay != adjusted_mode->vdisplay)
> -               pfit_control = (PFIT_ENABLE | VERT_AUTO_SCALE |
> -                               HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
> -                               HORIZ_INTERP_BILINEAR);
> -       else
> -               pfit_control = 0;
> -
> -       if (!IS_I965G(dev)) {
> -               if (dev_priv->panel_wants_dither || dev_priv->lvds_dither)
> -                       pfit_control |= PANEL_8TO6_DITHER_ENABLE;
> -       }
> -       else
> -               pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
> -
> -       I915_WRITE(PFIT_CONTROL, pfit_control);
> +       I915_WRITE(PFIT_PGM_RATIOS, lvds_priv->pfit_pgm_ratios);
> +       I915_WRITE(PFIT_CONTROL, lvds_priv->pfit_control);
>  }
> 
>  /**
> @@ -344,10 +546,35 @@
>                                    uint64_t value)
>  {
>         struct drm_device *dev = connector->dev;
> +       struct intel_output *intel_output =
> +                       to_intel_output(connector);
> 
>         if (property == dev->mode_config.dpms_property && connector->encoder)
>                 intel_lvds_dpms(connector->encoder, (uint32_t)(value & 0xf));
> 
> +       if (property == dev->mode_config.scaling_mode_property &&
> +                       connector->encoder) {
> +               struct drm_crtc *crtc = connector->encoder->crtc;
> +               struct intel_lvds_priv *lvds_priv = intel_output->dev_priv;
> +
> +               if (value == DRM_MODE_SCALE_NON_GPU) {
> +                       DRM_DEBUG("non_GPU property is unsupported.\n");
> +                       return 0;
> +               }
> +
> +               if (lvds_priv->fitting_mode == value)
> +                       return 0;
> +
> +               lvds_priv->fitting_mode = value;
> +               if (crtc && crtc->enabled) {
> +                       /*
> +                        * If the CRTC is enabled, the display will be changed
> +                        * according to the new panel fitting mode.
> +                        */
> +                       drm_crtc_helper_set_mode(crtc, &crtc->mode,
> +                                                crtc->x, crtc->y, crtc->fb);
> +               }
> +       }
>         return 0;
>  }
> 
> @@ -445,6 +672,7 @@
>         struct drm_encoder *encoder;
>         struct drm_display_mode *scan; /* *modes, *bios_mode; */
>         struct drm_crtc *crtc;
> +       struct intel_lvds_priv *lvds_priv;
>         u32 lvds;
>         int pipe;
> 
> @@ -452,7 +680,8 @@
>         if (dmi_check_system(intel_no_lvds))
>                 return;
> 
> -       intel_output = kzalloc(sizeof(struct intel_output), GFP_KERNEL);
> +       intel_output = kzalloc(sizeof(struct intel_output) +
> +                               sizeof(struct intel_lvds_priv), GFP_KERNEL);
>         if (!intel_output) {
>                 return;
>         }
> @@ -474,7 +703,18 @@
>         connector->interlace_allowed = false;
>         connector->doublescan_allowed = false;
> 
> +       lvds_priv = (struct intel_lvds_priv *)(intel_output + 1);
> +       intel_output->dev_priv = lvds_priv;
> +       /* create the scaling mode property */
> +       drm_mode_create_scaling_mode_property(dev);
> +       /*
> +        * the initial panel fitting mode will be FULL_ASPECT
> +        */
> 
> +       drm_connector_attach_property(&intel_output->base,
> +                                     dev->mode_config.scaling_mode_property,
> +                                     DRM_MODE_SCALE_ASPECT);
> +       lvds_priv->fitting_mode = DRM_MODE_SCALE_ASPECT;
>         /*
>          * LVDS discovery:
>          * 1) check for EDID on DDC
> @@ -554,5 +794,5 @@
>         if (intel_output->ddc_bus)
>                 intel_i2c_destroy(intel_output->ddc_bus);
>         drm_connector_cleanup(connector);
> -       kfree(connector);
> +       kfree(intel_output);
>  }
> 
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/intel-gfx




More information about the Intel-gfx mailing list