xf86-video-nv: man/nv.man src/g80_dac.c src/g80_display.c src/g80_display.h src/g80_output.c src/g80_output.h src/g80_sor.c

Aaron Plattner aplattner at kemper.freedesktop.org
Tue Jul 24 20:48:05 PDT 2007


 man/nv.man        |    4 +
 src/g80_dac.c     |   11 +++-
 src/g80_display.c |   46 ++++++++---------
 src/g80_display.h |    4 +
 src/g80_output.c  |   10 +--
 src/g80_output.h  |    2 
 src/g80_sor.c     |  143 +++++++++++++++++++++++++++++++++++++++---------------
 7 files changed, 147 insertions(+), 73 deletions(-)

New commits:
diff-tree 08b68473351081fe1ed96ba7e206ed0d301b8a91 (from f0ebb42ee94eac4b294d12d02f4406a444b347ff)
Author: Aaron Plattner <aplattner at nvidia.com>
Date:   Tue Jul 24 20:36:04 2007 -0700

    G80: Allow DVI scaling.
    
    Revamp how the scaling code works.  When a mode is set on a DVI output,
    determine the current preferred mode and scale to that.  Add a new scaling
    option, "off", which disables scaling and scans out the actual timings in the
    mode to be set.

diff --git a/man/nv.man b/man/nv.man
index f27cd6d..7b9d946 100644
--- a/man/nv.man
+++ b/man/nv.man
@@ -175,8 +175,10 @@ Valid values:
 .B scale
 Control how the image is scaled to fit the flat panel.
 Note that some flat panels perform their own scaling, overriding this option.
+.RB \*q off \*q
+is not valid for laptop flat panels (LVDS).
 Valid values:
-.RB \*q aspect "\*q, \*q" fill "\*q, and \*q" center \*q.
+.RB \*q off "\*q, \*q" aspect "\*q, \*q" fill "\*q, and \*q" center \*q.
 Default:
 .RB \*q aspect \*q.
 .\" ******************** end G80 section ********************
diff --git a/src/g80_dac.c b/src/g80_dac.c
index 7848de2..30413cd 100644
--- a/src/g80_dac.c
+++ b/src/g80_dac.c
@@ -76,6 +76,13 @@ G80DacDPMSSet(xf86OutputPtr output, int 
     pNv->reg[(0x0061A004+off)/4] = tmp;
 }
 
+Bool
+G80DacModeFixup(xf86OutputPtr output, DisplayModePtr mode,
+                DisplayModePtr adjusted_mode)
+{
+    return TRUE;
+}
+
 static void
 G80DacModeSet(xf86OutputPtr output, DisplayModePtr mode,
               DisplayModePtr adjusted_mode)
@@ -99,6 +106,8 @@ G80DacModeSet(xf86OutputPtr output, Disp
     C(0x00000404 + dacOff,
         (adjusted_mode->Flags & V_NHSYNC) ? 1 : 0 |
         (adjusted_mode->Flags & V_NVSYNC) ? 2 : 0);
+
+    G80CrtcSetScale(output->crtc, adjusted_mode, G80_SCALE_OFF);
 }
 
 /*
@@ -165,7 +174,7 @@ static const xf86OutputFuncsRec G80DacOu
     .save = NULL,
     .restore = NULL,
     .mode_valid = G80OutputModeValid,
-    .mode_fixup = G80OutputModeFixup,
+    .mode_fixup = G80DacModeFixup,
     .prepare = G80OutputPrepare,
     .commit = G80OutputCommit,
     .mode_set = G80DacModeSet,
diff --git a/src/g80_display.c b/src/g80_display.c
index 14352aa..542a68e 100644
--- a/src/g80_display.c
+++ b/src/g80_display.c
@@ -42,7 +42,6 @@ typedef struct G80CrtcPrivRec {
     Bool cursorVisible;
     Bool skipModeFixup;
     Bool dither;
-    enum G80ScaleMode scale;
 } G80CrtcPrivRec, *G80CrtcPrivPtr;
 
 static void G80CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update);
@@ -307,31 +306,35 @@ G80DispShutdown(ScrnInfoPtr pScrn)
     while((pNv->reg[0x61C830/4] & 0x10000000));
 }
 
+void
+G80CrtcDoModeFixup(DisplayModePtr dst, const DisplayModePtr src)
+{
+    /* Magic mode timing fudge factor */
+    const int fudge = ((src->Flags & V_INTERLACE) && (src->Flags & V_DBLSCAN)) ? 2 : 1;
+    const int interlaceDiv = (src->Flags & V_INTERLACE) ? 2 : 1;
+
+    /* Stash the src timings in the Crtc fields in dst */
+    dst->CrtcHBlankStart = src->CrtcVTotal << 16 | src->CrtcHTotal;
+    dst->CrtcHSyncEnd = ((src->CrtcVSyncEnd - src->CrtcVSyncStart) / interlaceDiv - 1) << 16 |
+        (src->CrtcHSyncEnd - src->CrtcHSyncStart - 1);
+    dst->CrtcHBlankEnd = ((src->CrtcVBlankEnd - src->CrtcVSyncStart) / interlaceDiv - fudge) << 16 |
+        (src->CrtcHBlankEnd - src->CrtcHSyncStart - 1);
+    dst->CrtcHTotal = ((src->CrtcVTotal - src->CrtcVSyncStart + src->CrtcVBlankStart) / interlaceDiv - fudge) << 16 |
+        (src->CrtcHTotal - src->CrtcHSyncStart + src->CrtcHBlankStart - 1);
+    dst->CrtcHSkew = ((src->CrtcVTotal + src->CrtcVBlankEnd - src->CrtcVSyncStart) / 2 - 2) << 16 |
+        ((2*src->CrtcVTotal - src->CrtcVSyncStart + src->CrtcVBlankStart) / 2 - 2);
+}
+
 static Bool
 G80CrtcModeFixup(xf86CrtcPtr crtc,
                  DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
     G80CrtcPrivPtr pPriv = crtc->driver_private;
-    int interlaceDiv, fudge;
 
     if(pPriv->skipModeFixup)
         return TRUE;
 
-    /* Magic mode timing fudge factor */
-    fudge = ((adjusted_mode->Flags & V_INTERLACE) && (adjusted_mode->Flags & V_DBLSCAN)) ? 2 : 1;
-    interlaceDiv = (adjusted_mode->Flags & V_INTERLACE) ? 2 : 1;
-
-    /* Stash the mode timings in the Crtc fields in adjusted_mode */
-    adjusted_mode->CrtcHBlankStart = mode->CrtcVTotal << 16 | mode->CrtcHTotal;
-    adjusted_mode->CrtcHSyncEnd = ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) / interlaceDiv - 1) << 16 |
-        (mode->CrtcHSyncEnd - mode->CrtcHSyncStart - 1);
-    adjusted_mode->CrtcHBlankEnd = ((mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / interlaceDiv - fudge) << 16 |
-        (mode->CrtcHBlankEnd - mode->CrtcHSyncStart - 1);
-    adjusted_mode->CrtcHTotal = ((mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / interlaceDiv - fudge) << 16 |
-        (mode->CrtcHTotal - mode->CrtcHSyncStart + mode->CrtcHBlankStart - 1);
-    adjusted_mode->CrtcHSkew = ((mode->CrtcVTotal + mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / 2 - 2) << 16 |
-        ((2*mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / 2 - 2);
-
+    G80CrtcDoModeFixup(adjusted_mode, mode);
     return TRUE;
 }
 
@@ -365,7 +368,6 @@ G80CrtcModeSet(xf86CrtcPtr crtc, Display
         case 24: C(0x00000870 + headOff, 0xCF00); break;
     }
     G80CrtcSetDither(crtc, pPriv->dither, FALSE);
-    G80CrtcSetScale(crtc, adjusted_mode, pPriv->scale, FALSE);
     C(0x000008A8 + headOff, 0x40000);
     C(0x000008C0 + headOff, y << 16 | x);
     C(0x000008C8 + headOff, VDisplay << 16 | HDisplay);
@@ -504,20 +506,19 @@ static void ComputeAspectScale(DisplayMo
 }
 
 void G80CrtcSetScale(xf86CrtcPtr crtc, DisplayModePtr mode,
-                     enum G80ScaleMode scale, Bool update)
+                     enum G80ScaleMode scale)
 {
     ScrnInfoPtr pScrn = crtc->scrn;
     G80CrtcPrivPtr pPriv = crtc->driver_private;
     const int headOff = 0x400 * pPriv->head;
     int outX, outY;
 
-    pPriv->scale = scale;
-
     switch(scale) {
         case G80_SCALE_ASPECT:
             ComputeAspectScale(mode, &outX, &outY);
             break;
 
+        case G80_SCALE_OFF:
         case G80_SCALE_FILL:
             outX = mode->CrtcHDisplay;
             outY = mode->CrtcVDisplay;
@@ -537,8 +538,6 @@ void G80CrtcSetScale(xf86CrtcPtr crtc, D
     }
     C(0x000008D8 + headOff, outY << 16 | outX);
     C(0x000008DC + headOff, outY << 16 | outX);
-
-    if(update) C(0x00000080, 0);
 }
 
 static void
@@ -600,7 +599,6 @@ G80DispCreateCrtcs(ScrnInfoPtr pScrn)
         g80_crtc = xnfcalloc(sizeof(*g80_crtc), 1);
         g80_crtc->head = head;
         g80_crtc->dither = pNv->Dither;
-        g80_crtc->scale = G80_SCALE_ASPECT;
         crtc->driver_private = g80_crtc;
     }
 }
diff --git a/src/g80_display.h b/src/g80_display.h
index 8bd3bfb..2031fed 100644
--- a/src/g80_display.h
+++ b/src/g80_display.h
@@ -1,4 +1,5 @@
 enum G80ScaleMode {
+    G80_SCALE_OFF,
     G80_SCALE_ASPECT,
     G80_SCALE_FILL,
     G80_SCALE_CENTER,
@@ -13,12 +14,13 @@ void G80DispCommand(ScrnInfoPtr, CARD32 
 
 Head G80CrtcGetHead(xf86CrtcPtr);
 
+void G80CrtcDoModeFixup(DisplayModePtr dst, const DisplayModePtr src);
 void G80CrtcBlankScreen(xf86CrtcPtr, Bool blank);
 void G80CrtcEnableCursor(xf86CrtcPtr, Bool update);
 void G80CrtcDisableCursor(xf86CrtcPtr, Bool update);
 void G80CrtcSetCursorPosition(xf86CrtcPtr, int x, int y);
 void G80CrtcSkipModeFixup(xf86CrtcPtr);
 void G80CrtcSetDither(xf86CrtcPtr, Bool dither, Bool update);
-void G80CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum G80ScaleMode, Bool update);
+void G80CrtcSetScale(xf86CrtcPtr, DisplayModePtr, enum G80ScaleMode);
 
 void G80DispCreateCrtcs(ScrnInfoPtr pScrn);
diff --git a/src/g80_output.c b/src/g80_output.c
index 448864f..8bd2096 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -29,6 +29,7 @@
 #include <strings.h>
 
 #include "g80_type.h"
+#include "g80_display.h"
 #include "g80_output.h"
 
 static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
@@ -173,13 +174,6 @@ G80OutputModeValid(xf86OutputPtr output,
     return MODE_OK;
 }
 
-Bool
-G80OutputModeFixup(xf86OutputPtr output, DisplayModePtr mode,
-                   DisplayModePtr adjusted_mode)
-{
-    return TRUE;
-}
-
 void
 G80OutputPrepare(xf86OutputPtr output)
 {
@@ -329,12 +323,14 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
 
             pPriv->partner = sor;
             pPriv->i2c = i2c;
+            pPriv->scale = G80_SCALE_OFF;
         }
         if(sor) {
             G80OutputPrivPtr pPriv = sor->driver_private;
 
             pPriv->partner = dac;
             pPriv->i2c = i2c;
+            pPriv->scale = G80_SCALE_ASPECT;
         }
     }
 
diff --git a/src/g80_output.h b/src/g80_output.h
index 900b76d..33514c6 100644
--- a/src/g80_output.h
+++ b/src/g80_output.h
@@ -3,6 +3,7 @@ typedef struct G80OutputPrivRec {
     ORNum or;
     PanelType panelType;
     DisplayModePtr nativeMode;
+    enum G80ScaleMode scale;
 
     xf86OutputPtr partner;
     I2CBusPtr i2c;
@@ -14,7 +15,6 @@ typedef struct G80OutputPrivRec {
 
 void G80OutputSetPClk(xf86OutputPtr, int pclk);
 int G80OutputModeValid(xf86OutputPtr, DisplayModePtr);
-Bool G80OutputModeFixup(xf86OutputPtr, DisplayModePtr mode, DisplayModePtr adjusted_mode);
 void G80OutputPrepare(xf86OutputPtr);
 void G80OutputCommit(xf86OutputPtr);
 void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c);
diff --git a/src/g80_sor.c b/src/g80_sor.c
index 8ba3425..c98b66d 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.c
@@ -122,6 +122,8 @@ G80SorModeSet(xf86OutputPtr output, Disp
         type |
         ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
         ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0));
+
+    G80CrtcSetScale(output->crtc, adjusted_mode, pPriv->scale);
 }
 
 static xf86OutputStatus
@@ -151,49 +153,90 @@ G80SorDestroy(xf86OutputPtr output)
 
     G80OutputDestroy(output);
 
-    if(pPriv->nativeMode) {
-        if(pPriv->nativeMode->name)
-            xfree(pPriv->nativeMode->name);
-        xfree(pPriv->nativeMode);
-    }
+    xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode);
 
     xfree(output->driver_private);
     output->driver_private = NULL;
 }
 
-/******************** LVDS ********************/
+static void G80SorSetModeBackend(DisplayModePtr dst, const DisplayModePtr src)
+{
+    // Stash the backend mode timings from src into dst
+    dst->Clock           = src->Clock;
+    dst->Flags           = src->Flags;
+    dst->CrtcHDisplay    = src->CrtcHDisplay;
+    dst->CrtcHBlankStart = src->CrtcHBlankStart;
+    dst->CrtcHSyncStart  = src->CrtcHSyncStart;
+    dst->CrtcHSyncEnd    = src->CrtcHSyncEnd;
+    dst->CrtcHBlankEnd   = src->CrtcHBlankEnd;
+    dst->CrtcHTotal      = src->CrtcHTotal;
+    dst->CrtcHSkew       = src->CrtcHSkew;
+    dst->CrtcVDisplay    = src->CrtcVDisplay;
+    dst->CrtcVBlankStart = src->CrtcVBlankStart;
+    dst->CrtcVSyncStart  = src->CrtcVSyncStart;
+    dst->CrtcVSyncEnd    = src->CrtcVSyncEnd;
+    dst->CrtcVBlankEnd   = src->CrtcVBlankEnd;
+    dst->CrtcVTotal      = src->CrtcVTotal;
+    dst->CrtcHAdjusted   = src->CrtcHAdjusted;
+    dst->CrtcVAdjusted   = src->CrtcVAdjusted;
+}
+
 static Bool
-G80SorModeFixupScale(xf86OutputPtr output, DisplayModePtr mode,
-                     DisplayModePtr adjusted_mode)
+G80SorModeFixup(xf86OutputPtr output, DisplayModePtr mode,
+                DisplayModePtr adjusted_mode)
 {
     G80OutputPrivPtr pPriv = output->driver_private;
     DisplayModePtr native = pPriv->nativeMode;
 
-    // Stash the saved mode timings in adjusted_mode
-    adjusted_mode->Clock = native->Clock;
-    adjusted_mode->Flags = native->Flags;
-    adjusted_mode->CrtcHDisplay = native->CrtcHDisplay;
-    adjusted_mode->CrtcHBlankStart = native->CrtcHBlankStart;
-    adjusted_mode->CrtcHSyncStart = native->CrtcHSyncStart;
-    adjusted_mode->CrtcHSyncEnd = native->CrtcHSyncEnd;
-    adjusted_mode->CrtcHBlankEnd = native->CrtcHBlankEnd;
-    adjusted_mode->CrtcHTotal = native->CrtcHTotal;
-    adjusted_mode->CrtcHSkew = native->CrtcHSkew;
-    adjusted_mode->CrtcVDisplay = native->CrtcVDisplay;
-    adjusted_mode->CrtcVBlankStart = native->CrtcVBlankStart;
-    adjusted_mode->CrtcVSyncStart = native->CrtcVSyncStart;
-    adjusted_mode->CrtcVSyncEnd = native->CrtcVSyncEnd;
-    adjusted_mode->CrtcVBlankEnd = native->CrtcVBlankEnd;
-    adjusted_mode->CrtcVTotal = native->CrtcVTotal;
-    adjusted_mode->CrtcHAdjusted = native->CrtcHAdjusted;
-    adjusted_mode->CrtcVAdjusted = native->CrtcVAdjusted;
-
-    // This mode is already "fixed"
-    G80CrtcSkipModeFixup(output->crtc);
+    if(native && pPriv->scale != G80_SCALE_OFF) {
+        G80SorSetModeBackend(adjusted_mode, native);
+        // This mode is already "fixed"
+        G80CrtcSkipModeFixup(output->crtc);
+    }
 
     return TRUE;
 }
 
+static Bool
+G80SorTMDSModeFixup(xf86OutputPtr output, DisplayModePtr mode,
+                    DisplayModePtr adjusted_mode)
+{
+    int scrnIndex = output->scrn->scrnIndex;
+    G80OutputPrivPtr pPriv = output->driver_private;
+    DisplayModePtr modes = output->probed_modes;
+
+    xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode);
+
+    if(modes) {
+        // Find the preferred mode and use that as the "native" mode.
+        // If no preferred mode is available, use the first one.
+        DisplayModePtr mode;
+
+        // Find the preferred mode.
+        for(mode = modes; mode; mode = mode->next) {
+            if(mode->type & M_T_PREFERRED) {
+                xf86DrvMsgVerb(scrnIndex, X_INFO, 5,
+                               "%s: preferred mode is %s\n",
+                               output->name, mode->name);
+                break;
+            }
+        }
+
+        // XXX: May not want to allow scaling if no preferred mode is found.
+        if(!mode) {
+            mode = modes;
+            xf86DrvMsgVerb(scrnIndex, X_INFO, 5,
+                    "%s: no preferred mode found, using %s\n",
+                    output->name, mode->name);
+        }
+
+        pPriv->nativeMode = xf86DuplicateMode(mode);
+        G80CrtcDoModeFixup(pPriv->nativeMode, mode);
+    }
+
+    return G80SorModeFixup(output, mode, adjusted_mode);
+}
+
 static DisplayModePtr
 G80SorGetLVDSModes(xf86OutputPtr output)
 {
@@ -268,6 +311,8 @@ G80SorCreateResources(xf86OutputPtr outp
 static Bool
 G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val)
 {
+    G80OutputPrivPtr pPriv = output->driver_private;
+
     if(prop == properties.dither.atom) {
         INT32 i;
 
@@ -282,13 +327,13 @@ G80SorSetProperty(xf86OutputPtr output, 
         return TRUE;
     } else if(prop == properties.scale.atom) {
         const char *s;
-        enum G80ScaleMode scale;
-        DisplayModePtr mode;
+        enum G80ScaleMode oldScale, scale;
         int i;
         const struct {
             const char *name;
             enum G80ScaleMode scale;
         } modes[] = {
+            { "off",    G80_SCALE_OFF },
             { "aspect", G80_SCALE_ASPECT },
             { "fill",   G80_SCALE_FILL },
             { "center", G80_SCALE_CENTER },
@@ -310,12 +355,34 @@ G80SorSetProperty(xf86OutputPtr output, 
         }
         if(!modes[i].name)
             return FALSE;
+        if(scale == G80_SCALE_OFF && pPriv->panelType == LVDS)
+            // LVDS requires scaling
+            return FALSE;
 
-        /* Need to construct an adjusted mode */
-        mode = xf86DuplicateMode(&output->crtc->mode);
-        output->funcs->mode_fixup(output, &output->crtc->mode, mode);
-        G80CrtcSetScale(output->crtc, mode, scale, TRUE);
-        xfree(mode);
+        oldScale = pPriv->scale;
+        pPriv->scale = scale;
+        if(output->crtc) {
+            xf86CrtcPtr crtc = output->crtc;
+
+            if(!xf86CrtcSetMode(crtc, &crtc->desiredMode, crtc->desiredRotation,
+                                crtc->desiredX, crtc->desiredY)) {
+                xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
+                           "Failed to set scaling to %s for output %s\n",
+                           modes[i].name, output->name);
+
+                // Restore old scale and try again.
+                pPriv->scale = oldScale;
+                if(!xf86CrtcSetMode(crtc, &crtc->desiredMode,
+                                    crtc->desiredRotation, crtc->desiredX,
+                                    crtc->desiredY)) {
+                    xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
+                               "Failed to restore old scaling for output %s\n",
+                               output->name);
+                }
+
+                return FALSE;
+            }
+        }
         return TRUE;
     }
 
@@ -328,7 +395,7 @@ static const xf86OutputFuncsRec G80SorTM
     .save = NULL,
     .restore = NULL,
     .mode_valid = G80TMDSModeValid,
-    .mode_fixup = G80OutputModeFixup,
+    .mode_fixup = G80SorTMDSModeFixup,
     .prepare = G80OutputPrepare,
     .commit = G80OutputCommit,
     .mode_set = G80SorModeSet,
@@ -346,7 +413,7 @@ static const xf86OutputFuncsRec G80SorLV
     .save = NULL,
     .restore = NULL,
     .mode_valid = G80LVDSModeValid,
-    .mode_fixup = G80SorModeFixupScale,
+    .mode_fixup = G80SorModeFixup,
     .prepare = G80OutputPrepare,
     .commit = G80OutputCommit,
     .mode_set = G80SorModeSet,


More information about the xorg-commit mailing list