xf86-video-nv: man/nv.man src/nv_driver.c src/nv_hw.c src/nv_type.h

Aaron Plattner aplattner at kemper.freedesktop.org
Wed May 16 10:15:35 PDT 2007


 man/nv.man      |    5 +
 src/nv_driver.c |  214 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
 src/nv_hw.c     |   15 +++
 src/nv_type.h   |    9 ++
 4 files changed, 228 insertions(+), 15 deletions(-)

New commits:
diff-tree 51c6425bea6e4ef02f7b76e58e759f99b0e993e8 (from 0415ecaead518123ac6774300241867883a6dd57)
Author: Aaron Plattner <aplattner at 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 t
 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, DisplayModeP
     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 p
     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 p
     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,
-                          pScrn->display->modes, clockRanges,
-                          NULL, 256, max_width,
-                          512, 128, max_height,
-                          pScrn->display->virtualX,
-                          pScrn->display->virtualY,
-                          pNv->ScratchBufferStart,
-                          LOOKUP_BEST_REFRESH);
+    if (pNv->VBEDualhead) {
+        pScrn->modePool = VBEGetModePool(pScrn, pNv->pVbe, pNv->pVbeInfo,
+                                         V_MODETYPE_VBE);
+
+        VBESetModeNames(pScrn->modePool);
+        i = VBEValidateModes(pScrn, pScrn->monitor->Modes,
+                             pScrn->display->modes, clockRanges,
+                             NULL, 256, max_width,
+                             512, 128, max_height,
+                             pScrn->display->virtualX,
+                             pScrn->display->virtualY,
+                             pNv->ScratchBufferStart,
+                             LOOKUP_BEST_REFRESH);
+        if (i > 0)
+            VBESetModeParameters(pScrn, pNv->pVbe);
+    } else {
+        i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+                              pScrn->display->modes, clockRanges,
+                              NULL, 256, max_width,
+                              512, 128, max_height,
+                              pScrn->display->virtualX,
+                              pScrn->display->virtualY,
+                              pNv->ScratchBufferStart,
+                              LOOKUP_BEST_REFRESH);
+    }
 
     if (i < 1 && pNv->FBDev) {
 	fbdevHWUseBuildinMode(pScrn);
@@ -1662,6 +1786,22 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
      */
     xf86SetCrtcForModes(pScrn, 0);
 
+    if (pNv->VBEDualhead) {
+        DisplayModePtr p = pScrn->modes;
+
+        /*
+         * Loop through modes and double their widths.  Stash the real width in
+         * CrtcHDisplay.  Also adjust the screen dimensions.
+         */
+        do {
+            p->CrtcHDisplay = p->HDisplay;
+            p->HDisplay *= 2;
+        } while ((p = p->next) != pScrn->modes);
+
+        pScrn->virtualX *= 2;
+        pScrn->displayWidth *= 2;
+    }
+
     /* Set the current mode to the first in the list */
     pScrn->currentMode = pScrn->modes;
 
@@ -1843,6 +1983,32 @@ NVModeInit(ScrnInfoPtr pScrn, DisplayMod
     return TRUE;
 }
 
+static Bool
+NVSetModeVBE(ScrnInfoPtr pScrn, DisplayModePtr pMode)
+{
+    NVPtr pNv = NVPTR(pScrn);
+    VbeModeInfoData *data;
+    int mode;
+
+    data = (VbeModeInfoData*)pMode->Private;
+    mode = data->mode | 1 << 14;
+
+    if(!VBESetVBEMode(pNv->pVbe, mode, data->block))
+        return FALSE;
+    pNv->PCRTC0[0x820/4] = pNv->PCRTC0[0x2820/4] =
+        pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+    pNv->vbeCRTC1Offset = pMode->CrtcHDisplay * (pScrn->bitsPerPixel / 8);
+
+    pScrn->vtSema = TRUE;
+
+    NVLoadStateExt(pNv, NULL);
+    NVResetGraphics(pScrn);
+
+    pNv->CurrentLayout.mode = pMode;
+
+    return TRUE;
+}
+
 /*
  * Restore the initial (text) mode.
  */
@@ -2015,6 +2181,10 @@ NVScreenInit(int scrnIndex, ScreenPtr pS
 	fbdevHWSave(pScrn);
 	if (!fbdevHWModeInit(pScrn, pScrn->currentMode))
 	    return FALSE;
+    } else if (pNv->VBEDualhead) {
+        NVSaveRestoreVBE(pScrn, MODE_SAVE);
+        if (!NVSetModeVBE(pScrn, pScrn->currentMode))
+            return FALSE;
     } else {
 	/* Save the current state */
 	NVSave(pScrn);
@@ -2210,6 +2380,10 @@ NVScreenInit(int scrnIndex, ScreenPtr pS
     pNv->BlockHandler = pScreen->BlockHandler;
     pScreen->BlockHandler = NVBlockHandler;
 
+    pNv->accessEnabled = TRUE;
+    pNv->EnableDisableFBAccess = pScrn->EnableDisableFBAccess;
+    pScrn->EnableDisableFBAccess = NVEnableDisableFBAccess;
+
 #ifdef RANDR
     /* Install our DriverFunc.  We have to do it this way instead of using the
      * HaveDriverFuncs argument to xf86AddDriver, because InitOutput clobbers
@@ -2248,6 +2422,20 @@ NVSave(ScrnInfoPtr pScrn)
     NVDACSave(pScrn, vgaReg, nvReg, pNv->Primary);
 }
 
+static void
+NVSaveRestoreVBE(ScrnInfoPtr pScrn, vbeSaveRestoreFunction function)
+{
+    NVPtr pNv = NVPTR(pScrn);
+
+    if (function == MODE_SAVE) {
+        VBEGetVBEMode(pNv->pVbe, &pNv->vbeMode);
+        NVSave(pScrn);
+    } else if (function == MODE_RESTORE) {
+        NVRestore(pScrn);
+        VBESetVBEMode(pNv->pVbe, pNv->vbeMode, NULL);
+    }
+}
+
 #ifdef RANDR
 static Bool
 NVRandRGetInfo(ScrnInfoPtr pScrn, Rotation *rotations)
diff --git a/src/nv_hw.c b/src/nv_hw.c
index a221d11..ae499fa 100644
--- a/src/nv_hw.c
+++ b/src/nv_hw.c
@@ -948,7 +948,8 @@ void NVLoadStateExt (
     pNv->PTIMER[0x0100] = 0xFFFFFFFF;
 
     if(pNv->Architecture == NV_ARCH_04) {
-        pNv->PFB[0x0200/4] = state->config;
+        if (state)
+            pNv->PFB[0x0200/4] = state->config;
     } else 
     if((pNv->Architecture < NV_ARCH_40) ||
        ((pNv->Chipset & 0xfff0) == 0x0040))
@@ -1411,6 +1412,11 @@ void NVLoadStateExt (
     pNv->PFIFO[0x0495] = 0x00000001;
     pNv->PFIFO[0x0140] = 0x00000001;
 
+    if(!state) {
+        pNv->CurrentState = NULL;
+        return;
+    }
+
     if(pNv->Architecture >= NV_ARCH_10) {
         if(pNv->twoHeads) {
            pNv->PCRTC0[0x0860/4] = state->head;
@@ -1590,7 +1596,12 @@ void NVSetStartAddress (
     CARD32 start
 )
 {
-    pNv->PCRTC[0x800/4] = start;
+    if (pNv->VBEDualhead) {
+        pNv->PCRTC0[0x800/4] = start;
+        pNv->PCRTC0[0x2800/4] = start + pNv->vbeCRTC1Offset;
+    } else {
+        pNv->PCRTC[0x800/4] = start;
+    }
 }
 
 
diff --git a/src/nv_type.h b/src/nv_type.h
index 6b29d99..b10babc 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -133,6 +133,8 @@ typedef struct {
     void		(*PointerMoved)(int index, int x, int y);
     ScreenBlockHandlerProcPtr BlockHandler;
     CloseScreenProcPtr  CloseScreen;
+    xf86EnableDisableFBAccessProc *EnableDisableFBAccess;
+    Bool                accessEnabled;
     Bool                FBDev;
     int			Rotate;
     NVFBLayout		CurrentLayout;
@@ -174,6 +176,13 @@ typedef struct {
     Bool                WaitVSyncPossible;
     Bool                BlendingPossible;
     Bool                RandRRotation;
+
+    /* VBE dual-head */
+    Bool                VBEDualhead;
+    vbeInfoPtr          pVbe;
+    VbeInfoBlock       *pVbeInfo;
+    int                 vbeMode;
+    CARD32              vbeCRTC1Offset;
 } NVRec, *NVPtr;
 
 #define NVPTR(p) ((NVPtr)((p)->driverPrivate))


More information about the xorg-commit mailing list