drm/i915: Enable aspect/centering panel fitting for Ironlake.
authorChris Wilson <chris@chris-wilson.co.uk>
Sat, 7 Aug 2010 10:01:28 +0000 (11:01 +0100)
committerEric Anholt <eric@anholt.net>
Mon, 9 Aug 2010 18:24:34 +0000 (11:24 -0700)
v2: Hook in DP paths to keep FULLSCREEN panel fitting on eDP.

Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Signed-off-by: Eric Anholt <eric@anholt.net>
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_panel.c [new file with mode: 0644]

index 384fd453579631f18dcf5966f0609d2d835b3134..5c8e53458edbfee1c37e54b7b982d49e747d563e 100644 (file)
@@ -19,6 +19,7 @@ i915-y := i915_drv.o i915_dma.o i915_irq.o i915_mem.o \
          intel_hdmi.o \
          intel_sdvo.o \
          intel_modes.o \
+         intel_panel.o \
          intel_i2c.o \
          intel_fb.o \
          intel_tv.o \
index 6221f239fa5ea2e27a620df62e85b03345c2db0e..4b0ffb6c55612f1e4109772d454fdef61eca1b9a 100644 (file)
@@ -614,6 +614,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];
index 24fbd0f245078754c26f6e199dc851d2dfc7a0ea..25e3866f9159b909c542d20f8887fe605a09fbf2 100644 (file)
@@ -2005,15 +2005,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 */
index c4c5868a8aa07b686c561c1d4076500a7cf0efc5..cee5d9ceb3b86625eabf6338d5662cbae8095b27 100644 (file)
@@ -523,21 +523,9 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
 
        if ((IS_eDP(intel_dp) || IS_PCH_eDP(intel_dp)) &&
            dev_priv->panel_fixed_mode) {
-               struct drm_display_mode *fixed_mode = dev_priv->panel_fixed_mode;
-
-               adjusted_mode->hdisplay = fixed_mode->hdisplay;
-               adjusted_mode->hsync_start = fixed_mode->hsync_start;
-               adjusted_mode->hsync_end = fixed_mode->hsync_end;
-               adjusted_mode->htotal = fixed_mode->htotal;
-
-               adjusted_mode->vdisplay = fixed_mode->vdisplay;
-               adjusted_mode->vsync_start = fixed_mode->vsync_start;
-               adjusted_mode->vsync_end = fixed_mode->vsync_end;
-               adjusted_mode->vtotal = fixed_mode->vtotal;
-
-               adjusted_mode->clock = fixed_mode->clock;
-               drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
-
+               intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+               intel_pch_panel_fitting(dev, DRM_MODE_SCALE_FULLSCREEN,
+                                       mode, adjusted_mode);
                /*
                 * the mode->clock is used to calculate the Data&Link M/N
                 * of the pipe. For the eDP the fixed clock should be used.
@@ -572,8 +560,10 @@ intel_dp_mode_fixup(struct drm_encoder *encoder, struct drm_display_mode *mode,
                              "count %d clock %d\n",
                              intel_dp->link_bw, intel_dp->lane_count,
                              adjusted_mode->clock);
+
                return true;
        }
+
        return false;
 }
 
index a44b8cb4d2cc100de7fb0a406adffb19e2835a38..c552b06e5d213bccaa3d31f025baa130f5d39fad 100644 (file)
@@ -186,6 +186,13 @@ extern bool intel_dpd_is_edp(struct drm_device *dev);
 extern void intel_edp_link_config (struct intel_encoder *, int *, int *);
 
 
+extern void intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+                                  struct drm_display_mode *adjusted_mode);
+extern void intel_pch_panel_fitting(struct drm_device *dev,
+                                   int fitting_mode,
+                                   struct drm_display_mode *mode,
+                                   struct drm_display_mode *adjusted_mode);
+
 extern int intel_panel_fitter_pipe (struct drm_device *dev);
 extern void intel_crtc_load_lut(struct drm_crtc *crtc);
 extern void intel_encoder_prepare (struct drm_encoder *encoder);
index 312ac306469ac952dbcaca2dd4e93df7de7e1a16..cb5821eb59b635593103e896f4ac11abc20ba969 100644 (file)
@@ -246,26 +246,20 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
        /* If we don't have a panel mode, there is nothing we can do */
        if (dev_priv->panel_fixed_mode == NULL)
                return true;
+
        /*
         * 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,
         * with the panel scaling set up to source from the H/VDisplay
         * of the original mode.
         */
-       adjusted_mode->hdisplay = dev_priv->panel_fixed_mode->hdisplay;
-       adjusted_mode->hsync_start =
-               dev_priv->panel_fixed_mode->hsync_start;
-       adjusted_mode->hsync_end =
-               dev_priv->panel_fixed_mode->hsync_end;
-       adjusted_mode->htotal = dev_priv->panel_fixed_mode->htotal;
-       adjusted_mode->vdisplay = dev_priv->panel_fixed_mode->vdisplay;
-       adjusted_mode->vsync_start =
-               dev_priv->panel_fixed_mode->vsync_start;
-       adjusted_mode->vsync_end =
-               dev_priv->panel_fixed_mode->vsync_end;
-       adjusted_mode->vtotal = dev_priv->panel_fixed_mode->vtotal;
-       adjusted_mode->clock = dev_priv->panel_fixed_mode->clock;
-       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+       intel_fixed_panel_mode(dev_priv->panel_fixed_mode, adjusted_mode);
+
+       if (HAS_PCH_SPLIT(dev)) {
+               intel_pch_panel_fitting(dev, intel_lvds->fitting_mode,
+                                       mode, adjusted_mode);
+               return true;
+       }
 
        /* Make sure pre-965s set dither correctly */
        if (!IS_I965G(dev)) {
@@ -278,10 +272,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) |
@@ -293,10 +283,8 @@ static bool intel_lvds_mode_fixup(struct drm_encoder *encoder,
         * to register description and PRM.
         * Change the value here to see the borders for debugging
         */
-       if (!HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(BCLRPAT_A, 0);
-               I915_WRITE(BCLRPAT_B, 0);
-       }
+       I915_WRITE(BCLRPAT_A, 0);
+       I915_WRITE(BCLRPAT_B, 0);
 
        switch (intel_lvds->fitting_mode) {
        case DRM_MODE_SCALE_CENTER:
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
new file mode 100644 (file)
index 0000000..e7f5299
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright © 2006-2010 Intel Corporation
+ * Copyright (c) 2006 Dave Airlie <airlied@linux.ie>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *     Eric Anholt <eric@anholt.net>
+ *      Dave Airlie <airlied@linux.ie>
+ *      Jesse Barnes <jesse.barnes@intel.com>
+ *      Chris Wilson <chris@chris-wilson.co.uk>
+ */
+
+#include "intel_drv.h"
+
+void
+intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+                      struct drm_display_mode *adjusted_mode)
+{
+       adjusted_mode->hdisplay = fixed_mode->hdisplay;
+       adjusted_mode->hsync_start = fixed_mode->hsync_start;
+       adjusted_mode->hsync_end = fixed_mode->hsync_end;
+       adjusted_mode->htotal = fixed_mode->htotal;
+
+       adjusted_mode->vdisplay = fixed_mode->vdisplay;
+       adjusted_mode->vsync_start = fixed_mode->vsync_start;
+       adjusted_mode->vsync_end = fixed_mode->vsync_end;
+       adjusted_mode->vtotal = fixed_mode->vtotal;
+
+       adjusted_mode->clock = fixed_mode->clock;
+
+       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
+}
+
+/* adjusted_mode has been preset to be the panel's fixed mode */
+void
+intel_pch_panel_fitting(struct drm_device *dev,
+                       int fitting_mode,
+                       struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       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 (fitting_mode) {
+       case DRM_MODE_SCALE_CENTER:
+               width = mode->hdisplay;
+               height = mode->vdisplay;
+               x = (adjusted_mode->hdisplay - width + 1)/2;
+               y = (adjusted_mode->vdisplay - height + 1)/2;
+               break;
+
+       case DRM_MODE_SCALE_ASPECT:
+               /* Scale but preserve the aspect ratio */
+               {
+                       u32 scaled_width = adjusted_mode->hdisplay * mode->vdisplay;
+                       u32 scaled_height = mode->hdisplay * adjusted_mode->vdisplay;
+                       if (scaled_width > scaled_height) { /* pillar */
+                               width = scaled_height / mode->vdisplay;
+                               x = (adjusted_mode->hdisplay - width + 1) / 2;
+                               y = 0;
+                               height = adjusted_mode->vdisplay;
+                       } else if (scaled_width < scaled_height) { /* letter */
+                               height = scaled_width / mode->hdisplay;
+                               y = (adjusted_mode->vdisplay - height + 1) / 2;
+                               x = 0;
+                               width = adjusted_mode->hdisplay;
+                       } else {
+                               x = y = 0;
+                               width = adjusted_mode->hdisplay;
+                               height = adjusted_mode->vdisplay;
+                       }
+               }
+               break;
+
+       default:
+       case DRM_MODE_SCALE_FULLSCREEN:
+               x = y = 0;
+               width = adjusted_mode->hdisplay;
+               height = adjusted_mode->vdisplay;
+               break;
+       }
+
+done:
+       dev_priv->pch_pf_pos = (x << 16) | y;
+       dev_priv->pch_pf_size = (width << 16) | height;
+}