[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

xserver-xorg-video-nv: Changes to 'upstream-unstable'



 Makefile.am            |    2 
 README.G80             |    5 
 compat/.gitignore      |    2 
 compat/Makefile.am     |   15 +
 compat/README          |    7 
 configure.ac           |   72 +++++--
 man/Makefile.am        |    9 
 man/nv.man             |   29 +-
 src/Makefile.am        |   31 ++-
 src/g80_cursor.c       |  150 +++------------
 src/g80_cursor.h       |    8 
 src/g80_dac.c          |  199 ++++++++++++++++++++
 src/g80_ddc.c          |  230 -----------------------
 src/g80_ddc.h          |    1 
 src/g80_display.c      |  485 +++++++++++++++++++++++++------------------------
 src/g80_display.h      |   22 +-
 src/g80_driver.c       |  239 ++++++++++++++----------
 src/g80_exa.c          |  329 +++++++++++++++++++++++++++++++++
 src/g80_exa.h          |    1 
 src/g80_output.c       |  350 +++++++++++++++++++++++++++++++++++
 src/g80_output.h       |   31 +++
 src/g80_sor.c          |  301 ++++++++++++++++++++++++++++++
 src/g80_type.h         |   40 ++--
 src/g80_xaa.c          |   10 -
 src/g80_xaa.h          |    5 
 src/local_xf86Rename.h |   23 ++
 src/nv_dac.c           |    3 
 src/nv_driver.c        |  236 ++++++++++++++++++++---
 src/nv_hw.c            |   19 +
 src/nv_include.h       |    5 
 src/nv_local.h         |    3 
 src/nv_setup.c         |    3 
 src/nv_type.h          |   11 +
 src/nv_video.c         |   13 -
 src/riva_hw.c          |    2 
 src/riva_include.h     |    5 
 src/riva_local.h       |    3 
 37 files changed, 2070 insertions(+), 829 deletions(-)

New commits:
commit 209c84e788faf3c4d0ce053e5f29ff5f5b798628
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Mon Jun 18 13:08:31 2007 -0700

    Bump to 2.1.0.

diff --git a/configure.ac b/configure.ac
index 66a1efb..0b5c14b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@
 
 AC_PREREQ(2.57)
 AC_INIT([xf86-video-nv],
-        2.0.96,
+        2.1.0,
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         xf86-video-nv)
 

commit 24770ccf880f056bc0db9464249caca10692fb56
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Mon Jun 18 12:36:29 2007 -0700

    Fix some random colormap corruption on DFPs with certain pre-G80 GPUs.

diff --git a/src/nv_dac.c b/src/nv_dac.c
index 3fb687f..e1f0740 100644
--- a/src/nv_dac.c
+++ b/src/nv_dac.c
@@ -1,6 +1,6 @@
  /***************************************************************************\
 |*                                                                           *|
-|*       Copyright 2003 NVIDIA, Corporation.  All rights reserved.           *|
+|*       Copyright 2007 NVIDIA, Corporation.  All rights reserved.           *|
 |*                                                                           *|
 |*     NOTICE TO USER:   The source code  is copyrighted under  U.S. and     *|
 |*     international laws.  Users and possessors of this source code are     *|
@@ -221,6 +221,7 @@ NVDACInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
        }
        nvReg->crtcSync = pNv->PRAMDAC[0x0828/4];
        nvReg->crtcSync += NVDACPanelTweaks(pNv, nvReg);
+       nvReg->crtcVSync = pNv->fpVTotal - 6;
     }
 
     nvReg->vpll = nvReg->pll;
diff --git a/src/nv_hw.c b/src/nv_hw.c
index ae499fa..63f9067 100644
--- a/src/nv_hw.c
+++ b/src/nv_hw.c
@@ -1501,6 +1501,7 @@ void NVLoadStateExt (
     } else {
        pNv->PRAMDAC[0x0848/4] = state->scale;
        pNv->PRAMDAC[0x0828/4] = state->crtcSync;
+       pNv->PRAMDAC[0x0808/4] = state->crtcVSync;
     }
     pNv->PRAMDAC[0x0600/4] = state->general;
 
@@ -1588,6 +1589,7 @@ void NVUnloadStateExt
 
     if(pNv->FlatPanel) {
        state->crtcSync = pNv->PRAMDAC[0x0828/4];
+       state->crtcVSync = pNv->PRAMDAC[0x0808/4];
     }
 }
 
diff --git a/src/nv_setup.c b/src/nv_setup.c
index 71d7955..1bf58e0 100644
--- a/src/nv_setup.c
+++ b/src/nv_setup.c
@@ -687,6 +687,7 @@ NVCommonSetup(ScrnInfoPtr pScrn)
     if(pNv->FlatPanel && !pNv->Television) {
        pNv->fpWidth = pNv->PRAMDAC[0x0820/4] + 1;
        pNv->fpHeight = pNv->PRAMDAC[0x0800/4] + 1;
+       pNv->fpVTotal = pNv->PRAMDAC[0x804/4] + 1;
        pNv->fpSyncs = pNv->PRAMDAC[0x0848/4] & 0x30000033;
        xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Panel size is %i x %i\n",
                   pNv->fpWidth, pNv->fpHeight);
diff --git a/src/nv_type.h b/src/nv_type.h
index b10babc..b4f1cd3 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -70,6 +70,7 @@ typedef struct _riva_hw_state
     U032 timingV;
     U032 displayV;
     U032 crtcSync;
+    U032 crtcVSync;
 } RIVA_HW_STATE, *NVRegPtr;
 
 
@@ -161,6 +162,7 @@ typedef struct {
     Bool                fpScaler;
     int                 fpWidth;
     int                 fpHeight;
+    CARD32              fpVTotal;
     CARD32              fpSyncs;
     Bool                usePanelTweak;
     int                 PanelTweak;

commit 4e56465a79587c4df6bf1dfd7cc87a4f22707a8f
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Thu Jun 7 18:28:56 2007 -0700

    G80: Mode validation.
    
    Disable LVDS modes larger than the native resolution.
    Disable dual-link TMDS modes for now since they don't work reliably.

diff --git a/src/g80_output.c b/src/g80_output.c
index 6a2723b..11bdb25 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -164,8 +164,10 @@ G80OutputSetPClk(xf86OutputPtr output, int pclk)
 int
 G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
 {
-    if(mode->Clock > 400000 || mode->Clock < 25000)
-        return MODE_CLOCK_RANGE;
+    if(mode->Clock > 400000)
+        return MODE_CLOCK_HIGH;
+    if(mode->Clock < 25000)
+        return MODE_CLOCK_LOW;
 
     return MODE_OK;
 }
diff --git a/src/g80_sor.c b/src/g80_sor.c
index a51e5e0..2ab9f2e 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.c
@@ -65,6 +65,30 @@ G80SorDPMSSet(xf86OutputPtr output, int mode)
     while((pNv->reg[(0x61C030+off)/4] & 0x10000000));
 }
 
+static int
+G80TMDSModeValid(xf86OutputPtr output, DisplayModePtr mode)
+{
+    // Disable dual-link modes until I can find a way to make them work
+    // reliably.
+    if (mode->Clock > 165000)
+        return MODE_CLOCK_HIGH;
+
+    return G80OutputModeValid(output, mode);
+}
+
+static int
+G80LVDSModeValid(xf86OutputPtr output, DisplayModePtr mode)
+{
+    G80OutputPrivPtr pPriv = output->driver_private;
+    DisplayModePtr native = pPriv->nativeMode;
+
+    // Ignore modes larger than the native res.
+    if (mode->HDisplay > native->HDisplay || mode->VDisplay > native->VDisplay)
+        return MODE_PANEL;
+
+    return G80OutputModeValid(output, mode);
+}
+
 static void
 G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
               DisplayModePtr adjusted_mode)
@@ -180,7 +204,7 @@ static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = {
     .dpms = G80SorDPMSSet,
     .save = NULL,
     .restore = NULL,
-    .mode_valid = G80OutputModeValid,
+    .mode_valid = G80TMDSModeValid,
     .mode_fixup = G80OutputModeFixup,
     .prepare = G80OutputPrepare,
     .commit = G80OutputCommit,
@@ -194,7 +218,7 @@ static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = {
     .dpms = G80SorDPMSSet,
     .save = NULL,
     .restore = NULL,
-    .mode_valid = G80OutputModeValid,
+    .mode_valid = G80LVDSModeValid,
     .mode_fixup = G80SorModeFixupScale,
     .prepare = G80OutputPrepare,
     .commit = G80OutputCommit,

commit 6b71721439802bffd715602af3036083ff442449
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Mon Jun 4 23:15:42 2007 -0700

    G80: LVDS support.

diff --git a/src/g80_output.c b/src/g80_output.c
index d68250f..6a2723b 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -85,6 +85,7 @@ static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
                                    "for port %i\n",
                                    or, pNv->i2cMap[port].sor, port);
                     pNv->i2cMap[port].sor = or;
+                    pNv->i2cMap[port].panelType = (type == 2) ? TMDS : LVDS;
                     break;
             }
         }
@@ -317,7 +318,8 @@ G80CreateOutputs(ScrnInfoPtr pScrn)
         if(pNv->i2cMap[i].dac != -1)
             dac = G80CreateDac(pScrn, pNv->i2cMap[i].dac);
         if(pNv->i2cMap[i].sor != -1)
-            sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor);
+            sor = G80CreateSor(pScrn, pNv->i2cMap[i].sor,
+                               pNv->i2cMap[i].panelType);
 
         if(dac) {
             G80OutputPrivPtr pPriv = dac->driver_private;
diff --git a/src/g80_output.h b/src/g80_output.h
index 0b666f5..900b76d 100644
--- a/src/g80_output.h
+++ b/src/g80_output.h
@@ -1,6 +1,8 @@
 typedef struct G80OutputPrivRec {
     ORType type;
     ORNum or;
+    PanelType panelType;
+    DisplayModePtr nativeMode;
 
     xf86OutputPtr partner;
     I2CBusPtr i2c;
@@ -26,4 +28,4 @@ xf86OutputPtr G80CreateDac(ScrnInfoPtr, ORNum);
 Bool G80DacLoadDetect(xf86OutputPtr);
 
 /* g80_sor.c */
-xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum);
+xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum, PanelType);
diff --git a/src/g80_sor.c b/src/g80_sor.c
index ea7e015..a51e5e0 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.c
@@ -38,8 +38,9 @@ G80SorSetPClk(xf86OutputPtr output, int pclk)
     G80Ptr pNv = G80PTR(output->scrn);
     G80OutputPrivPtr pPriv = output->driver_private;
     const int orOff = 0x800 * pPriv->or;
+    const int limit = pPriv->panelType == LVDS ? 112000 : 165000;
 
-    pNv->reg[(0x00614300+orOff)/4] = (pclk > 165000) ? 0x101 : 0;
+    pNv->reg[(0x00614300+orOff)/4] = (pclk > limit) ? 0x101 : 0;
 }
 
 static void
@@ -61,6 +62,7 @@ G80SorDPMSSet(xf86OutputPtr output, int mode)
         tmp &= ~1;
 
     pNv->reg[(0x0061C004+off)/4] = tmp;
+    while((pNv->reg[(0x61C030+off)/4] & 0x10000000));
 }
 
 static void
@@ -70,6 +72,7 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
     ScrnInfoPtr pScrn = output->scrn;
     G80OutputPrivPtr pPriv = output->driver_private;
     const int sorOff = 0x40 * pPriv->or;
+    CARD32 type;
 
     if(!adjusted_mode) {
         /* Disconnect the SOR */
@@ -77,6 +80,13 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
         return;
     }
 
+    if(pPriv->panelType == LVDS)
+        type = 0;
+    else if(adjusted_mode->Clock > 165000)
+        type = 0x500;
+    else
+        type = 0x100;
+
     // This wouldn't be necessary, but the server is stupid and calls
     // G80SorDPMSSet after the output is disconnected, even though the hardware
     // turns it off automatically.
@@ -84,7 +94,7 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
 
     C(0x00000600 + sorOff,
         (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) |
-        (adjusted_mode->Clock > 165000 ? 0x500 : 0x100) |
+        type |
         ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
         ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0));
 }
@@ -92,7 +102,6 @@ G80SorModeSet(xf86OutputPtr output, DisplayModePtr mode,
 static xf86OutputStatus
 G80SorDetect(xf86OutputPtr output)
 {
-
     G80OutputPrivPtr pPriv = output->driver_private;
 
     /* Assume physical status isn't going to change before the BlockHandler */
@@ -103,16 +112,71 @@ G80SorDetect(xf86OutputPtr output)
     return pPriv->cached_status;
 }
 
+static xf86OutputStatus
+G80SorLVDSDetect(xf86OutputPtr output)
+{
+    /* Assume LVDS is always connected */
+    return XF86OutputStatusConnected;
+}
+
 static void
 G80SorDestroy(xf86OutputPtr output)
 {
+    G80OutputPrivPtr pPriv = output->driver_private;
+
     G80OutputDestroy(output);
 
+    if(pPriv->nativeMode) {
+        if(pPriv->nativeMode->name)
+            xfree(pPriv->nativeMode->name);
+        xfree(pPriv->nativeMode);
+    }
+
     xfree(output->driver_private);
     output->driver_private = NULL;
 }
 
-static const xf86OutputFuncsRec G80SorOutputFuncs = {
+/******************** LVDS ********************/
+static Bool
+G80SorModeFixupScale(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);
+
+    return TRUE;
+}
+
+static DisplayModePtr
+G80SorGetLVDSModes(xf86OutputPtr output)
+{
+    G80OutputPrivPtr pPriv = output->driver_private;
+    return xf86DuplicateMode(pPriv->nativeMode);
+}
+
+static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = {
     .dpms = G80SorDPMSSet,
     .save = NULL,
     .restore = NULL,
@@ -126,33 +190,88 @@ static const xf86OutputFuncsRec G80SorOutputFuncs = {
     .destroy = G80SorDestroy,
 };
 
+static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = {
+    .dpms = G80SorDPMSSet,
+    .save = NULL,
+    .restore = NULL,
+    .mode_valid = G80OutputModeValid,
+    .mode_fixup = G80SorModeFixupScale,
+    .prepare = G80OutputPrepare,
+    .commit = G80OutputCommit,
+    .mode_set = G80SorModeSet,
+    .detect = G80SorLVDSDetect,
+    .get_modes = G80SorGetLVDSModes,
+    .destroy = G80SorDestroy,
+};
+
+static DisplayModePtr
+GetLVDSNativeMode(G80Ptr pNv)
+{
+    DisplayModePtr mode = xnfcalloc(1, sizeof(DisplayModeRec));
+    const CARD32 size = pNv->reg[0x00610B4C/4];
+    const int width = size & 0x3fff;
+    const int height = (size >> 16) & 0x3fff;
+
+    mode->HDisplay = mode->CrtcHDisplay = width;
+    mode->VDisplay = mode->CrtcVDisplay = height;
+    mode->Clock           = pNv->reg[0x610AD4/4] & 0x3fffff;
+    mode->CrtcHBlankStart = pNv->reg[0x610AFC/4];
+    mode->CrtcHSyncEnd    = pNv->reg[0x610B04/4];
+    mode->CrtcHBlankEnd   = pNv->reg[0x610AE8/4];
+    mode->CrtcHTotal      = pNv->reg[0x610AF4/4];
+
+    mode->next = mode->prev = NULL;
+    mode->status = MODE_OK;
+    mode->type = M_T_DRIVER | M_T_PREFERRED;
+
+    xf86SetModeDefaultName(mode);
+
+    return mode;
+}
+
 xf86OutputPtr
-G80CreateSor(ScrnInfoPtr pScrn, ORNum or)
+G80CreateSor(ScrnInfoPtr pScrn, ORNum or, PanelType panelType)
 {
     G80Ptr pNv = G80PTR(pScrn);
     G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
     const int off = 0x800 * or;
     xf86OutputPtr output;
     char orName[5];
+    const xf86OutputFuncsRec *funcs;
 
     if(!pPriv)
         return FALSE;
 
-    pNv->reg[(0x61C00C+off)/4] = 0x03010700;
-    pNv->reg[(0x61C010+off)/4] = 0x0000152f;
-    pNv->reg[(0x61C014+off)/4] = 0x00000000;
-    pNv->reg[(0x61C018+off)/4] = 0x00245af8;
+    if(panelType == LVDS) {
+        strcpy(orName, "LVDS");
+        funcs = &G80SorLVDSOutputFuncs;
+    } else {
+        snprintf(orName, 5, "DVI%d", or);
+        pNv->reg[(0x61C00C+off)/4] = 0x03010700;
+        pNv->reg[(0x61C010+off)/4] = 0x0000152f;
+        pNv->reg[(0x61C014+off)/4] = 0x00000000;
+        pNv->reg[(0x61C018+off)/4] = 0x00245af8;
+        funcs = &G80SorTMDSOutputFuncs;
+    }
 
-    snprintf(orName, 5, "DVI%i", or);
-    output = xf86OutputCreate(pScrn, &G80SorOutputFuncs, orName);
+    output = xf86OutputCreate(pScrn, funcs, orName);
 
     pPriv->type = SOR;
     pPriv->or = or;
+    pPriv->panelType = panelType;
     pPriv->cached_status = XF86OutputStatusUnknown;
     pPriv->set_pclk = G80SorSetPClk;
     output->driver_private = pPriv;
     output->interlaceAllowed = TRUE;
     output->doubleScanAllowed = TRUE;
 
+    if(panelType == LVDS) {
+        pPriv->nativeMode = GetLVDSNativeMode(pNv);
+
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "%s native size %dx%d\n",
+                   orName, pPriv->nativeMode->HDisplay,
+                   pPriv->nativeMode->VDisplay);
+    }
+
     return output;
 }
diff --git a/src/g80_type.h b/src/g80_type.h
index 15b8792..819a9f6 100644
--- a/src/g80_type.h
+++ b/src/g80_type.h
@@ -25,6 +25,11 @@ typedef enum ORNum {
    SOR1 = 1
 } ORNum;
 
+typedef enum PanelType {
+    TMDS,
+    LVDS,
+} PanelType;
+
 typedef enum AccelMethod {
     XAA,
     EXA,
@@ -41,8 +46,9 @@ typedef struct G80Rec {
     const unsigned char*table1;
     int                 offscreenHeight;
     struct {
-        ORNum dac;
-        ORNum sor;
+        ORNum           dac;
+        ORNum           sor;
+        PanelType       panelType;
     } i2cMap[4];
 
     xf86Int10InfoPtr    int10;

commit 70b304cd0df0af515ce8414559f28a7ca7825517
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Mon Jun 4 22:38:14 2007 -0700

    G80: Rearrange HW video timing computations.
    
    Compute the HW parameters in G80CrtcModeFixup and stash them in adjusted_mode.
    Move some register writes into G80CreateSor.

diff --git a/src/g80_display.c b/src/g80_display.c
index 652a5a9..d10f2d6 100644
--- a/src/g80_display.c
+++ b/src/g80_display.c
@@ -40,6 +40,7 @@ typedef struct G80CrtcPrivRec {
     Head head;
     int pclk; /* Target pixel clock in kHz */
     Bool cursorVisible;
+    Bool skipModeFixup;
 } G80CrtcPrivRec, *G80CrtcPrivPtr;
 
 static void G80CrtcShowHideCursor(xf86CrtcPtr crtc, Bool show, Bool update);
@@ -234,14 +235,6 @@ G80DispPreInit(ScrnInfoPtr pScrn)
     pNv->reg[0x006101D8/4] = pNv->reg[0x0061B000/4];
     pNv->reg[0x006101E0/4] = pNv->reg[0x0061C000/4];
     pNv->reg[0x006101E4/4] = pNv->reg[0x0061C800/4];
-    pNv->reg[0x0061c00c/4] = 0x03010700;
-    pNv->reg[0x0061c010/4] = 0x0000152f;
-    pNv->reg[0x0061c014/4] = 0x00000000;
-    pNv->reg[0x0061c018/4] = 0x00245af8;
-    pNv->reg[0x0061c80c/4] = 0x03010700;
-    pNv->reg[0x0061c810/4] = 0x0000152f;
-    pNv->reg[0x0061c814/4] = 0x00000000;
-    pNv->reg[0x0061c818/4] = 0x00245af8;
     pNv->reg[0x0061A004/4] = 0x80550000;
     pNv->reg[0x0061A010/4] = 0x00000001;
     pNv->reg[0x0061A804/4] = 0x80550000;
@@ -308,13 +301,35 @@ G80DispShutdown(ScrnInfoPtr pScrn)
     pNv->reg[0x00610200/4] = 0;
     pNv->reg[0x00610300/4] = 0;
     while((pNv->reg[0x00610200/4] & 0x1e0000) != 0);
+    while((pNv->reg[0x61C030/4] & 0x10000000));
+    while((pNv->reg[0x61C830/4] & 0x10000000));
 }
 
 static Bool
 G80CrtcModeFixup(xf86CrtcPtr crtc,
                  DisplayModePtr mode, DisplayModePtr adjusted_mode)
 {
-    // TODO: Fix up the mode here
+    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);
+
     return TRUE;
 }
 
@@ -324,36 +339,21 @@ G80CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode,
 {
     ScrnInfoPtr pScrn = crtc->scrn;
     G80CrtcPrivPtr pPriv = crtc->driver_private;
-    const int HDisplay = mode->HDisplay, VDisplay = mode->VDisplay;
+    const int HDisplay = adjusted_mode->HDisplay, VDisplay = adjusted_mode->VDisplay;
     const int headOff = 0x400 * G80CrtcGetHead(crtc);
-    int interlaceDiv, fudge;
 
-    // TODO: Use adjusted_mode and fix it up in G80CrtcModeFixup
-    pPriv->pclk = mode->Clock;
-
-    /* Magic mode timing fudge factor */
-    fudge = ((mode->Flags & V_INTERLACE) && (mode->Flags & V_DBLSCAN)) ? 2 : 1;
-    interlaceDiv = (mode->Flags & V_INTERLACE) ? 2 : 1;
+    pPriv->pclk = adjusted_mode->Clock;
 
-    C(0x00000804 + headOff, mode->Clock | 0x800000);
-    C(0x00000808 + headOff, (mode->Flags & V_INTERLACE) ? 2 : 0);
+    C(0x00000804 + headOff, adjusted_mode->Clock | 0x800000);
+    C(0x00000808 + headOff, (adjusted_mode->Flags & V_INTERLACE) ? 2 : 0);
     C(0x00000810 + headOff, 0);
     C(0x0000082C + headOff, 0);
-    C(0x00000814 + headOff, mode->CrtcVTotal << 16 | mode->CrtcHTotal);
-    C(0x00000818 + headOff,
-        ((mode->CrtcVSyncEnd - mode->CrtcVSyncStart) / interlaceDiv - 1) << 16 |
-        (mode->CrtcHSyncEnd - mode->CrtcHSyncStart - 1));
-    C(0x0000081C + headOff,
-        ((mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / interlaceDiv - fudge) << 16 |
-        (mode->CrtcHBlankEnd - mode->CrtcHSyncStart - 1));
-    C(0x00000820 + headOff,
-        ((mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / interlaceDiv - fudge) << 16 |
-        (mode->CrtcHTotal - mode->CrtcHSyncStart + mode->CrtcHBlankStart - 1));
-    if(mode->Flags & V_INTERLACE) {
-        C(0x00000824 + headOff,
-            ((mode->CrtcVTotal + mode->CrtcVBlankEnd - mode->CrtcVSyncStart) / 2 - 2) << 16 |
-            ((2*mode->CrtcVTotal - mode->CrtcVSyncStart + mode->CrtcVBlankStart) / 2 - 2));
-    }
+    C(0x00000814 + headOff, adjusted_mode->CrtcHBlankStart);
+    C(0x00000818 + headOff, adjusted_mode->CrtcHSyncEnd);
+    C(0x0000081C + headOff, adjusted_mode->CrtcHBlankEnd);
+    C(0x00000820 + headOff, adjusted_mode->CrtcHTotal);
+    if(adjusted_mode->Flags & V_INTERLACE)
+        C(0x00000824 + headOff, adjusted_mode->CrtcHSkew);
     C(0x00000868 + headOff, pScrn->virtualY << 16 | pScrn->virtualX);
     C(0x0000086C + headOff, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
     switch(pScrn->depth) {
@@ -362,9 +362,8 @@ G80CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode,
         case 16: C(0x00000870 + headOff, 0xE800); break;
         case 24: C(0x00000870 + headOff, 0xCF00); break;
     }
-    C(0x000008A0 + headOff, 0);
-    if((mode->Flags & V_DBLSCAN) || (mode->Flags & V_INTERLACE) ||
-       mode->CrtcHDisplay != HDisplay || mode->CrtcVDisplay != VDisplay) {
+    if((adjusted_mode->Flags & V_DBLSCAN) || (adjusted_mode->Flags & V_INTERLACE) ||
+       adjusted_mode->CrtcHDisplay != HDisplay || adjusted_mode->CrtcVDisplay != VDisplay) {
         C(0x000008A4 + headOff, 9);
     } else {
         C(0x000008A4 + headOff, 0);
@@ -373,8 +372,8 @@ G80CrtcModeSet(xf86CrtcPtr crtc, DisplayModePtr mode,
     C(0x000008C0 + headOff, y << 16 | x);
     C(0x000008C8 + headOff, VDisplay << 16 | HDisplay);
     C(0x000008D4 + headOff, 0);
-    C(0x000008D8 + headOff, mode->CrtcVDisplay << 16 | mode->CrtcHDisplay);
-    C(0x000008DC + headOff, mode->CrtcVDisplay << 16 | mode->CrtcHDisplay);
+    C(0x000008D8 + headOff, adjusted_mode->CrtcVDisplay << 16 | adjusted_mode->CrtcHDisplay);
+    C(0x000008DC + headOff, adjusted_mode->CrtcVDisplay << 16 | adjusted_mode->CrtcHDisplay);
 
     G80CrtcBlankScreen(crtc, FALSE);
 }
@@ -458,6 +457,7 @@ static void
 G80CrtcPrepare(xf86CrtcPtr crtc)
 {
     ScrnInfoPtr pScrn = crtc->scrn;
+    G80CrtcPrivPtr pPriv = crtc->driver_private;
     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
     int i;
 
@@ -467,6 +467,15 @@ G80CrtcPrepare(xf86CrtcPtr crtc)
         if(!output->crtc)
             output->funcs->mode_set(output, NULL, NULL);
     }
+
+    pPriv->skipModeFixup = FALSE;
+}
+
+void
+G80CrtcSkipModeFixup(xf86CrtcPtr crtc)
+{
+    G80CrtcPrivPtr pPriv = crtc->driver_private;
+    pPriv->skipModeFixup = TRUE;
 }
 
 static void
diff --git a/src/g80_display.h b/src/g80_display.h
index fac7877..d6f24f4 100644
--- a/src/g80_display.h
+++ b/src/g80_display.h
@@ -11,5 +11,6 @@ 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 G80DispCreateCrtcs(ScrnInfoPtr pScrn);
diff --git a/src/g80_sor.c b/src/g80_sor.c
index 90119f0..ea7e015 100644
--- a/src/g80_sor.c
+++ b/src/g80_sor.c
@@ -129,13 +129,20 @@ static const xf86OutputFuncsRec G80SorOutputFuncs = {
 xf86OutputPtr
 G80CreateSor(ScrnInfoPtr pScrn, ORNum or)
 {
+    G80Ptr pNv = G80PTR(pScrn);
     G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
+    const int off = 0x800 * or;
     xf86OutputPtr output;
     char orName[5];
 
     if(!pPriv)
         return FALSE;
 
+    pNv->reg[(0x61C00C+off)/4] = 0x03010700;
+    pNv->reg[(0x61C010+off)/4] = 0x0000152f;
+    pNv->reg[(0x61C014+off)/4] = 0x00000000;
+    pNv->reg[(0x61C018+off)/4] = 0x00245af8;
+
     snprintf(orName, 5, "DVI%i", or);
     output = xf86OutputCreate(pScrn, &G80SorOutputFuncs, orName);
 

commit 1f4790adcafd402c84a4a761c870a26a5178a4ff
Author: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Date:   Sun Jun 3 11:16:55 2007 +1000

    Fix build. Including xf86DDC.h before we include xf86.h doesn't fly
    and it's not necessary anyway as it's pulled in by g80_type.h
    
    Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

diff --git a/src/g80_output.c b/src/g80_output.c
index 354d39a..d68250f 100644
--- a/src/g80_output.c
+++ b/src/g80_output.c
@@ -27,7 +27,6 @@
 #endif
 
 #include <strings.h>
-#include <xf86DDC.h>
 
 #include "g80_type.h"
 #include "g80_output.h"

commit 9b8470e9c81e6ce2c8cd69942fb2ffd2d4c06102
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Wed May 16 14:45:36 2007 -0700

    Bump to 2.0.96.

diff --git a/configure.ac b/configure.ac
index 3adb00b..66a1efb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@
 
 AC_PREREQ(2.57)
 AC_INIT([xf86-video-nv],
-        2.0.95,
+        2.0.96,
         [https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
         xf86-video-nv)
 

commit 51c6425bea6e4ef02f7b76e58e759f99b0e993e8
Author: Aaron Plattner <aplattner@nvidia.com>
Date:   Thu May 10 17:09:36 2007 -0700

    Add rudimentary VBE-based dual head support for pre-G80.

diff --git a/man/nv.man b/man/nv.man
index 9f5917f..e9bcec9 100644
--- a/man/nv.man
+++ b/man/nv.man
@@ -93,6 +93,11 @@ the wrong one, this option may be used to force usage of a particular output.
 The options are "0" or "1".
 Default: autodetected.
 .TP
+.BI "Option \*qDualhead\*q \*q" boolean \*q
+Enables simple VBE-based dual head mode.
+This sets the same resolution on both outputs and lays them out side-by-side.
+The screens will be panned together as one big metamode if the virtual desktop is larger than both screens combined.
+.TP
 .BI "Option \*qFlatPanel\*q \*q" boolean \*q
 The driver usually can autodetect the presence of a digital flat panel.  In
 the case that this fails, this option can be used to force the driver to 
diff --git a/src/nv_driver.c b/src/nv_driver.c
index a20bf64..4c2a395 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -34,6 +34,7 @@
 #include "nv_include.h"
 
 #include "xf86int10.h"
+#include "vbeModes.h"
 
 const   OptionInfoRec * RivaAvailableOptions(int chipid, int busid);
 Bool    RivaGetScrnInfoRec(PciChipsets *chips, int chip);
@@ -70,8 +71,10 @@ static Bool	NVMapMem(ScrnInfoPtr pScrn);
 static Bool	NVMapMemFBDev(ScrnInfoPtr pScrn);
 static Bool	NVUnmapMem(ScrnInfoPtr pScrn);
 static void	NVSave(ScrnInfoPtr pScrn);
+static void	NVSaveRestoreVBE(ScrnInfoPtr, vbeSaveRestoreFunction);
 static void	NVRestore(ScrnInfoPtr pScrn);
 static Bool	NVModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
+static Bool	NVSetModeVBE(ScrnInfoPtr pScrn, DisplayModePtr pMode);
 
 
 /*
@@ -410,6 +413,17 @@ static const char *vbeSymbols[] = {
     "vbeDoEDID",
     NULL
 };
+
+static const char *vbeModeSymbols[] = {
+    "VBEExtendedInit",
+    "VBEGetVBEInfo",
+    "VBEGetModePool",
+    "VBEValidateModes",
+    "VBESetModeParameters",
+    "VBEGetVBEMode",
+    "VBESetVBEMode",
+    NULL
+};
 #endif
 
 static const char *i2cSymbols[] = {
@@ -488,7 +502,8 @@ typedef enum {
     OPTION_FP_DITHER,
     OPTION_CRTC_NUMBER,
     OPTION_FP_SCALE,
-    OPTION_FP_TWEAK
+    OPTION_FP_TWEAK,
+    OPTION_DUALHEAD,
 } NVOpts;
 
 
@@ -505,6 +520,7 @@ static const OptionInfoRec NVOptions[] = {
     { OPTION_CRTC_NUMBER,	"CrtcNumber",	OPTV_INTEGER,	{0}, FALSE },
     { OPTION_FP_SCALE,          "FPScale",      OPTV_BOOLEAN,   {0}, FALSE },
     { OPTION_FP_TWEAK,          "FPTweak",      OPTV_INTEGER,   {0}, FALSE },
+    { OPTION_DUALHEAD,          "DualHead",     OPTV_BOOLEAN,   {0}, FALSE },
     { -1,                       NULL,           OPTV_NONE,      {0}, FALSE }
 };
 
@@ -821,6 +837,27 @@ NVSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
     return NVModeInit(pScrn, mode);
 }
 
+Bool
+NVSwitchModeVBE(int scrnIndex, DisplayModePtr mode, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+    NVPtr pNv = NVPTR(pScrn);
+    const Bool disableAccess = pNv->accessEnabled;
+
+    if(disableAccess)
+        pScrn->EnableDisableFBAccess(scrnIndex, FALSE);
+
+    NVSync(pScrn);
+    if (!NVSetModeVBE(pScrn, mode))
+        return FALSE;
+    NVAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
+
+    if(disableAccess)
+        pScrn->EnableDisableFBAccess(scrnIndex, TRUE);
+
+    return TRUE;
+}
+
 /*
  * This function is used to initialize the Start Address - the first
  * displayed location in the video memory.
@@ -869,6 +906,17 @@ NVEnterVTFBDev(int scrnIndex, int flags)
     return TRUE;
 }
 
+static Bool
+NVEnterVTVBE(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+    if (!NVSetModeVBE(pScrn, pScrn->currentMode))
+        return FALSE;
+    NVAdjustFrame(scrnIndex, 0, 0, 0);
+    return TRUE;
+}
+
 /*
  * This is called when VT switching away from the X server.  Its job is
  * to restore the previous (text) mode.
@@ -888,7 +936,14 @@ NVLeaveVT(int scrnIndex, int flags)
     NVLockUnlock(pNv, 1);
 }
 
+static void
+NVLeaveVTVBE(int scrnIndex, int flags)
+{
+    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
 
+    NVSync(pScrn);
+    NVSaveRestoreVBE(pScrn, MODE_RESTORE);
+}
 
 static void 
 NVBlockHandler (
@@ -930,9 +985,15 @@ NVCloseScreen(int scrnIndex, ScreenPtr pScreen)
     NVPtr pNv = NVPTR(pScrn);
 
     if (pScrn->vtSema) {
-        NVSync(pScrn);
-        NVRestore(pScrn);
-        NVLockUnlock(pNv, 1);
+        if (!pNv->NoAccel)
+            NVSync(pScrn);
+
+        if (pNv->VBEDualhead) {
+            NVSaveRestoreVBE(pScrn, MODE_RESTORE);
+        } else {
+            NVRestore(pScrn);
+            NVLockUnlock(pNv, 1);
+        }
     }
 
     NVUnmapMem(pScrn);
@@ -956,6 +1017,16 @@ NVCloseScreen(int scrnIndex, ScreenPtr pScreen)
     return (*pScreen->CloseScreen)(scrnIndex, pScreen);
 }
 
+static void
+NVEnableDisableFBAccess(int scrnIndex, Bool enable)
+{
+    NVPtr pNv = NVPTR(xf86Screens[scrnIndex]);
+
+    pNv->accessEnabled = enable;
+    pNv->EnableDisableFBAccess(scrnIndex, enable);
+}
+
+
 /* Free up any persistent data structures */
 
 /* Optional */
@@ -1404,7 +1475,43 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
     } else {
         pNv->usePanelTweak = FALSE;
     }
-    
+
+    if (xf86ReturnOptValBool(pNv->Options, OPTION_DUALHEAD, FALSE)) {
+        if (pNv->FBDev)
+            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+                       "FBDev and Dualhead are incompatible.\n");
+        else
+            pNv->VBEDualhead = TRUE;
+    }
+
+    if (pNv->VBEDualhead) {
+        if (!xf86LoadSubModule(pScrn, "vbe")) {
+            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+                       "Couldn't load the VBE module and Dualhead is "
+                       "enabled.\n");
+            return FALSE;
+        }
+        xf86LoaderReqSymLists(vbeModeSymbols, NULL);
+        pNv->pVbe = VBEExtendedInit(NULL, pNv->pEnt->index,
+                                    SET_BIOS_SCRATCH | RESTORE_BIOS_SCRATCH);
+        if (!pNv->pVbe) return FALSE;
+
+        pNv->pVbeInfo = VBEGetVBEInfo(pNv->pVbe);
+        if (!pNv->pVbeInfo) return FALSE;
+
+        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+                   "Using VBE dual-head mode.\n");
+
+        xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+                   "Using software cursor.\n");
+        pNv->HWCursor = FALSE;
+
+        pScrn->SwitchMode    = NVSwitchModeVBE;
+        pScrn->EnterVT       = NVEnterVTVBE;
+        pScrn->LeaveVT       = NVLeaveVTVBE;
+        pScrn->ValidMode     = NULL;
+    }
+
     if (pNv->pEnt->device->MemBase != 0) {
 	/* Require that the config file value matches one of the PCI values. */
 	if (!xf86CheckPciMemBase(pNv->PciInfo, pNv->pEnt->device->MemBase)) {
@@ -1622,14 +1729,31 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
      * pScrn->maxVValue are set.  Since our NVValidMode() already takes
      * care of this, we don't worry about setting them here.
      */
-    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,



Reply to: