summaryrefslogtreecommitdiff
path: root/driver/xf86-video-nv/src
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2007-09-30 14:18:15 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2007-09-30 14:18:15 +0000
commitf25cb21322e90ab2c4d34d5bd8027006950662f6 (patch)
treef1986b6c009c7eba0d01e7a0297c5deec3163b97 /driver/xf86-video-nv/src
parentda0ef05280ed34be0687c3802ab4724f7a9d063a (diff)
xf86-video-nv 2.1.5
Diffstat (limited to 'driver/xf86-video-nv/src')
-rw-r--r--driver/xf86-video-nv/src/g80_cursor.c150
-rw-r--r--driver/xf86-video-nv/src/g80_cursor.h8
-rw-r--r--driver/xf86-video-nv/src/g80_dac.c208
-rw-r--r--driver/xf86-video-nv/src/g80_exa.c329
-rw-r--r--driver/xf86-video-nv/src/g80_exa.h1
-rw-r--r--driver/xf86-video-nv/src/g80_output.c363
-rw-r--r--driver/xf86-video-nv/src/g80_output.h31
-rw-r--r--driver/xf86-video-nv/src/g80_sor.c500
-rw-r--r--driver/xf86-video-nv/src/g80_xaa.h5
-rw-r--r--driver/xf86-video-nv/src/local_xf86Rename.h23
-rw-r--r--driver/xf86-video-nv/src/riva_const.h3
11 files changed, 1500 insertions, 121 deletions
diff --git a/driver/xf86-video-nv/src/g80_cursor.c b/driver/xf86-video-nv/src/g80_cursor.c
index 07422e570..98a27362d 100644
--- a/driver/xf86-video-nv/src/g80_cursor.c
+++ b/driver/xf86-video-nv/src/g80_cursor.c
@@ -21,7 +21,6 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -36,36 +35,10 @@
#define CURSOR_PTR ((CARD32*)pNv->mem + pNv->videoRam * 256 - 0x1000)
-static void G80SetCursorColors(ScrnInfoPtr pScrn, int bg, int fg)
-{
- G80Ptr pNv = G80PTR(pScrn);
- CARD32 *dst = CURSOR_PTR;
- CARD32 *src = pNv->tmpCursor;
- int i, j;
-
- fg |= 0xff000000;
- bg |= 0xff000000;
-
- for(i = 0; i < 128; i++) {
- CARD32 b = *src++;
- CARD32 m = *src++;
-
- for(j = 0; j < 32; j++) {
- if(m & 1)
- *dst = (b & 1) ? fg : bg;
- else
- *dst = 0;
- b >>= 1;
- m >>= 1;
- dst++;
- }
- }
-}
-
-static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
+void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y)
{
- G80Ptr pNv = G80PTR(pScrn);
- const int headOff = 0x1000*pNv->head;
+ G80Ptr pNv = G80PTR(crtc->scrn);
+ const int headOff = 0x1000*G80CrtcGetHead(crtc);
x &= 0xffff;
y &= 0xffff;
@@ -73,113 +46,58 @@ static void G80SetCursorPosition(ScrnInfoPtr pScrn, int x, int y)
pNv->reg[(0x00647080 + headOff)/4] = 0;
}
-static void G80LoadCursorImage(ScrnInfoPtr pScrn, unsigned char *bits)
-{
- G80Ptr pNv = G80PTR(pScrn);
- memcpy(pNv->tmpCursor, bits, sizeof(pNv->tmpCursor));
-}
-
-static void G80HideCursor(ScrnInfoPtr pScrn)
+void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src)
{
- G80Ptr pNv = G80PTR(pScrn);
+ G80Ptr pNv = G80PTR(crtc->scrn);
+ CARD32 *dst = CURSOR_PTR;
- pNv->cursorVisible = FALSE;
- G80DispHideCursor(G80PTR(pScrn), TRUE);
+ /* Assume cursor is 64x64 */
+ memcpy(dst, src, 64 * 64 * 4);
}
-static void G80ShowCursor(ScrnInfoPtr pScrn)
+Bool G80CursorAcquire(ScrnInfoPtr pScrn)
{
G80Ptr pNv = G80PTR(pScrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
- pNv->cursorVisible = TRUE;
- G80DispShowCursor(G80PTR(pScrn), TRUE);
-}
+ if(!pNv->HWCursor) return TRUE;
-static Bool G80UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
-{
- return TRUE;
-}
+ /* Initialize the cursor on each head */
+ for(i = 0; i < xf86_config->num_crtc; i++) {
+ const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]);
-#ifdef ARGB_CURSOR
-static Bool G80UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
-{
- if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64))
- return TRUE;
+ pNv->reg[(0x00610270+headOff)/4] = 0x2000;
+ while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
- return FALSE;
-}
-
-static void G80LoadCursorARGB(ScrnInfoPtr pScrn, CursorPtr pCurs)
-{
- G80Ptr pNv = G80PTR(pScrn);
- CARD32 *dst = CURSOR_PTR, *src = pCurs->bits->argb;
- int y;
-
- for(y = 0; y < pCurs->bits->height; y++) {
- memcpy(dst, src, pCurs->bits->width * 4);
- memset(dst + pCurs->bits->width, 0, (64 - pCurs->bits->width) * 4);
- src += pCurs->bits->width;
- dst += 64;
+ pNv->reg[(0x00610270+headOff)/4] = 1;
+ while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000);
}
- memset(dst, 0, (64 - y) * 64 * 4);
-}
-#endif
-
-Bool G80CursorAcquire(G80Ptr pNv)
-{
- const int headOff = 0x10 * pNv->head;
-
- if(!pNv->HWCursor) return TRUE;
-
- pNv->reg[(0x00610270+headOff)/4] = 0x2000;
- while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
-
- pNv->reg[(0x00610270+headOff)/4] = 1;
- while((pNv->reg[(0x00610270+headOff)/4] & 0x30000) != 0x10000);
-
return TRUE;
}
-void G80CursorRelease(G80Ptr pNv)
+void G80CursorRelease(ScrnInfoPtr pScrn)
{
- const int headOff = 0x10 * pNv->head;
+ G80Ptr pNv = G80PTR(pScrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
if(!pNv->HWCursor) return;
- pNv->reg[(0x00610270+headOff)/4] = 0;
- while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
+ /* Release the cursor on each head */
+ for(i = 0; i < xf86_config->num_crtc; i++) {
+ const int headOff = 0x10 * G80CrtcGetHead(xf86_config->crtc[i]);
+
+ pNv->reg[(0x00610270+headOff)/4] = 0;
+ while(pNv->reg[(0x00610270+headOff)/4] & 0x30000);
+ }
}
Bool G80CursorInit(ScreenPtr pScreen)
{
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- G80Ptr pNv = G80PTR(pScrn);
- xf86CursorInfoPtr infoPtr;
-
- if(!pNv->HWCursor)
- return TRUE;
-
- infoPtr = xf86CreateCursorInfoRec();
- if(!infoPtr) return FALSE;
-
- pNv->CursorInfo = infoPtr;
- pNv->cursorVisible = FALSE;
-
- infoPtr->MaxWidth = infoPtr->MaxHeight = 64;
- infoPtr->Flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
- HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32;
- infoPtr->SetCursorColors = G80SetCursorColors;
- infoPtr->SetCursorPosition = G80SetCursorPosition;
- infoPtr->LoadCursorImage = G80LoadCursorImage;
- infoPtr->HideCursor = G80HideCursor;
- infoPtr->ShowCursor = G80ShowCursor;
- infoPtr->UseHWCursor = G80UseHWCursor;
-
-#ifdef ARGB_CURSOR
- infoPtr->UseHWCursorARGB = G80UseHWCursorARGB;
- infoPtr->LoadCursorARGB = G80LoadCursorARGB;
-#endif
-
- return xf86InitCursor(pScreen, infoPtr);
+ return xf86_cursors_init(pScreen, 64, 64,
+ HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
+ HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 |
+ HARDWARE_CURSOR_ARGB);
}
diff --git a/driver/xf86-video-nv/src/g80_cursor.h b/driver/xf86-video-nv/src/g80_cursor.h
index 9cd56eead..4d81d803b 100644
--- a/driver/xf86-video-nv/src/g80_cursor.h
+++ b/driver/xf86-video-nv/src/g80_cursor.h
@@ -1,3 +1,7 @@
Bool G80CursorInit(ScreenPtr);
-Bool G80CursorAcquire(G80Ptr);
-void G80CursorRelease(G80Ptr);
+Bool G80CursorAcquire(ScrnInfoPtr);
+void G80CursorRelease(ScrnInfoPtr);
+
+/* CRTC cursor functions */
+void G80SetCursorPosition(xf86CrtcPtr crtc, int x, int y);
+void G80LoadCursorARGB(xf86CrtcPtr crtc, CARD32 *src);
diff --git a/driver/xf86-video-nv/src/g80_dac.c b/driver/xf86-video-nv/src/g80_dac.c
new file mode 100644
index 000000000..30413cd50
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_dac.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <unistd.h>
+
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "g80_type.h"
+#include "g80_display.h"
+#include "g80_output.h"
+
+static void
+G80DacSetPClk(xf86OutputPtr output, int pclk)
+{
+ G80Ptr pNv = G80PTR(output->scrn);
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int orOff = 0x800 * pPriv->or;
+
+ pNv->reg[(0x00614280+orOff)/4] = 0;
+}
+
+static void
+G80DacDPMSSet(xf86OutputPtr output, int mode)
+{
+ G80Ptr pNv = G80PTR(output->scrn);
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int off = 0x800 * pPriv->or;
+ CARD32 tmp;
+
+ /*
+ * DPMSModeOn everything on
+ * DPMSModeStandby hsync disabled, vsync enabled
+ * DPMSModeSuspend hsync enabled, vsync disabled
+ * DPMSModeOff sync disabled
+ */
+ while(pNv->reg[(0x0061A004+off)/4] & 0x80000000);
+
+ tmp = pNv->reg[(0x0061A004+off)/4];
+ tmp &= ~0x7f;
+ tmp |= 0x80000000;
+
+ if(mode == DPMSModeStandby || mode == DPMSModeOff)
+ tmp |= 1;
+ if(mode == DPMSModeSuspend || mode == DPMSModeOff)
+ tmp |= 4;
+ if(mode != DPMSModeOn)
+ tmp |= 0x10;
+ if(mode == DPMSModeOff)
+ tmp |= 0x40;
+
+ 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)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int dacOff = 0x80 * pPriv->or;
+
+ if(!adjusted_mode) {
+ C(0x00000400 + dacOff, 0);
+ return;
+ }
+
+ // This wouldn't be necessary, but the server is stupid and calls
+ // G80DacDPMSSet after the output is disconnected, even though the hardware
+ // turns it off automatically.
+ G80DacDPMSSet(output, DPMSModeOn);
+
+ C(0x00000400 + dacOff,
+ (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) | 0x40);
+ 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);
+}
+
+/*
+ * Perform DAC load detection to determine if there is a connected display.
+ */
+static xf86OutputStatus
+G80DacDetect(xf86OutputPtr output)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+
+ /* Assume physical status isn't going to change before the BlockHandler */
+ if(pPriv->cached_status != XF86OutputStatusUnknown)
+ return pPriv->cached_status;
+
+ G80OutputPartnersDetect(output, pPriv->partner, pPriv->i2c);
+ return pPriv->cached_status;
+}
+
+Bool
+G80DacLoadDetect(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ G80Ptr pNv = G80PTR(pScrn);
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int scrnIndex = pScrn->scrnIndex;
+ const int dacOff = 2048 * pPriv->or;
+ CARD32 load, tmp, tmp2;
+
+ xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on VGA%i ... ",
+ pPriv->or);
+
+ pNv->reg[(0x0061A010+dacOff)/4] = 0x00000001;
+ tmp2 = pNv->reg[(0x0061A004+dacOff)/4];
+ pNv->reg[(0x0061A004+dacOff)/4] = 0x80150000;
+ while(pNv->reg[(0x0061A004+dacOff)/4] & 0x80000000);
+ tmp = pNv->architecture == 0x50 ? 420 : 340;
+ pNv->reg[(0x0061A00C+dacOff)/4] = tmp | 0x100000;
+ usleep(4500);
+ load = pNv->reg[(0x0061A00C+dacOff)/4];
+ pNv->reg[(0x0061A00C+dacOff)/4] = 0;
+ pNv->reg[(0x0061A004+dacOff)/4] = 0x80000000 | tmp2;
+
+ // Use this DAC if all three channels show load.
+ if((load & 0x38000000) == 0x38000000) {
+ xf86ErrorF("found one!\n");
+ return TRUE;
+ }
+
+ xf86ErrorF("nothing.\n");
+ return FALSE;
+}
+
+static void
+G80DacDestroy(xf86OutputPtr output)
+{
+ G80OutputDestroy(output);
+
+ xfree(output->driver_private);
+ output->driver_private = NULL;
+}
+
+static const xf86OutputFuncsRec G80DacOutputFuncs = {
+ .dpms = G80DacDPMSSet,
+ .save = NULL,
+ .restore = NULL,
+ .mode_valid = G80OutputModeValid,
+ .mode_fixup = G80DacModeFixup,
+ .prepare = G80OutputPrepare,
+ .commit = G80OutputCommit,
+ .mode_set = G80DacModeSet,
+ .detect = G80DacDetect,
+ .get_modes = G80OutputGetDDCModes,
+ .destroy = G80DacDestroy,
+};
+
+xf86OutputPtr
+G80CreateDac(ScrnInfoPtr pScrn, ORNum or)
+{
+ G80OutputPrivPtr pPriv = xnfcalloc(sizeof(*pPriv), 1);
+ xf86OutputPtr output;
+ char orName[5];
+
+ if(!pPriv)
+ return FALSE;
+
+ snprintf(orName, 5, "VGA%i", or);
+ output = xf86OutputCreate(pScrn, &G80DacOutputFuncs, orName);
+
+ pPriv->type = DAC;
+ pPriv->or = or;
+ pPriv->cached_status = XF86OutputStatusUnknown;
+ pPriv->set_pclk = G80DacSetPClk;
+ output->driver_private = pPriv;
+ output->interlaceAllowed = TRUE;
+ output->doubleScanAllowed = TRUE;
+
+ return output;
+}
diff --git a/driver/xf86-video-nv/src/g80_exa.c b/driver/xf86-video-nv/src/g80_exa.c
new file mode 100644
index 000000000..96dbc2178
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_exa.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "g80_type.h"
+#include "g80_dma.h"
+#include "g80_xaa.h"
+
+static void
+waitMarker(ScreenPtr pScreen, int marker)
+{
+ G80Sync(xf86Screens[pScreen->myNum]);
+}
+
+static Bool
+setSrc(G80Ptr pNv, PixmapPtr pSrc)
+{
+ CARD32 depth;
+
+ switch(pSrc->drawable.depth) {
+ case 8: depth = 0x000000f3; break;
+ case 15: depth = 0x000000f8; break;
+ case 16: depth = 0x000000e8; break;
+ case 24: depth = 0x000000e6; break;
+ case 32: depth = 0x000000cf; break;
+ default: return FALSE;
+ }
+
+ G80DmaStart(pNv, 0x230, 2);
+ G80DmaNext (pNv, depth);
+ G80DmaNext (pNv, 0x00000001);
+ G80DmaStart(pNv, 0x244, 5);
+ G80DmaNext (pNv, exaGetPixmapPitch(pSrc));
+ G80DmaNext (pNv, pSrc->drawable.width);
+ G80DmaNext (pNv, pSrc->drawable.height);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaNext (pNv, exaGetPixmapOffset(pSrc));
+
+ return TRUE;
+}
+
+static Bool
+setDst(G80Ptr pNv, PixmapPtr pDst)
+{
+ CARD32 depth, depth2;
+
+ switch(pDst->drawable.depth) {
+ case 8: depth = 0x000000f3; depth2 = 3; break;
+ case 15: depth = 0x000000f8; depth2 = 1; break;
+ case 16: depth = 0x000000e8; depth2 = 0; break;
+ case 24: depth = 0x000000e6; depth2 = 2; break;
+ case 32: depth = 0x000000cf; depth2 = 2; break;
+ default: return FALSE;
+ }
+
+ G80DmaStart(pNv, 0x200, 2);
+ G80DmaNext (pNv, depth);
+ G80DmaNext (pNv, 0x00000001);
+ G80DmaStart(pNv, 0x214, 5);
+ G80DmaNext (pNv, exaGetPixmapPitch(pDst));
+ G80DmaNext (pNv, pDst->drawable.width);
+ G80DmaNext (pNv, pDst->drawable.height);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaNext (pNv, exaGetPixmapOffset(pDst));
+ G80DmaStart(pNv, 0x2e8, 1);
+ G80DmaNext (pNv, depth2);
+ G80DmaStart(pNv, 0x584, 1);
+ G80DmaNext (pNv, depth);
+ G80SetClip(pNv, 0, 0, pDst->drawable.width, pDst->drawable.height);
+
+ return TRUE;
+}
+
+/* solid fills */
+
+static Bool
+prepareSolid(PixmapPtr pPixmap,
+ int alu,
+ Pixel planemask,
+ Pixel fg)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ if(pPixmap->drawable.depth > 24) return FALSE;
+ if(!setDst(pNv, pPixmap)) return FALSE;
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, alu, planemask);
+ G80DmaStart(pNv, 0x580, 1);
+ G80DmaNext (pNv, 4);
+ G80DmaStart(pNv, 0x588, 1);
+ G80DmaNext (pNv, fg);
+
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+ return TRUE;
+}
+
+static void
+solid(PixmapPtr pPixmap, int x1, int y1, int x2, int y2)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pPixmap->drawable.pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaStart(pNv, 0x600, 4);
+ G80DmaNext (pNv, x1);
+ G80DmaNext (pNv, y1);
+ G80DmaNext (pNv, x2);
+ G80DmaNext (pNv, y2);
+
+ if((x2 - x1) * (y2 - y1) >= 512)
+ G80DmaKickoff(pNv);
+}
+
+static void
+doneSolid(PixmapPtr pPixmap)
+{
+}
+
+/* screen to screen copies */
+
+static Bool
+prepareCopy(PixmapPtr pSrcPixmap,
+ PixmapPtr pDstPixmap,
+ int dx,
+ int dy,
+ int alu,
+ Pixel planemask)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ if(!setSrc(pNv, pSrcPixmap)) return FALSE;
+ if(!setDst(pNv, pDstPixmap)) return FALSE;
+ G80DmaStart(pNv, 0x2ac, 1);
+ if(alu == GXcopy && planemask == ~0) {
+ G80DmaNext (pNv, 3);
+ } else {
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, alu, planemask);
+ }
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+ return TRUE;
+}
+
+static void
+copy(PixmapPtr pDstPixmap,
+ int srcX,
+ int srcY,
+ int dstX,
+ int dstY,
+ int width,
+ int height)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDstPixmap->drawable.pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaStart(pNv, 0x110, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaStart(pNv, 0x8b0, 12);
+ G80DmaNext (pNv, dstX);
+ G80DmaNext (pNv, dstY);
+ G80DmaNext (pNv, width);
+ G80DmaNext (pNv, height);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, srcX);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, srcY);
+
+ if(width * height >= 512)
+ G80DmaKickoff(pNv);
+}
+
+static void
+doneCopy(PixmapPtr pDstPixmap)
+{
+}
+
+/* composite */
+
+static Bool
+checkComposite(int op,
+ PicturePtr pSrc,
+ PicturePtr pMask,
+ PicturePtr pDst)
+{
+ return FALSE;
+}
+
+/* upload to screen */
+
+static Bool
+upload(PixmapPtr pDst,
+ int x,
+ int y,
+ int w,
+ int h,
+ char *src,
+ int src_pitch)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pDst->drawable.pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+ const int Bpp = pDst->drawable.bitsPerPixel >> 3;
+ int line_dwords = (w * Bpp + 3) / 4;
+ const Bool kickoff = w * h >= 512;
+ CARD32 depth;
+
+ if(!setDst(pNv, pDst)) return FALSE;
+ switch(pDst->drawable.depth) {
+ case 8: depth = 0x000000f3; break;
+ case 15: depth = 0x000000f8; break;
+ case 16: depth = 0x000000e8; break;
+ case 24: depth = 0x000000e6; break;
+ case 32: depth = 0x000000cf; break;
+ default: return FALSE;
+ }
+
+ G80SetClip(pNv, x, y, w, h);
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 3);
+ G80DmaStart(pNv, 0x800, 2);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, depth);
+ G80DmaStart(pNv, 0x838, 10);
+ G80DmaNext (pNv, (line_dwords * 4) / Bpp);
+ G80DmaNext (pNv, h);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, x);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, y);
+
+ while(h-- > 0) {
+ int count = line_dwords;
+ char *p = src;
+
+ while(count) {
+ int size = count > 1792 ? 1792 : count;
+
+ G80DmaStart(pNv, 0x40000860, size);
+ memcpy(&pNv->dmaBase[pNv->dmaCurrent], p, size * 4);
+
+ p += size * Bpp;
+ pNv->dmaCurrent += size;
+
+ count -= size;
+ }
+
+ src += src_pitch;
+ }
+
+ if(kickoff)
+ G80DmaKickoff(pNv);
+ else
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+
+ return TRUE;
+}
+
+/******************************************************************************/
+
+Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ ExaDriverPtr exa;
+ const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+
+ exa = pNv->exa = exaDriverAlloc();
+ if(!exa) return FALSE;
+
+ exa->exa_major = EXA_VERSION_MAJOR;
+ exa->exa_minor = EXA_VERSION_MINOR;
+ exa->memoryBase = pNv->mem;
+ exa->offScreenBase = 0;
+ exa->memorySize = pitch * pNv->offscreenHeight;
+ exa->pixmapOffsetAlign = 256;
+ exa->pixmapPitchAlign = 256;
+ exa->flags = EXA_OFFSCREEN_PIXMAPS;
+ exa->maxX = 8192;
+ exa->maxY = 8192;
+
+ /**** Rendering ops ****/
+ exa->PrepareSolid = prepareSolid;
+ exa->Solid = solid;
+ exa->DoneSolid = doneSolid;
+ exa->PrepareCopy = prepareCopy;
+ exa->Copy = copy;
+ exa->DoneCopy = doneCopy;
+ exa->CheckComposite = checkComposite;
+ //exa->PrepareComposite = prepareComposite;
+ //exa->Composite = composite;
+ //exa->DoneComposite = doneComposite;
+ exa->UploadToScreen = upload;
+
+ exa->WaitMarker = waitMarker;
+
+ return exaDriverInit(pScreen, exa);
+}
diff --git a/driver/xf86-video-nv/src/g80_exa.h b/driver/xf86-video-nv/src/g80_exa.h
new file mode 100644
index 000000000..2f01af621
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_exa.h
@@ -0,0 +1 @@
+Bool G80ExaInit(ScreenPtr pScreen, ScrnInfoPtr pScrn);
diff --git a/driver/xf86-video-nv/src/g80_output.c b/driver/xf86-video-nv/src/g80_output.c
new file mode 100644
index 000000000..1ec6a89af
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_output.c
@@ -0,0 +1,363 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <strings.h>
+
+#include "g80_type.h"
+#include "g80_display.h"
+#include "g80_output.h"
+
+static Bool G80ReadPortMapping(int scrnIndex, G80Ptr pNv)
+{
+ unsigned char *table2;
+ unsigned char headerSize, entries;
+ int i;
+ CARD16 a;
+ CARD32 b;
+
+ /* Clear the i2c map to invalid */
+ for(i = 0; i < 4; i++)
+ pNv->i2cMap[i].dac = pNv->i2cMap[i].sor = -1;
+
+ if(*(CARD16*)pNv->table1 != 0xaa55) goto fail;
+
+ a = *(CARD16*)(pNv->table1 + 0x36);
+ table2 = (unsigned char*)pNv->table1 + a;
+
+ if(table2[0] != 0x40) goto fail;
+
+ b = *(CARD32*)(table2 + 6);
+ if(b != 0x4edcbdcb) goto fail;
+
+ headerSize = table2[1];
+ entries = table2[2];
+
+ for(i = 0; i < entries; i++) {
+ int type, port;
+ ORNum or;
+
+ b = *(CARD32*)&table2[headerSize + 8*i];
+ type = b & 0xf;
+ port = (b >> 4) & 0xf;
+ or = ffs((b >> 24) & 0xf) - 1;
+
+ if(type == 0xe) break;
+
+ if(type < 4) {
+ switch(type) {
+ case 0: /* CRT */
+ if(pNv->i2cMap[port].dac != -1) {
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "DDC routing table corrupt! DAC %i -> %i "
+ "for port %i\n",
+ or, pNv->i2cMap[port].dac, port);
+ }
+ pNv->i2cMap[port].dac = or;
+ break;
+ case 1: /* TV */
+ /* Ignore TVs */
+ break;
+
+ case 2: /* TMDS */
+ if(pNv->i2cMap[port].sor != -1)
+ xf86DrvMsg(scrnIndex, X_WARNING,
+ "DDC routing table corrupt! SOR %i -> %i "
+ "for port %i\n",
+ or, pNv->i2cMap[port].sor, port);
+ pNv->i2cMap[port].sor = or;
+ break;
+
+ case 3: /* LVDS */
+ pNv->lvds.present = TRUE;
+ pNv->lvds.or = or;
+ break;
+ }
+ }
+ }
+
+ xf86DrvMsg(scrnIndex, X_PROBED, "Connector map:\n");
+ if(pNv->lvds.present)
+ xf86DrvMsg(scrnIndex, X_PROBED, " [N/A] -> SOR%i (LVDS)\n", pNv->lvds.or);
+ for(i = 0; i < 4; i++) {
+ if(pNv->i2cMap[i].dac != -1)
+ xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> DAC%i\n", i, pNv->i2cMap[i].dac);
+ if(pNv->i2cMap[i].sor != -1)
+ xf86DrvMsg(scrnIndex, X_PROBED, " Bus %i -> SOR%i\n", i, pNv->i2cMap[i].sor);
+ }
+
+ return TRUE;
+
+fail:
+ xf86DrvMsg(scrnIndex, X_ERROR, "Couldn't find the DDC routing table. "
+ "Mode setting will probably fail!\n");
+ return FALSE;
+}
+
+static void G80_I2CPutBits(I2CBusPtr b, int clock, int data)
+{
+ G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
+ const int off = b->DriverPrivate.val * 0x18;
+
+ pNv->reg[(0x0000E138+off)/4] = 4 | clock | data << 1;
+}
+
+static void G80_I2CGetBits(I2CBusPtr b, int *clock, int *data)
+{
+ G80Ptr pNv = G80PTR(xf86Screens[b->scrnIndex]);
+ const int off = b->DriverPrivate.val * 0x18;
+ unsigned char val;
+
+ val = pNv->reg[(0x0000E138+off)/4];
+ *clock = !!(val & 1);
+ *data = !!(val & 2);
+}
+
+static I2CBusPtr
+G80I2CInit(ScrnInfoPtr pScrn, const char *name, const int port)
+{
+ I2CBusPtr i2c;
+
+ /* Allocate the I2C bus structure */
+ i2c = xf86CreateI2CBusRec();
+ if(!i2c) return NULL;
+
+ i2c->BusName = strdup(name);
+ i2c->scrnIndex = pScrn->scrnIndex;
+ i2c->I2CPutBits = G80_I2CPutBits;
+ i2c->I2CGetBits = G80_I2CGetBits;
+ i2c->ByteTimeout = 2200; /* VESA DDC spec 3 p. 43 (+10 %) */
+ i2c->StartTimeout = 550;
+ i2c->BitTimeout = 40;
+ i2c->ByteTimeout = 40;
+ i2c->AcknTimeout = 40;
+ i2c->DriverPrivate.val = port;
+
+ if(xf86I2CBusInit(i2c)) {
+ return i2c;
+ } else {
+ xfree(i2c);
+ return NULL;
+ }
+}
+
+void
+G80OutputSetPClk(xf86OutputPtr output, int pclk)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+ if(pPriv->set_pclk)
+ pPriv->set_pclk(output, pclk);
+}
+
+int
+G80OutputModeValid(xf86OutputPtr output, DisplayModePtr mode)
+{
+ if(mode->Clock > 400000)
+ return MODE_CLOCK_HIGH;
+ if(mode->Clock < 25000)
+ return MODE_CLOCK_LOW;
+
+ return MODE_OK;
+}
+
+void
+G80OutputPrepare(xf86OutputPtr output)
+{
+}
+
+void
+G80OutputCommit(xf86OutputPtr output)
+{
+}
+
+static xf86MonPtr
+ProbeDDC(I2CBusPtr i2c)
+{
+ ScrnInfoPtr pScrn = xf86Screens[i2c->scrnIndex];
+ G80Ptr pNv = G80PTR(pScrn);
+ xf86MonPtr monInfo = NULL;
+ const int bus = i2c->DriverPrivate.val, off = bus * 0x18;
+
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Probing for EDID on I2C bus %i...\n", bus);
+ pNv->reg[(0x0000E138+off)/4] = 7;
+ /* Should probably use xf86OutputGetEDID here */
+ monInfo = xf86DoEDID_DDC2(pScrn->scrnIndex, i2c);
+ pNv->reg[(0x0000E138+off)/4] = 3;
+
+ if(monInfo) {
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "DDC detected a %s:\n", monInfo->features.input_type ?
+ "DFP" : "CRT");
+ xf86PrintEDID(monInfo);
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, " ... none found\n");
+ }
+
+ return monInfo;
+}
+
+/*
+ * Read an EDID from the i2c port. Perform load detection on the DAC (if
+ * present) to see if the display is connected via VGA. Sets the cached status
+ * of both outputs. The status is marked dirty again in the BlockHandler.
+ */
+void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c)
+{
+ xf86MonPtr monInfo = ProbeDDC(i2c);
+ xf86OutputPtr connected = NULL;
+ Bool load = dac && G80DacLoadDetect(dac);
+
+ if(dac) {
+ G80OutputPrivPtr pPriv = dac->driver_private;
+
+ if(load) {
+ pPriv->cached_status = XF86OutputStatusConnected;
+ connected = dac;
+ } else {
+ pPriv->cached_status = XF86OutputStatusDisconnected;
+ }
+ }
+
+ if(sor) {
+ G80OutputPrivPtr pPriv = sor->driver_private;
+
+ if(monInfo && !load) {
+ pPriv->cached_status = XF86OutputStatusConnected;
+ connected = sor;
+ } else {
+ pPriv->cached_status = XF86OutputStatusDisconnected;
+ }
+ }
+
+ if(connected)
+ xf86OutputSetEDID(connected, monInfo);
+}
+
+/*
+ * Reset the cached output status for all outputs. Called from G80BlockHandler.
+ */
+void
+G80OutputResetCachedStatus(ScrnInfoPtr pScrn)
+{
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+
+ for(i = 0; i < xf86_config->num_output; i++) {
+ G80OutputPrivPtr pPriv = xf86_config->output[i]->driver_private;
+ pPriv->cached_status = XF86OutputStatusUnknown;
+ }
+}
+
+DisplayModePtr
+G80OutputGetDDCModes(xf86OutputPtr output)
+{
+ /* The EDID is read as part of the detect step */
+ output->funcs->detect(output);
+ return xf86OutputGetEDIDModes(output);
+}
+
+void
+G80OutputDestroy(xf86OutputPtr output)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+
+ if(pPriv->partner)
+ ((G80OutputPrivPtr)pPriv->partner->driver_private)->partner = NULL;
+ else
+ xf86DestroyI2CBusRec(pPriv->i2c, TRUE, TRUE);
+ pPriv->i2c = NULL;
+}
+
+Bool
+G80CreateOutputs(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int i;
+
+ if(!G80ReadPortMapping(pScrn->scrnIndex, pNv))
+ return FALSE;
+
+ /* For each DDC port, create an output for the attached ORs */
+ for(i = 0; i < 4; i++) {
+ xf86OutputPtr dac = NULL, sor = NULL;
+ I2CBusPtr i2c;
+ char i2cName[16];
+
+ if(pNv->i2cMap[i].dac == -1 && pNv->i2cMap[i].sor == -1)
+ /* No outputs on this port */
+ continue;
+
+ snprintf(i2cName, sizeof(i2cName), "I2C%i", i);
+ i2c = G80I2CInit(pScrn, i2cName, i);
+ if(!i2c) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to initialize I2C for port %i.\n",
+ i);
+ continue;
+ }
+
+ 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, TMDS);
+
+ if(dac) {
+ G80OutputPrivPtr pPriv = dac->driver_private;
+
+ 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;
+ }
+ }
+
+ if(pNv->lvds.present) {
+ xf86OutputPtr lvds = G80CreateSor(pScrn, pNv->lvds.or, LVDS);
+ G80OutputPrivPtr pPriv = lvds->driver_private;
+
+ pPriv->scale = G80_SCALE_ASPECT;
+ }
+
+ /* For each output, set the crtc and clone masks */
+ for(i = 0; i < xf86_config->num_output; i++) {
+ xf86OutputPtr output = xf86_config->output[i];
+
+ /* Any output can connect to any head */
+ output->possible_crtcs = 0x3;
+ output->possible_clones = 0;
+ }
+
+ return TRUE;
+}
diff --git a/driver/xf86-video-nv/src/g80_output.h b/driver/xf86-video-nv/src/g80_output.h
new file mode 100644
index 000000000..33514c61f
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_output.h
@@ -0,0 +1,31 @@
+typedef struct G80OutputPrivRec {
+ ORType type;
+ ORNum or;
+ PanelType panelType;
+ DisplayModePtr nativeMode;
+ enum G80ScaleMode scale;
+
+ xf86OutputPtr partner;
+ I2CBusPtr i2c;
+
+ xf86OutputStatus cached_status;
+
+ void (*set_pclk)(xf86OutputPtr, int pclk);
+} G80OutputPrivRec, *G80OutputPrivPtr;
+
+void G80OutputSetPClk(xf86OutputPtr, int pclk);
+int G80OutputModeValid(xf86OutputPtr, DisplayModePtr);
+void G80OutputPrepare(xf86OutputPtr);
+void G80OutputCommit(xf86OutputPtr);
+void G80OutputPartnersDetect(xf86OutputPtr dac, xf86OutputPtr sor, I2CBusPtr i2c);
+void G80OutputResetCachedStatus(ScrnInfoPtr);
+DisplayModePtr G80OutputGetDDCModes(xf86OutputPtr);
+void G80OutputDestroy(xf86OutputPtr);
+Bool G80CreateOutputs(ScrnInfoPtr);
+
+/* g80_dac.c */
+xf86OutputPtr G80CreateDac(ScrnInfoPtr, ORNum);
+Bool G80DacLoadDetect(xf86OutputPtr);
+
+/* g80_sor.c */
+xf86OutputPtr G80CreateSor(ScrnInfoPtr, ORNum, PanelType);
diff --git a/driver/xf86-video-nv/src/g80_sor.c b/driver/xf86-video-nv/src/g80_sor.c
new file mode 100644
index 000000000..c98b66d42
--- /dev/null
+++ b/driver/xf86-video-nv/src/g80_sor.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) 2007 NVIDIA, Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+#include <X11/Xatom.h>
+
+#include "g80_type.h"
+#include "g80_display.h"
+#include "g80_output.h"
+
+static void
+G80SorSetPClk(xf86OutputPtr output, int pclk)
+{
+ G80Ptr pNv = G80PTR(output->scrn);
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int orOff = 0x800 * pPriv->or;
+ const int limit = 165000;
+
+ pNv->reg[(0x00614300+orOff)/4] = (pclk > limit) ? 0x101 : 0;
+}
+
+static void
+G80SorDPMSSet(xf86OutputPtr output, int mode)
+{
+ G80Ptr pNv = G80PTR(output->scrn);
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int off = 0x800 * pPriv->or;
+ CARD32 tmp;
+
+ while(pNv->reg[(0x0061C004+off)/4] & 0x80000000);
+
+ tmp = pNv->reg[(0x0061C004+off)/4];
+ tmp |= 0x80000000;
+
+ if(mode == DPMSModeOn)
+ tmp |= 1;
+ else
+ tmp &= ~1;
+
+ pNv->reg[(0x0061C004+off)/4] = tmp;
+ 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)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ G80OutputPrivPtr pPriv = output->driver_private;
+ const int sorOff = 0x40 * pPriv->or;
+ CARD32 type;
+
+ if(!adjusted_mode) {
+ /* Disconnect the SOR */
+ C(0x00000600 + sorOff, 0);
+ 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.
+ G80SorDPMSSet(output, DPMSModeOn);
+
+ C(0x00000600 + sorOff,
+ (G80CrtcGetHead(output->crtc) == HEAD0 ? 1 : 2) |
+ type |
+ ((adjusted_mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
+ ((adjusted_mode->Flags & V_NVSYNC) ? 0x2000 : 0));
+
+ G80CrtcSetScale(output->crtc, adjusted_mode, pPriv->scale);
+}
+
+static xf86OutputStatus
+G80SorDetect(xf86OutputPtr output)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+
+ /* Assume physical status isn't going to change before the BlockHandler */
+ if(pPriv->cached_status != XF86OutputStatusUnknown)
+ return pPriv->cached_status;
+
+ G80OutputPartnersDetect(pPriv->partner, output, pPriv->i2c);
+ 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);
+
+ xf86DeleteMode(&pPriv->nativeMode, pPriv->nativeMode);
+
+ xfree(output->driver_private);
+ output->driver_private = NULL;
+}
+
+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
+G80SorModeFixup(xf86OutputPtr output, DisplayModePtr mode,
+ DisplayModePtr adjusted_mode)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+ DisplayModePtr native = pPriv->nativeMode;
+
+ 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)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+ return xf86DuplicateMode(pPriv->nativeMode);
+}
+
+#ifdef RANDR_12_INTERFACE
+#define MAKE_ATOM(a) MakeAtom((a), sizeof(a) - 1, TRUE);
+
+struct property {
+ Atom atom;
+ INT32 range[2];
+};
+
+static struct {
+ struct property dither;
+ struct property scale;
+} properties;
+
+static void
+G80SorCreateResources(xf86OutputPtr output)
+{
+ ScrnInfoPtr pScrn = output->scrn;
+ G80Ptr pNv = G80PTR(pScrn);
+ int data, err;
+ const char *s;
+
+ /******** dithering ********/
+ properties.dither.atom = MAKE_ATOM("dither");
+ properties.dither.range[0] = 0;
+ properties.dither.range[1] = 1;
+ err = RRConfigureOutputProperty(output->randr_output,
+ properties.dither.atom, FALSE, TRUE, FALSE,
+ 2, properties.dither.range);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to configure dithering property for %s: error %d\n",
+ output->name, err);
+
+ // Set the default value
+ data = pNv->Dither;
+ err = RRChangeOutputProperty(output->randr_output, properties.dither.atom,
+ XA_INTEGER, 32, PropModeReplace, 1, &data,
+ FALSE, FALSE);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to set dithering property for %s: error %d\n",
+ output->name, err);
+
+ /******** scaling ********/
+ properties.scale.atom = MAKE_ATOM("scale");
+ err = RRConfigureOutputProperty(output->randr_output,
+ properties.scale.atom, FALSE, FALSE,
+ FALSE, 0, NULL);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to configure scaling property for %s: error %d\n",
+ output->name, err);
+
+ // Set the default value
+ s = "aspect";
+ err = RRChangeOutputProperty(output->randr_output, properties.scale.atom,
+ XA_STRING, 8, PropModeReplace, strlen(s),
+ (pointer)s, FALSE, FALSE);
+ if(err)
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to set scaling property for %s: error %d\n",
+ output->name, err);
+}
+
+static Bool
+G80SorSetProperty(xf86OutputPtr output, Atom prop, RRPropertyValuePtr val)
+{
+ G80OutputPrivPtr pPriv = output->driver_private;
+
+ if(prop == properties.dither.atom) {
+ INT32 i;
+
+ if(val->type != XA_INTEGER || val->format != 32 || val->size != 1)
+ return FALSE;
+
+ i = *(INT32*)val->data;
+ if(i < properties.dither.range[0] || i > properties.dither.range[1])
+ return FALSE;
+
+ G80CrtcSetDither(output->crtc, i, TRUE);
+ return TRUE;
+ } else if(prop == properties.scale.atom) {
+ const char *s;
+ 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 },
+ { NULL, 0 },
+ };
+
+ if(val->type != XA_STRING || val->format != 8)
+ return FALSE;
+ s = (char*)val->data;
+
+ for(i = 0; modes[i].name; i++) {
+ const char *name = modes[i].name;
+ const int len = strlen(name);
+
+ if(val->size == len && !strncmp(name, s, len)) {
+ scale = modes[i].scale;
+ break;
+ }
+ }
+ if(!modes[i].name)
+ return FALSE;
+ if(scale == G80_SCALE_OFF && pPriv->panelType == LVDS)
+ // LVDS requires scaling
+ return FALSE;
+
+ 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;
+ }
+
+ return FALSE;
+}
+#endif // RANDR_12_INTERFACE
+
+static const xf86OutputFuncsRec G80SorTMDSOutputFuncs = {
+ .dpms = G80SorDPMSSet,
+ .save = NULL,
+ .restore = NULL,
+ .mode_valid = G80TMDSModeValid,
+ .mode_fixup = G80SorTMDSModeFixup,
+ .prepare = G80OutputPrepare,
+ .commit = G80OutputCommit,
+ .mode_set = G80SorModeSet,
+ .detect = G80SorDetect,
+ .get_modes = G80OutputGetDDCModes,
+#ifdef RANDR_12_INTERFACE
+ .create_resources = G80SorCreateResources,
+ .set_property = G80SorSetProperty,
+#endif
+ .destroy = G80SorDestroy,
+};
+
+static const xf86OutputFuncsRec G80SorLVDSOutputFuncs = {
+ .dpms = G80SorDPMSSet,
+ .save = NULL,
+ .restore = NULL,
+ .mode_valid = G80LVDSModeValid,
+ .mode_fixup = G80SorModeFixup,
+ .prepare = G80OutputPrepare,
+ .commit = G80OutputCommit,
+ .mode_set = G80SorModeSet,
+ .detect = G80SorLVDSDetect,
+ .get_modes = G80SorGetLVDSModes,
+#ifdef RANDR_12_INTERFACE
+ .create_resources = G80SorCreateResources,
+ .set_property = G80SorSetProperty,
+#endif
+ .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, 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;
+
+ 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;
+ }
+
+ output = xf86OutputCreate(pScrn, funcs, orName);
+
+ pPriv->type = SOR;
+ pPriv->or = or;
+ pPriv->panelType = panelType;
+ pPriv->cached_status = XF86OutputStatusUnknown;
+ if(panelType == TMDS)
+ 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/driver/xf86-video-nv/src/g80_xaa.h b/driver/xf86-video-nv/src/g80_xaa.h
index e2f1f63c5..6c1d7652f 100644
--- a/driver/xf86-video-nv/src/g80_xaa.h
+++ b/driver/xf86-video-nv/src/g80_xaa.h
@@ -1 +1,6 @@
+void G80Sync(ScrnInfoPtr pScrn);
+void G80DMAKickoffCallback(ScrnInfoPtr pScrn);
+void G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1);
+void G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask);
+void G80SetClip(G80Ptr pNv, int x, int y, int w, int h);
Bool G80XAAInit(ScreenPtr);
diff --git a/driver/xf86-video-nv/src/local_xf86Rename.h b/driver/xf86-video-nv/src/local_xf86Rename.h
new file mode 100644
index 000000000..f3a07c6b4
--- /dev/null
+++ b/driver/xf86-video-nv/src/local_xf86Rename.h
@@ -0,0 +1,23 @@
+/*
+ *Copyright © 2006 Keith Packard
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#define XF86NAME(x) nv_##x
diff --git a/driver/xf86-video-nv/src/riva_const.h b/driver/xf86-video-nv/src/riva_const.h
index 4949fc124..890bcaaa6 100644
--- a/driver/xf86-video-nv/src/riva_const.h
+++ b/driver/xf86-video-nv/src/riva_const.h
@@ -1,5 +1,3 @@
-/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/nv/riva_const.h $ */
-
#ifndef __RIVA_CONST_H__
#define __RIVA_CONST_H__
@@ -8,4 +6,3 @@
#define RIVA_DRIVER_NAME "riva128"
#endif /* __RIVA_CONST_H__ */
-