mirror of
https://github.com/X11Libre/xf86-video-nv.git
synced 2026-03-24 01:24:21 +00:00
Add rudimentary VBE-based dual head support for pre-G80.
This commit is contained in:
@@ -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
|
||||
|
||||
214
src/nv_driver.c
214
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,
|
||||
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, DisplayModePtr mode)
|
||||
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 pScreen, int argc, char **argv)
|
||||
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 pScreen, int argc, char **argv)
|
||||
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)
|
||||
|
||||
15
src/nv_hw.c
15
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
Reference in New Issue
Block a user