xf86-video-intel: 4 commits - man/intel.man src/i810_reg.h src/i830_lvds.c

Jesse Barnes jbarnes at kemper.freedesktop.org
Wed Mar 26 14:55:37 PDT 2008


 man/intel.man   |   26 +++
 src/i810_reg.h  |   25 +++
 src/i830_lvds.c |  368 ++++++++++++++++++++++++++++++++++++++++++++++++++------
 3 files changed, 373 insertions(+), 46 deletions(-)

New commits:
commit 588371ba15afffa9343629f0ea7ce530586eef0b
Merge: 52d6ced... c13efdd...
Author: Jesse Barnes <jbarnes at hobbes.virtuousgeek.org>
Date:   Wed Mar 26 14:53:15 2008 -0700

    Merge branch 'master' into pfit

commit 52d6ced652059989e6d9780a149488ccd16e3a22
Author: Jesse Barnes <jbarnes at hobbes.virtuousgeek.org>
Date:   Wed Mar 19 11:59:15 2008 -0700

    Fixup backlight control and panel fitting property names
    
    They should be listed as lower case, since that's what you'd pass to xrandr.

diff --git a/man/intel.man b/man/intel.man
index 473897a..f59ffb4 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -209,19 +209,19 @@ By adjusting the BACKLIGHT property, the brightness on the LVDS output can be ad
 .TP 2
 The driver will attempt to automatically detect the backlight control method for your platform.  If this fails however, you can select another method which may allow you to control your backlight.  Available methods include:
 .PP
-.B NATIVE
+.B native
 .TP 4
 Intel chipsets include backlight control registers, which on some platforms may be wired to control the backlight directly.  This method uses those registers.
 .PP
-.B LEGACY
+.B legacy
 .TP 4
 The legacy backlight control registers exist in PCI configuration space, and have fewer available backlight levels than the native registers.  However, some platforms are wired this way and so need to use this method.
 .PP
-.B COMBO
+.B combo
 .TP 4
 This method attempts to use the native registers where possible, resorting to the legacy, configuration space registers only to enable the backlight if needed.  On platforms that have both wired this can be a good choice as it allows the fine grained backlight control of the native interface.
 .PP
-.B KERNEL
+.B kernel
 .TP 4
 On some system, the kernel may provide a backlight control driver.  In that case, using the kernel interfaces is preferable, as the same driver may respond to hotkey events or external APIs.
 
@@ -231,15 +231,15 @@ On some system, the kernel may provide a backlight control driver.  In that case
 .TP 2
 By default, the driver will attempt to upscale resolutions smaller than the LCD's native size while preserving the aspect ratio.  Other modes are available however:
 .PP
-.B CENTER
+.B center
 .TP 4
 Simply center the image on-screen, without scaling.
 .PP
-.B FULL_ASPECT
+.B full_aspect
 .TP 4
 The default mode.  Try to upscale the image to the screen size, while preserving aspect ratio.  May result in letterboxing or pillar-boxing with some resolutions.
 .PP
-.B FULL
+.B full
 .TP 4
 Upscale the image to the native screen size without regard to aspect ratio.  In this mode, the full screen image may appear distorted in some resolutions.
 
commit ffb5a115cc62ed63110f77815b7f04976f720065
Merge: 05cf070... 24e6eb2...
Author: Jesse Barnes <jbarnes at nietzche.virtuousgeek.org>
Date:   Mon Mar 17 15:19:05 2008 -0700

    Merge branch 'master' into pfit

commit 05cf07071e25f84dec3476a9bed7235ed50cd249
Author: Jesse Barnes <jbarnes at nietzche.virtuousgeek.org>
Date:   Thu Mar 13 18:12:00 2008 -0700

    Initial panel fitting changes
    
    Basic support for panel fitting.

diff --git a/man/intel.man b/man/intel.man
index e5736e5..473897a 100644
--- a/man/intel.man
+++ b/man/intel.man
@@ -225,6 +225,24 @@ This method attempts to use the native registers where possible, resorting to th
 .TP 4
 On some system, the kernel may provide a backlight control driver.  In that case, using the kernel interfaces is preferable, as the same driver may respond to hotkey events or external APIs.
 
+.PP
+.B PANEL_FITTING
+- control LCD panel fitting
+.TP 2
+By default, the driver will attempt to upscale resolutions smaller than the LCD's native size while preserving the aspect ratio.  Other modes are available however:
+.PP
+.B CENTER
+.TP 4
+Simply center the image on-screen, without scaling.
+.PP
+.B FULL_ASPECT
+.TP 4
+The default mode.  Try to upscale the image to the screen size, while preserving aspect ratio.  May result in letterboxing or pillar-boxing with some resolutions.
+.PP
+.B FULL
+.TP 4
+Upscale the image to the native screen size without regard to aspect ratio.  In this mode, the full screen image may appear distorted in some resolutions.
+
 .SS "TV"
 Integrated TV output.  Available properties include:
 
diff --git a/src/i810_reg.h b/src/i810_reg.h
index d5b6805..d799e77 100644
--- a/src/i810_reg.h
+++ b/src/i810_reg.h
@@ -871,8 +871,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 #define PFIT_CONTROL	0x61230
 # define PFIT_ENABLE				(1 << 31)
-# define PFIT_PIPE_MASK				(3 << 29)
-# define PFIT_PIPE_SHIFT			29
+/* Pre-965 */
 # define VERT_INTERP_DISABLE			(0 << 10)
 # define VERT_INTERP_BILINEAR			(1 << 10)
 # define VERT_INTERP_MASK			(3 << 10)
@@ -882,12 +881,30 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 # define HORIZ_INTERP_MASK			(3 << 6)
 # define HORIZ_AUTO_SCALE			(1 << 5)
 # define PANEL_8TO6_DITHER_ENABLE		(1 << 3)
+/* 965+ */
+# define PFIT_PIPE_MASK				(3 << 29)
+# define PFIT_PIPE_SHIFT			29
+# define PFIT_SCALING_MODE_MASK			(7 << 26)
+#  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_FILTER_SELECT_MASK		(3 << 24)
+#  define PFIT_FILTER_FUZZY			(0 << 24)
+#  define PFIT_FILTER_CRISP			(1 << 24)
+#  define PFIT_FILTER_MEDIAN			(2 << 24)
 
 #define PFIT_PGM_RATIOS	0x61234
+/* 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
-
-#define PFIT_AUTO_RATIOS	0x61238
+/* 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 DPLL_A		0x06014
 #define DPLL_B		0x06018
diff --git a/src/i830_lvds.c b/src/i830_lvds.c
index a75d7e6..daf71da 100644
--- a/src/i830_lvds.c
+++ b/src/i830_lvds.c
@@ -44,12 +44,25 @@
 #include "i830_display.h"
 #include "X11/Xatom.h"
 
+/*
+ * Three panel fitting modes:
+ * CENTER - center image on screen, don't scale
+ * FULL_ASPECT - scale image to fit screen, but preserve aspect ratio
+ * FULL - scale image to fit screen without regard to aspect ratio
+ */
+enum pfit_mode {
+    CENTER = 0,
+    FULL_ASPECT,
+    FULL,
+};
+
 struct i830_lvds_priv {
     /* The BIOS's fixed timings for the LVDS */
     DisplayModePtr panel_fixed_mode;
     
     /* The panel needs dithering enabled */
     Bool	    panel_wants_dither;
+    Bool	    need_border;
 
     /* restore backlight to this value */
     int		    backlight_duty_cycle;
@@ -57,6 +70,9 @@ struct i830_lvds_priv {
     void (*set_backlight)(xf86OutputPtr output, int level);
     int (*get_backlight)(xf86OutputPtr output);
     int backlight_max;
+    enum pfit_mode fitting_mode;
+    uint32_t pfit_control;
+    uint32_t pfit_pgm_ratios;
 };
 
 #define BACKLIGHT_CLASS "/sys/class/backlight"
@@ -481,7 +497,13 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
     ScrnInfoPtr		    pScrn = output->scrn;
     xf86CrtcConfigPtr	    xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     I830CrtcPrivatePtr	    intel_crtc = output->crtc->driver_private;
+    I830Ptr		    pI830 = I830PTR(pScrn);
+    uint32_t		    pfit_control = 0, pfit_pgm_ratios = 0;
+    float		    panel_ratio, desired_ratio, vert_scale, horiz_scale;
+    float		    horiz_ratio, vert_ratio;
+    int left_border = 0, right_border = 0, top_border = 0, bottom_border = 0;
     int i;
+    Bool border = 0;
 
     for (i = 0; i < xf86_config->num_output; i++) {
 	xf86OutputPtr other_output = xf86_config->output[i];
@@ -500,24 +522,207 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 	return FALSE;
     }
 
+    /* If we don't have a panel mode there's not much 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,
      * with the panel scaling set up to source from the H/VDisplay
      * of the original mode.
      */
-    if (dev_priv->panel_fixed_mode != NULL) {
-	adjusted_mode->HDisplay = dev_priv->panel_fixed_mode->HDisplay;
-	adjusted_mode->HSyncStart = dev_priv->panel_fixed_mode->HSyncStart;
-	adjusted_mode->HSyncEnd = dev_priv->panel_fixed_mode->HSyncEnd;
-	adjusted_mode->HTotal = dev_priv->panel_fixed_mode->HTotal;
-	adjusted_mode->VDisplay = dev_priv->panel_fixed_mode->VDisplay;
-	adjusted_mode->VSyncStart = dev_priv->panel_fixed_mode->VSyncStart;
-	adjusted_mode->VSyncEnd = dev_priv->panel_fixed_mode->VSyncEnd;
-	adjusted_mode->VTotal = dev_priv->panel_fixed_mode->VTotal;
-	adjusted_mode->Clock = dev_priv->panel_fixed_mode->Clock;
-	xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
+    adjusted_mode->HDisplay = dev_priv->panel_fixed_mode->HDisplay;
+    adjusted_mode->HSyncStart = dev_priv->panel_fixed_mode->HSyncStart;
+    adjusted_mode->HSyncEnd = dev_priv->panel_fixed_mode->HSyncEnd;
+    adjusted_mode->HTotal = dev_priv->panel_fixed_mode->HTotal;
+    adjusted_mode->VDisplay = dev_priv->panel_fixed_mode->VDisplay;
+    adjusted_mode->VSyncStart = dev_priv->panel_fixed_mode->VSyncStart;
+    adjusted_mode->VSyncEnd = dev_priv->panel_fixed_mode->VSyncEnd;
+    adjusted_mode->VTotal = dev_priv->panel_fixed_mode->VTotal;
+    adjusted_mode->Clock = dev_priv->panel_fixed_mode->Clock;
+    xf86SetModeCrtc(adjusted_mode, INTERLACE_HALVE_V);
+
+    /* Native modes don't need fitting */
+    if (adjusted_mode->HDisplay == mode->HDisplay &&
+	adjusted_mode->VDisplay == mode->VDisplay) {
+	pfit_control = 0;
+	pfit_pgm_ratios = 0;
+	border = 0;
+	goto out;
+    }
+
+    /* Basic panel fitting options */
+    if (!IS_I965G(pI830)) {
+	if (dev_priv->panel_wants_dither)
+	    pfit_control |= PANEL_8TO6_DITHER_ENABLE;
+    } else {
+	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 = (float)adjusted_mode->HDisplay /
+ 	(float)adjusted_mode->VDisplay;
+    desired_ratio = (float)mode->HDisplay /
+	(float)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 */
+    OUTREG(BCLRPAT_A, 0);
+    OUTREG(BCLRPAT_B, 0);
+    switch (dev_priv->fitting_mode) {
+    case CENTER:
+	/*
+	 * For centered modes, we have to calculate border widths & heights and
+	 * modify the values programmed into the CRTC.  Also need to make sure
+	 * LVDS borders are enabled (see i830_display.c).
+	 */
+	left_border =
+	    (dev_priv->panel_fixed_mode->HDisplay - mode->HDisplay) / 2;
+	right_border = left_border;
+	if (mode->HDisplay & 1)
+	    right_border++;
+	top_border =
+	    (dev_priv->panel_fixed_mode->VDisplay - mode->VDisplay) / 2;
+	bottom_border = top_border;
+	if (mode->VDisplay & 1)
+	    bottom_border++;
+
+	/* Set active & border values */
+	adjusted_mode->CrtcHDisplay = mode->HDisplay;
+	adjusted_mode->CrtcHBlankStart = mode->HDisplay + right_border - 1;
+	adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal -
+	    left_border - 1;
+	adjusted_mode->CrtcHSyncStart = adjusted_mode->CrtcHBlankStart;
+	adjusted_mode->CrtcHSyncEnd = adjusted_mode->CrtcHBlankEnd;
+	adjusted_mode->CrtcVDisplay = mode->VDisplay;
+	adjusted_mode->CrtcVBlankStart = mode->VDisplay + bottom_border - 1;
+	adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal -
+	    top_border - 1;
+	adjusted_mode->CrtcVSyncStart = adjusted_mode->CrtcVBlankStart;
+	adjusted_mode->CrtcVSyncEnd = adjusted_mode->CrtcVBlankEnd;
+	border = 1;
+	break;
+    case FULL_ASPECT:
+	/* Scale but preserve aspect ratio */
+	pfit_control |= PFIT_ENABLE;
+	if (IS_I965G(pI830)) {
+	    /*
+	     * 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_RATIOS reg.
+	     */
+	    uint32_t horiz_bits, vert_bits, bits = 12;
+
+	    horiz_ratio = ((float)mode->HDisplay) /
+		((float)adjusted_mode->HDisplay);
+	    vert_ratio = ((float)mode->VDisplay) /
+		((float)adjusted_mode->VDisplay);
+
+	    horiz_scale = ((float)adjusted_mode->HDisplay) /
+		((float)mode->HDisplay);
+	    vert_scale = ((float)adjusted_mode->VDisplay) /
+		((float)mode->VDisplay);
+
+	    /* Retain aspect ratio */
+	    if (panel_ratio > desired_ratio) { /* Pillar */
+		unsigned long scaled_width = (float)mode->HDisplay * vert_scale;
+
+		horiz_ratio = vert_ratio;
+		pfit_control |= VERT_AUTO_SCALE | VERT_INTERP_BILINEAR |
+		    HORIZ_INTERP_BILINEAR;
+
+		/* Pillar will have left/right borders */
+		left_border =  (dev_priv->panel_fixed_mode->HDisplay -
+				scaled_width) / 2;
+		right_border = left_border;
+		if (mode->HDisplay & 1) /* odd resolutions */
+		    right_border++;
+
+		adjusted_mode->CrtcHDisplay = scaled_width;
+		adjusted_mode->CrtcHBlankStart = scaled_width +
+		    right_border - 1;
+		adjusted_mode->CrtcHBlankEnd = adjusted_mode->CrtcHTotal -
+		    left_border - 1;
+		adjusted_mode->CrtcHSyncStart = adjusted_mode->CrtcHBlankStart;
+		adjusted_mode->CrtcHSyncEnd = adjusted_mode->CrtcHBlankEnd;
+		border = 1;
+	    } else if (panel_ratio < desired_ratio) { /* Letter */
+		unsigned long scaled_height = (float)mode->VDisplay *
+		    horiz_scale;
+
+		vert_ratio = horiz_ratio;
+		pfit_control |= HORIZ_AUTO_SCALE | VERT_INTERP_BILINEAR |
+		    HORIZ_INTERP_BILINEAR;
+
+		/* Letterbox will have top/bottom borders */
+		top_border = (dev_priv->panel_fixed_mode->VDisplay -
+			      mode->VDisplay) / 2;
+		bottom_border = top_border;
+		if (mode->VDisplay & 1)
+		    bottom_border++;
+
+		adjusted_mode->CrtcVDisplay = scaled_height;
+		adjusted_mode->CrtcVBlankStart = scaled_height +
+		    bottom_border - 1;
+		adjusted_mode->CrtcVBlankEnd = adjusted_mode->CrtcVTotal -
+		    top_border - 1;
+		adjusted_mode->CrtcVSyncStart = adjusted_mode->CrtcVBlankStart;
+		adjusted_mode->CrtcVSyncEnd = adjusted_mode->CrtcVBlankEnd;
+		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 = 0.5 + (1 << bits) * horiz_ratio;
+	    vert_bits = 0.5 + (1 << bits) * vert_ratio;
+
+	    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 FULL:
+	/*
+	 * 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(pI830))
+	    pfit_control |= PFIT_SCALING_AUTO;
+	else
+	    pfit_control |= VERT_AUTO_SCALE | HORIZ_AUTO_SCALE |
+		VERT_INTERP_BILINEAR | HORIZ_INTERP_BILINEAR;
+	break;
+    default:
+	/* shouldn't happen */
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "error: bad fitting mode\n");
+	break;
+    }
+  
+out:
+    dev_priv->pfit_control = pfit_control;
+    dev_priv->pfit_pgm_ratios = pfit_pgm_ratios;
+    dev_priv->need_border = border;
+
     /* XXX: It would be nice to support lower refresh rates on the
      * panels to reduce power consumption, and perhaps match the
      * user's requested refresh rate.
@@ -527,42 +732,43 @@ i830_lvds_mode_fixup(xf86OutputPtr output, DisplayModePtr mode,
 }
 
 static void
-i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
-		   DisplayModePtr adjusted_mode)
+i830_lvds_prepare(xf86OutputPtr output)
 {
     I830OutputPrivatePtr    intel_output = output->driver_private;
     struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
     ScrnInfoPtr		    pScrn = output->scrn;
     I830Ptr		    pI830 = I830PTR(pScrn);
-    I830CrtcPrivatePtr	    intel_crtc = output->crtc->driver_private;
-    uint32_t		    pfit_control;
+    uint32_t		    lvds;
 
-    /* The LVDS pin pair will already have been turned on in
-     * i830_crtc_mode_set since it has a large impact on the DPLL settings.
-     */
+    lvds = INREG(LVDS);
 
-    /* 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.
+    i830_lvds_dpms(output, DPMSModeOff);
+    /*
+     * ->prepare will be called after the CRTC is off but before
+     * we set the mode, so program the PFIT regs here.
      */
-    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 (dev_priv->need_border)
+	OUTREG(LVDS, lvds | LVDS_BORDER_ENABLE);
+    else
+	OUTREG(LVDS, lvds & (~LVDS_BORDER_ENABLE));
+}
 
-    if (!IS_I965G(pI830)) {
-	if (dev_priv->panel_wants_dither)
-	    pfit_control |= PANEL_8TO6_DITHER_ENABLE;
-    } else {
-	pfit_control |= intel_crtc->pipe << PFIT_PIPE_SHIFT;
-    }
+static void
+i830_lvds_mode_set(xf86OutputPtr output, DisplayModePtr mode,
+		   DisplayModePtr adjusted_mode)
+{
+    I830OutputPrivatePtr    intel_output = output->driver_private;
+    struct i830_lvds_priv   *dev_priv = intel_output->dev_priv;
+    ScrnInfoPtr		    pScrn = output->scrn;
+    I830Ptr		    pI830 = I830PTR(pScrn);
 
-    OUTREG(PFIT_CONTROL, pfit_control);
+    /*
+     * PFIT must be enabled/disabled while LVDS is on but pipes are still off
+     */
+    OUTREG(PFIT_PGM_RATIOS, dev_priv->pfit_pgm_ratios);
+    OUTREG(PFIT_CONTROL, dev_priv->pfit_control);
+    /* It's harmless to turn on the LVDS if it's already on */
+    i830_lvds_dpms(output, DPMSModeOn);
 }
 
 /**
@@ -653,6 +859,17 @@ static char *backlight_control_names[] = {
 static Atom backlight_control_atom;
 static Atom backlight_control_name_atoms[NUM_BACKLIGHT_CONTROL_METHODS];
 
+#define PANEL_FITTING_NAME "PANEL_FITTING"
+#define NUM_PANEL_FITTING_TYPES 3
+static char *panel_fitting_names[] = {
+    "center",
+    "full_aspect",
+    "full",
+};
+static Atom panel_fitting_atom;
+static Atom panel_fitting_name_atoms[NUM_PANEL_FITTING_TYPES];
+
+
 static int
 i830_backlight_control_lookup(char *name)
 {
@@ -709,6 +926,18 @@ i830_lvds_set_backlight_control(xf86OutputPtr output)
 
     return Success;
 }
+
+static int
+i830_panel_fitting_lookup(char *name)
+{
+    int i;
+
+    for (i = 0; i < NUM_PANEL_FITTING_TYPES; i++)
+	if (!strcmp(name, panel_fitting_names[i]))
+	    return i;
+
+    return -1;
+}
 #endif /* RANDR_12_INTERFACE */
 
 static void
@@ -775,6 +1004,33 @@ i830_lvds_create_resources(xf86OutputPtr output)
 	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
 		   "failed to set backlight control, %d\n", err);
     }
+
+    /*
+     * Panel fitting control
+     */
+    panel_fitting_atom = MakeAtom(PANEL_FITTING_NAME,
+				  sizeof(PANEL_FITTING_NAME) - 1, TRUE);
+    for (i = 0; i < NUM_PANEL_FITTING_TYPES; i++) {
+	panel_fitting_name_atoms[i] = MakeAtom(panel_fitting_names[i],
+					       strlen(panel_fitting_names[i]),
+					       TRUE);
+    }
+    err = RRConfigureOutputProperty(output->randr_output,
+				    panel_fitting_atom, TRUE, FALSE, FALSE,
+				    NUM_PANEL_FITTING_TYPES,
+				    (INT32 *)panel_fitting_name_atoms);
+    if (err != 0) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "RRConfigureOutputProperty error, %d\n", err);
+    }
+    err = RRChangeOutputProperty(output->randr_output, panel_fitting_atom,
+				 XA_ATOM, 32, PropModeReplace, 1,
+				 &panel_fitting_name_atoms[dev_priv->fitting_mode],
+				 FALSE, TRUE);
+    if (err != 0) {
+	xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+		   "failed to set panel fitting mode, %d\n", err);
+    }   
 #endif /* RANDR_12_INTERFACE */
 }
 
@@ -846,6 +1102,36 @@ i830_lvds_set_property(xf86OutputPtr output, Atom property,
 		       "RRChangeOutputProperty error, %d\n", ret);
 	}
 	return TRUE;
+    } else if (property == panel_fitting_atom) {
+	Atom			atom;
+	char			*name;
+	int			ret;
+
+	if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
+	    return FALSE;
+
+	memcpy(&atom, value->data, 4);
+	name = NameForAtom(atom);
+	
+	ret = i830_panel_fitting_lookup(name);
+	if (ret < 0)
+	    return FALSE;
+
+	dev_priv->fitting_mode = ret;
+
+	if (output->crtc) {
+	    xf86CrtcPtr crtc = output->crtc;
+	    if (crtc->enabled) {
+		if (!xf86CrtcSetMode(crtc, &crtc->desiredMode,
+				     crtc->desiredRotation,
+				     crtc->desiredX, crtc->desiredY)) {
+		    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+			       "Failed to set mode after panel fitting change!\n");
+		    return FALSE;
+		}
+	    }
+	}
+	return TRUE;
     }
 
     return TRUE;
@@ -886,7 +1172,7 @@ static const xf86OutputFuncsRec i830_lvds_output_funcs = {
     .restore = i830_lvds_restore,
     .mode_valid = i830_lvds_mode_valid,
     .mode_fixup = i830_lvds_mode_fixup,
-    .prepare = i830_output_prepare,
+    .prepare = i830_lvds_prepare,
     .mode_set = i830_lvds_mode_set,
     .commit = i830_output_commit,
     .detect = i830_lvds_detect,
@@ -1075,6 +1361,12 @@ i830_lvds_init(ScrnInfoPtr pScrn)
 
     dev_priv->backlight_duty_cycle = dev_priv->get_backlight(output);
 
+    /*
+     * Default to filling the whole screen if the mode is less than the
+     * native size, without breaking aspect ratio.
+     */
+    dev_priv->fitting_mode = FULL_ASPECT;
+
     return;
 
 disable_exit:


More information about the xorg-commit mailing list