summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAaron Plattner <aplattner@nvidia.com>2007-02-16 16:11:13 -0800
committerAaron Plattner <aplattner@nvidia.com>2007-03-08 18:02:07 -0800
commit23383c2c2e1aa590f69197b1860053d5cb710cf7 (patch)
tree51f52a41d53fdc28521381708f513538e0e9f3ca
parentdd305c3f64f9267d54324d734f1028bfc00e474f (diff)
Initial G80 support. Bump to 1.99.1.
-rw-r--r--COPYING26
-rw-r--r--configure.ac13
-rw-r--r--man/Makefile.am9
-rw-r--r--man/nv.man80
-rw-r--r--src/Makefile.am24
-rw-r--r--src/g80_cursor.c185
-rw-r--r--src/g80_cursor.h3
-rw-r--r--src/g80_ddc.c232
-rw-r--r--src/g80_ddc.h1
-rw-r--r--src/g80_display.c515
-rw-r--r--src/g80_display.h9
-rw-r--r--src/g80_dma.c65
-rw-r--r--src/g80_dma.h14
-rw-r--r--src/g80_driver.c916
-rw-r--r--src/g80_type.h75
-rw-r--r--src/g80_xaa.c554
-rw-r--r--src/g80_xaa.h1
-rw-r--r--src/nv_driver.c42
-rw-r--r--src/nv_include.h2
19 files changed, 2719 insertions, 47 deletions
diff --git a/COPYING b/COPYING
index 7f33cbf..cad7191 100644
--- a/COPYING
+++ b/COPYING
@@ -1,12 +1,20 @@
-This is a stub file. This package has not yet had its complete licensing
-information compiled. Please see the individual source files for details on
-your rights to use and modify this software.
+Copyright (c) 2007 NVIDIA, Corporation
-Please submit updated COPYING files to the Xorg bugzilla:
+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:
-https://bugs.freedesktop.org/enter_bug.cgi?product=xorg
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
-All licensing questions regarding this software should be directed at the
-Xorg mailing list:
-
-http://lists.freedesktop.org/mailman/listinfo/xorg
+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.
diff --git a/configure.ac b/configure.ac
index 571d3f3..acebecf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -22,7 +22,7 @@
AC_PREREQ(2.57)
AC_INIT([xf86-video-nv],
- 1.2.2.1,
+ 1.99.1,
[https://bugs.freedesktop.org/enter_bug.cgi?product=xorg],
xf86-video-nv)
@@ -63,6 +63,17 @@ PKG_CHECK_EXISTS([xorg-server >= 1.0.99.901],
PKG_CHECK_MODULES(XORG, [xorg-server xproto fontsproto $REQUIRED_MODULES])
sdkdir=$(pkg-config --variable=sdkdir xorg-server)
+# Check for optional compile-time support
+AC_ARG_ENABLE(g80, AC_HELP_STRING([--enable-g80],
+ [Enable G80 support [[default=no]]]),
+ [SUPPORT_G80="$enableval"],
+ [SUPPORT_G80=no])
+AM_CONDITIONAL(SUPPORT_G80, test x$SUPPORT_G80 = xyes)
+if test "$SUPPORT_G80" = yes; then
+ AC_DEFINE(SUPPORT_G80,1,[Enable G80 support])
+ echo "Enabling G80 support"
+fi
+
# Checks for libraries.
# Checks for header files.
diff --git a/man/Makefile.am b/man/Makefile.am
index bf7ec17..036545c 100644
--- a/man/Makefile.am
+++ b/man/Makefile.am
@@ -41,6 +41,12 @@ SED = sed
XORGRELSTRING = @PACKAGE_STRING@
XORGMANNAME = X Version 11
+if SUPPORT_G80
+MAN_SUPPORT_G80 := 1
+else
+MAN_SUPPORT_G80 := 0
+endif
+
MAN_SUBSTS = \
-e 's|__vendorversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
-e 's|__xorgversion__|"$(XORGRELSTRING)" "$(XORGMANNAME)"|' \
@@ -51,7 +57,8 @@ MAN_SUBSTS = \
-e 's|__drivermansuffix__|$(DRIVER_MAN_SUFFIX)|g' \
-e 's|__adminmansuffix__|$(ADMIN_MAN_SUFFIX)|g' \
-e 's|__miscmansuffix__|$(MISC_MAN_SUFFIX)|g' \
- -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g'
+ -e 's|__filemansuffix__|$(FILE_MAN_SUFFIX)|g' \
+ -e 's|__support_g80__|$(MAN_SUPPORT_G80)|g'
SUFFIXES = .$(DRIVER_MAN_SUFFIX) .man
diff --git a/man/nv.man b/man/nv.man
index 83d20ae..243b406 100644
--- a/man/nv.man
+++ b/man/nv.man
@@ -58,6 +58,12 @@ NV40, NV41, NV43, NV44, NV45, C51
.TP 22
.B GeForce 7XXX
G70, G71, G72, G73
+.de G8
+.TP 22
+.B GeForce 8XXX
+G80
+..
+.if __support_g80__ .G8
.SH CONFIGURATION DETAILS
Please refer to __xconfigfile__(__filemansuffix__) for general configuration
@@ -69,7 +75,7 @@ present for all chips.
.PP
The following driver
.B Options
-are supported:
+are supported for pre-G80 hardware:
.TP
.BI "Option \*qHWCursor\*q \*q" boolean \*q
Enable or disable the HW cursor. Default: on.
@@ -128,42 +134,54 @@ Default: no rotation support.
.TP
.BI "Option \*qShadowFB\*q \*q" boolean \*q
Enable or disable use of the shadow framebuffer layer. Default: off.
+.
+.\" ******************** begin G80 section ********************
+.de G8
+.PP
+The following driver
+.B Options
+are available for G80:
+.TP
+.BI "Option \*qHWCursor\*q \*q" boolean \*q
+Enable or disable the hardware cursor. Default: on.
+.TP
+.BI "Option \*qNoAccel\*q \*q" boolean \*q
+Disable or enable acceleration. Default: acceleration is enabled.
+.TP
+.BI "Option \*qBackendMode\*q \*q" mode \*q
+Designate a mode to be used as the physical mode driving the display.
+The screen will be scaled to fit the requested mode.
+For example, if
+.B Option \*qBackendMode\*q \*q1280x1024\*q
+is specified, the monitor will always display the 1280x1024 mode and the screen will be scaled to match.
+..
+.if __support_g80__ .G8
+.\" ******************** end G80 section ********************
+.
.SH "SEE ALSO"
__xservername__(__appmansuffix__), __xconfigfile__(__filemansuffix__), xorgconfig(__appmansuffix__), Xserver(__appmansuffix__), X(__miscmansuffix__)
.SH AUTHORS
Authors include: David McKay, Jarno Paananen, Chas Inman, Dave Schmenk,
-Mark Vojkovich
+Mark Vojkovich, Aaron Plattner
.SH COPYRIGHT
.LP
-NOTICE TO USER: The source code is copyrighted under U.S. and
-international laws. Users and possessors of this source code are
-hereby granted a nonexclusive, royalty-free copyright license to
-use this code in individual and commercial software.
-.LP
-Any use of this source code must include, in the user documentation and
-internal comments to the code, notices to the end user as follows:
+Copyright (c) 2003 - 2007 NVIDIA, Corporation
.LP
-Copyright 1993-2003 NVIDIA, Corporation. All rights reserved.
+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:
.LP
-NVIDIA, CORPORATION MAKES NO REPRESENTATION ABOUT THE SUITABILITY
-OF THIS SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS"
-WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND. NVIDIA, CORPORATION
-DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOURCE CODE,
-INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT,
-AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL
-NVIDIA, CORPORATION BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
-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 SOURCE CODE.
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
.LP
-U.S. Government End Users. This source code is a "commercial
-item," as that term is defined at 48 C.F.R. 2.101 (OCT 1995),
-consisting of "commercial computer software" and "commercial
-computer software documentation," as such terms are used in
-48 C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government
-only as a commercial end item. Consistent with 48 C.F.R.
-12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995),
-all U.S. Government End Users acquire the source code with only
-those rights set forth herein.
-
+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.
diff --git a/src/Makefile.am b/src/Makefile.am
index ecc8597..b7c1128 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -28,7 +28,9 @@ nv_drv_la_LTLIBRARIES = nv_drv.la
nv_drv_la_LDFLAGS = -module -avoid-version
nv_drv_ladir = @moduledir@/drivers
-nv_drv_la_SOURCES = \
+nv_drv_la_SOURCES = $(nv_sources) $(riva_sources) $(g80_sources)
+
+nv_sources = \
nv_const.h \
nv_cursor.c \
nv_dac.c \
@@ -45,7 +47,9 @@ nv_drv_la_SOURCES = \
nv_type.h \
nvvga.h \
nv_video.c \
- nv_xaa.c \
+ nv_xaa.c
+
+riva_sources = \
riva_const.h \
riva_cursor.c \
riva_dac.c \
@@ -61,3 +65,19 @@ nv_drv_la_SOURCES = \
riva_tbl.h \
riva_type.h \
riva_xaa.c
+
+if SUPPORT_G80
+g80_sources = \
+ g80_cursor.c \
+ g80_cursor.h \
+ g80_ddc.c \
+ g80_ddc.h \
+ g80_display.c \
+ g80_display.h \
+ g80_dma.c \
+ g80_dma.h \
+ g80_driver.c \
+ g80_type.h \
+ g80_xaa.c \
+ g80_xaa.h
+endif
diff --git a/src/g80_cursor.c b/src/g80_cursor.c
new file mode 100644
index 0000000..07422e5
--- /dev/null
+++ b/src/g80_cursor.c
@@ -0,0 +1,185 @@
+/*
+ * 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 <string.h>
+
+#include <cursorstr.h>
+
+#include "g80_type.h"
+#include "g80_cursor.h"
+#include "g80_display.h"
+
+#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)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ const int headOff = 0x1000*pNv->head;
+
+ x &= 0xffff;
+ y &= 0xffff;
+ pNv->reg[(0x00647084 + headOff)/4] = y << 16 | x;
+ 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)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ pNv->cursorVisible = FALSE;
+ G80DispHideCursor(G80PTR(pScrn), TRUE);
+}
+
+static void G80ShowCursor(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ pNv->cursorVisible = TRUE;
+ G80DispShowCursor(G80PTR(pScrn), TRUE);
+}
+
+static Bool G80UseHWCursor(ScreenPtr pScreen, CursorPtr pCurs)
+{
+ return TRUE;
+}
+
+#ifdef ARGB_CURSOR
+static Bool G80UseHWCursorARGB(ScreenPtr pScreen, CursorPtr pCurs)
+{
+ if((pCurs->bits->width <= 64) && (pCurs->bits->height <= 64))
+ return TRUE;
+
+ 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;
+ }
+
+ 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)
+{
+ const int headOff = 0x10 * pNv->head;
+
+ if(!pNv->HWCursor) return;
+
+ 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);
+}
diff --git a/src/g80_cursor.h b/src/g80_cursor.h
new file mode 100644
index 0000000..9cd56ee
--- /dev/null
+++ b/src/g80_cursor.h
@@ -0,0 +1,3 @@
+Bool G80CursorInit(ScreenPtr);
+Bool G80CursorAcquire(G80Ptr);
+void G80CursorRelease(G80Ptr);
diff --git a/src/g80_ddc.c b/src/g80_ddc.c
new file mode 100644
index 0000000..3713028
--- /dev/null
+++ b/src/g80_ddc.c
@@ -0,0 +1,232 @@
+/*
+ * 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 <xf86DDC.h>
+
+#include "g80_type.h"
+#include "g80_ddc.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++) {
+ CARD32 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 < 4 && port != 0xf) {
+ switch(type) {
+ case 0: /* CRT */
+ case 1: /* TV */
+ 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 2: /* TMDS */
+ case 3: /* LVDS */
+ 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;
+ }
+ }
+ }
+
+ xf86DrvMsg(scrnIndex, X_PROBED, "I2C map:\n");
+ 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;
+
+ 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;
+ unsigned char val;
+
+ val = pNv->reg[(0x0000E138+off)/4];
+ *clock = !!(val & 1);
+ *data = !!(val & 2);
+}
+
+static xf86MonPtr G80ProbeDDCBus(ScrnInfoPtr pScrn, int bus)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ I2CBusPtr i2c;
+ xf86MonPtr monInfo = NULL;
+ const int off = bus * 0x18;
+
+ /* Allocate the I2C bus structure */
+ i2c = xf86CreateI2CBusRec();
+ if(!i2c) return NULL;
+
+ i2c->BusName = "DDC";
+ 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 = off;
+
+ if(!xf86I2CBusInit(i2c)) goto done;
+
+ pNv->reg[(0x0000E138+off)/4] = 7;
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "Probing for EDID on I2C bus %i...\n", bus);
+ 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");
+ }
+
+done:
+ xf86DestroyI2CBusRec(i2c, TRUE, TRUE);
+
+ return monInfo;
+}
+
+/*
+ * Try DDC on each bus until we find one that works.
+ */
+Bool G80ProbeDDC(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ xf86MonPtr monInfo;
+ int port;
+ Bool flatPanel;
+
+ if(!G80ReadPortMapping(pScrn->scrnIndex, pNv))
+ return FALSE;
+
+ for(port = 0; port < 4; port++) {
+ if(pNv->i2cMap[port].dac == -1 && pNv->i2cMap[port].sor == -1)
+ /* No outputs on this port. Skip it. */
+ continue;
+
+ monInfo = G80ProbeDDCBus(pScrn, port);
+ if(!monInfo)
+ /* No EDID on this port. */
+ continue;
+
+ flatPanel = (monInfo->features.input_type == 1);
+
+ if(flatPanel) {
+ if(pNv->i2cMap[port].sor == -1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Saw a flat panel EDID "
+ "on I2C port %i but no SOR outputs were registered for "
+ "that port.\n", port);
+ continue;
+ }
+ pNv->orType = SOR;
+ pNv->or = pNv->i2cMap[port].sor;
+ } else {
+ if(pNv->i2cMap[port].dac == -1) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Saw a flat panel EDID "
+ "on I2C port %i but no DAC outputs were registered for "
+ "that port.\n", port);
+ continue;
+ }
+ pNv->orType = DAC;
+ pNv->or = pNv->i2cMap[port].dac;
+ }
+
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Found a %s on I2C port %i, assigning %s%i\n",
+ flatPanel ? "flat panel" : "CRT",
+ port, flatPanel ? "SOR" : "DAC", pNv->or);
+
+ pScrn->monitor->DDC = monInfo;
+ xf86SetDDCproperties(pScrn, monInfo);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/src/g80_ddc.h b/src/g80_ddc.h
new file mode 100644
index 0000000..d209d62
--- /dev/null
+++ b/src/g80_ddc.h
@@ -0,0 +1 @@
+Bool G80ProbeDDC(ScrnInfoPtr pScrn);
diff --git a/src/g80_display.c b/src/g80_display.c
new file mode 100644
index 0000000..5ff3514
--- /dev/null
+++ b/src/g80_display.c
@@ -0,0 +1,515 @@
+/*
+ * 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 <float.h>
+#include <math.h>
+#include <strings.h>
+#include <unistd.h>
+
+#include "g80_type.h"
+#include "g80_display.h"
+
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+/*
+ * PLL calculation. pclk is in kHz.
+ */
+static void
+G80CalcPLL(float pclk, int *pNA, int *pMA, int *pNB, int *pMB, int *pP)
+{
+ const float refclk = 27000.0f;
+ const float minVcoA = 100000;
+ const float maxVcoA = 400000;
+ const float minVcoB = 600000;
+ float maxVcoB = 1400000;
+ const float minUA = 2000;
+ const float maxUA = 400000;
+ const float minUB = 50000;
+ const float maxUB = 200000;
+ const int minNA = 1, maxNA = 255;
+ const int minNB = 1, maxNB = 31;
+ const int minMA = 1, maxMA = 255;
+ const int minMB = 1, maxMB = 31;
+ const int minP = 0, maxP = 6;
+ int lowP, highP;
+ float vcoB;
+
+ int na, ma, nb, mb, p;
+ float bestError = FLT_MAX;
+
+ *pNA = *pMA = *pNB = *pMB = *pP = 0;
+
+ if(maxVcoB < pclk + pclk / 200)
+ maxVcoB = pclk + pclk / 200;
+ if(minVcoB / (1 << maxP) > pclk)
+ pclk = minVcoB / (1 << maxP);
+
+ vcoB = maxVcoB - maxVcoB / 200;
+ lowP = minP;
+ vcoB /= 1 << (lowP + 1);
+
+ while(pclk <= vcoB && lowP < maxP)
+ {
+ vcoB /= 2;
+ lowP++;
+ }
+
+ vcoB = maxVcoB + maxVcoB / 200;
+ highP = lowP;
+ vcoB /= 1 << (highP + 1);
+
+ while(pclk <= vcoB && highP < maxP)
+ {
+ vcoB /= 2;
+ highP++;
+ }
+
+ for(p = lowP; p <= highP; p++)
+ {
+ for(ma = minMA; ma <= maxMA; ma++)
+ {
+ if(refclk / ma < minUA)
+ break;
+ else if(refclk / ma > maxUA)
+ continue;
+
+ for(na = minNA; na <= maxNA; na++)
+ {
+ if(refclk * na / ma < minVcoA || refclk * na / ma > maxVcoA)
+ continue;
+
+ for(mb = minMB; mb <= maxMB; mb++)
+ {
+ if(refclk * na / ma / mb < minUB)
+ break;
+ else if(refclk * na / ma / mb > maxUB)
+ continue;
+
+ nb = rint(pclk * (1 << p) * (ma / (float)na) * mb / refclk);
+
+ if(nb > maxNB)
+ break;
+ else if(nb < minNB)
+ continue;
+ else
+ {
+ float freq = refclk * (na / (float)ma) * (nb / (float)mb) / (1 << p);
+ float error = fabsf(pclk - freq);
+ if(error < bestError) {
+ *pNA = na;
+ *pMA = ma;
+ *pNB = nb;
+ *pMB = mb;
+ *pP = p;
+ bestError = error;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void
+G80DispCommand(G80Ptr pNv, CARD32 addr, CARD32 data)
+{
+ pNv->reg[0x00610304/4] = data;
+ pNv->reg[0x00610300/4] = addr | 0x80010001;
+
+ while(pNv->reg[0x00610300/4] & 0x80000000) {
+ const int super = ffs((pNv->reg[0x00610024/4] >> 4) & 7);
+
+ if(super) {
+ if(super == 2) {
+ const int headOff = 0x800 * pNv->head;
+ const int orOff = 0x800 * pNv->or;
+
+ if(pNv->reg[0x00610030/4] & 0x600) {
+ int lo_n, lo_m, hi_n, hi_m, p;
+ CARD32 lo = pNv->reg[(0x00614104+headOff)/4];
+ CARD32 hi = pNv->reg[(0x00614108+headOff)/4];
+
+ pNv->reg[(0x00614100+headOff)/4] = 0x10000610;
+ lo &= 0xff00ff00;
+ hi &= 0x8000ff00;
+
+ G80CalcPLL(pNv->pclk, &lo_n, &lo_m, &hi_n, &hi_m, &p);
+
+ lo |= (lo_m << 16) | lo_n;
+ hi |= (p << 28) | (hi_m << 16) | hi_n;
+ pNv->reg[(0x00614104+headOff)/4] = lo;
+ pNv->reg[(0x00614108+headOff)/4] = hi;
+ }
+
+ pNv->reg[(0x00614200+headOff)/4] = 0;
+ switch(pNv->orType) {
+ case DAC:
+ pNv->reg[(0x00614280+orOff)/4] = 0;
+ break;
+ case SOR:
+ pNv->reg[(0x00614300+orOff)/4] =
+ (pNv->pclk > 165000) ? 0x101 : 0;
+ break;
+ }
+ }
+
+ pNv->reg[0x00610024/4] = 8 << super;
+ pNv->reg[0x00610030/4] = 0x80000000;
+ }
+ }
+}
+#define C(mthd, data) G80DispCommand(pNv, (mthd), (data))
+
+/*
+ * Performs load detection on the DACs. Sets pNv->orType and pNv->or
+ * accordingly.
+ */
+Bool G80LoadDetect(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ const int scrnIndex = pScrn->scrnIndex;
+ ORNum or;
+
+ pNv->orType = DAC;
+
+ for(or = DAC0; or <= DAC2; or++) {
+ const int dacOff = 2048 * or;
+ CARD32 load, tmp;
+
+ xf86DrvMsg(scrnIndex, X_PROBED, "Trying load detection on DAC%i ... ", or);
+
+ pNv->reg[(0x0061A010+dacOff)/4] = 0x00000001;
+ 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] = 0x80550000;
+ if((load & 0x38000000) == 0x38000000) {
+ xf86ErrorF("found one!\n");
+ pNv->or = or;
+ return TRUE;
+ }
+
+ xf86ErrorF("nothing.\n");
+ }
+
+ return FALSE;
+}
+
+Bool
+G80DispInit(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ pNv->reg[0x00610184/4] = pNv->reg[0x00614004/4];
+ pNv->reg[0x00610190/4] = pNv->reg[0x00616100/4];
+ pNv->reg[0x006101a0/4] = pNv->reg[0x00616900/4];
+ pNv->reg[0x00610194/4] = pNv->reg[0x00616104/4];
+ pNv->reg[0x006101a4/4] = pNv->reg[0x00616904/4];
+ pNv->reg[0x00610198/4] = pNv->reg[0x00616108/4];
+ pNv->reg[0x006101a8/4] = pNv->reg[0x00616908/4];
+ pNv->reg[0x0061019C/4] = pNv->reg[0x0061610C/4];
+ pNv->reg[0x006101ac/4] = pNv->reg[0x0061690c/4];
+ pNv->reg[0x006101D0/4] = pNv->reg[0x0061A000/4];
+ pNv->reg[0x006101D4/4] = pNv->reg[0x0061A800/4];
+ 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;
+ pNv->reg[0x0061A810/4] = 0x00000001;
+ pNv->reg[0x0061B004/4] = 0x80550000;
+ pNv->reg[0x0061B010/4] = 0x00000001;
+
+ if(pNv->reg[0x00610024/4] & 0x100) {
+ pNv->reg[0x00610024/4] = 0x100;
+ pNv->reg[0x006194E8/4] &= ~1;
+ while(pNv->reg[0x006194E8/4] & 2);
+ }
+
+ pNv->reg[0x00610200/4] = 0x2b00;
+ while((pNv->reg[0x00610200/4] & 0x1e0000) != 0);
+ pNv->reg[0x00610300/4] = 1;
+ pNv->reg[0x00610200/4] = 0x1000b03;
+ while(!(pNv->reg[0x00610200/4] & 0x40000000));
+
+ C(0x00000084, 0);
+ C(0x00000088, 0);
+ C(0x00000874, 0);
+ C(0x00000800, 0);
+ C(0x00000810, 0);
+ C(0x0000082C, 0);
+
+ return TRUE;
+}
+
+void
+G80DispShutdown(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ CARD32 mask;
+
+ G80DispBlankScreen(pScrn, TRUE);
+
+ mask = 4 << pNv->head;
+ pNv->reg[0x00610024/4] = mask;
+ while(!(pNv->reg[0x00610024/4] & mask));
+ pNv->reg[0x00610200/4] = 0;
+ pNv->reg[0x00610300/4] = 0;
+ while((pNv->reg[0x00610200/4] & 0x1e0000) != 0);
+}
+
+static void
+setupDAC(G80Ptr pNv, Head head, ORNum or, DisplayModePtr mode)
+{
+ const int dacOff = 0x80 * pNv->or;
+
+ C(0x00000400 + dacOff, (head == HEAD0 ? 1 : 2) | 0x40);
+ C(0x00000404 + dacOff,
+ (mode->Flags & V_NHSYNC) ? 1 : 0 |
+ (mode->Flags & V_NVSYNC) ? 2 : 0);
+}
+
+static void
+setupSOR(G80Ptr pNv, Head head, ORNum or, DisplayModePtr mode)
+{
+ const int sorOff = 0x40 * pNv->or;
+
+ C(0x00000600 + sorOff,
+ (head == HEAD0 ? 1 : 2) |
+ (mode->SynthClock > 165000 ? 0x500 : 0x100) |
+ ((mode->Flags & V_NHSYNC) ? 0x1000 : 0) |
+ ((mode->Flags & V_NVSYNC) ? 0x2000 : 0));
+}
+
+Bool
+G80DispSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ const int HDisplay = mode->HDisplay, VDisplay = mode->VDisplay;
+ const int headOff = 0x400 * pNv->head;
+ int interlaceDiv, fudge;
+
+ if(pNv->BackendMode)
+ mode = pNv->BackendMode;
+
+ pNv->pclk = mode->SynthClock;
+
+ /* Magic mode timing fudge factor */
+ fudge = ((mode->Flags & V_INTERLACE) && (mode->Flags & V_DBLSCAN)) ? 2 : 1;
+ interlaceDiv = (mode->Flags & V_INTERLACE) ? 2 : 1;
+
+ switch(pNv->orType) {
+ case DAC:
+ setupDAC(pNv, pNv->head, pNv->or, mode);
+ break;
+ case SOR:
+ setupSOR(pNv, pNv->head, pNv->or, mode);
+ break;
+ }
+
+ C(0x00000804 + headOff, mode->SynthClock | 0x800000);
+ C(0x00000808 + headOff, (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(0x00000868 + headOff, pScrn->virtualY << 16 | pScrn->virtualX);
+ C(0x0000086C + headOff, pScrn->displayWidth * (pScrn->bitsPerPixel / 8) | 0x100000);
+ switch(pScrn->depth) {
+ case 8: C(0x00000870 + headOff, 0x1E00); break;
+ case 15: C(0x00000870 + headOff, 0xE900); break;
+ 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) {
+ C(0x000008A4 + headOff, 9);
+ } else {
+ C(0x000008A4 + headOff, 0);
+ }
+ C(0x000008A8 + headOff, 0x40000);
+ /* Use the screen's panning, but not if it's bogus */
+ if(pScrn->frameX0 >= 0 && pScrn->frameY0 >= 0 &&
+ pScrn->frameX0 + HDisplay <= pScrn->virtualX &&
+ pScrn->frameY0 + VDisplay <= pScrn->virtualY) {
+ C(0x000008C0 + headOff, pScrn->frameY0 << 16 | pScrn->frameX0);
+ } else {
+ C(0x000008C0 + headOff, 0);
+ }
+ 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);
+
+ G80DispBlankScreen(pScrn, FALSE);
+
+ return TRUE;
+}
+
+void
+G80DispAdjustFrame(G80Ptr pNv, int x, int y)
+{
+ const int headOff = 0x400 * pNv->head;
+
+ C(0x000008C0 + headOff, y << 16 | x);
+ C(0x00000080, 0);
+}
+
+void
+G80DispBlankScreen(ScrnInfoPtr pScrn, Bool blank)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ const int headOff = 0x400 * pNv->head;
+
+ if(blank) {
+ G80DispHideCursor(pNv, FALSE);
+
+ C(0x00000840 + headOff, 0);
+ C(0x00000844 + headOff, 0);
+ if(pNv->architecture != 0x50)
+ C(0x0000085C + headOff, 0);
+ C(0x00000874 + headOff, 0);
+ if(pNv->architecture != 0x50)
+ C(0x0000089C + headOff, 0);
+ } else {
+ C(0x00000860 + headOff, 0);
+ C(0x00000864 + headOff, 0);
+ pNv->reg[0x00610380/4] = 0;
+ pNv->reg[0x00610384/4] = pNv->RamAmountKBytes * 1024 - 1;
+ pNv->reg[0x00610388/4] = 0x150000;
+ pNv->reg[0x0061038C/4] = 0;
+ C(0x00000884 + headOff, (pNv->videoRam << 2) - 0x40);
+ if(pNv->architecture != 0x50)
+ C(0x0000089C + headOff, 1);
+ if(pNv->cursorVisible)
+ G80DispShowCursor(pNv, FALSE);
+ C(0x00000840 + headOff, pScrn->depth == 8 ? 0x80000000 : 0xc0000000);
+ C(0x00000844 + headOff, (pNv->videoRam * 1024 - 0x5000) >> 8);
+ if(pNv->architecture != 0x50)
+ C(0x0000085C + headOff, 1);
+ C(0x00000874 + headOff, 1);
+ }
+
+ C(0x00000080, 0);
+}
+
+void
+G80DispDPMSSet(ScrnInfoPtr pScrn, int mode, int flags)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ const int off = 0x800 * pNv->or;
+ CARD32 tmp;
+
+ /*
+ * DPMSModeOn everything on
+ * DPMSModeStandby hsync disabled, vsync enabled
+ * DPMSModeSuspend hsync enabled, vsync disabled
+ * DPMSModeOff sync disabled
+ */
+ switch(pNv->orType) {
+ case DAC:
+ 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;
+
+ break;
+
+ case SOR:
+ 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;
+
+ break;
+ }
+}
+
+/******************************** Cursor stuff ********************************/
+void G80DispShowCursor(G80Ptr pNv, Bool update)
+{
+ const int headOff = 0x400 * pNv->head;
+
+ C(0x00000880 + headOff, 0x85000000);
+ if(update) C(0x00000080, 0);
+}
+
+void G80DispHideCursor(G80Ptr pNv, Bool update)
+{
+ const int headOff = 0x400 * pNv->head;
+
+ C(0x00000880 + headOff, 0x5000000);
+ if(update) C(0x00000080, 0);
+}
diff --git a/src/g80_display.h b/src/g80_display.h
new file mode 100644
index 0000000..aec6314
--- /dev/null
+++ b/src/g80_display.h
@@ -0,0 +1,9 @@
+Bool G80LoadDetect(ScrnInfoPtr);
+Bool G80DispInit(ScrnInfoPtr);
+Bool G80DispSetMode(ScrnInfoPtr, DisplayModePtr);
+void G80DispShutdown(ScrnInfoPtr);
+void G80DispAdjustFrame(G80Ptr pNv, int x, int y);
+void G80DispBlankScreen(ScrnInfoPtr, Bool blank);
+void G80DispDPMSSet(ScrnInfoPtr, int mode, int flags);
+void G80DispShowCursor(G80Ptr, Bool update);
+void G80DispHideCursor(G80Ptr, Bool update);
diff --git a/src/g80_dma.c b/src/g80_dma.c
new file mode 100644
index 0000000..63fdbe5
--- /dev/null
+++ b/src/g80_dma.c
@@ -0,0 +1,65 @@
+/*
+ * 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"
+
+void G80DmaKickoff(G80Ptr pNv)
+{
+ if(pNv->dmaCurrent != pNv->dmaPut) {
+ pNv->dmaPut = pNv->dmaCurrent;
+ pNv->reg[0x00c02040/4] = pNv->dmaPut << 2;
+ }
+}
+
+void G80DmaWait(G80Ptr pNv, int size)
+{
+ CARD32 dmaGet;
+
+ size++;
+
+ while(pNv->dmaFree < size) {
+ dmaGet = pNv->reg[0x00c02044/4] >> 2;
+
+ if(pNv->dmaPut >= dmaGet) {
+ pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
+ if(pNv->dmaFree < size) {
+ G80DmaNext(pNv, 0x20000000);
+ if(dmaGet <= SKIPS) {
+ if(pNv->dmaPut <= SKIPS) /* corner case - will be idle */
+ pNv->reg[0x00c02040/4] = (SKIPS + 1) << 2;
+ do { dmaGet = pNv->reg[0x00c02044/4] >> 2; }
+ while(dmaGet <= SKIPS);
+ }
+ pNv->reg[0x00c02040/4] = SKIPS << 2;
+ pNv->dmaCurrent = pNv->dmaPut = SKIPS;
+ pNv->dmaFree = dmaGet - (SKIPS + 1);
+ }
+ } else
+ pNv->dmaFree = dmaGet - pNv->dmaCurrent - 1;
+ }
+}
diff --git a/src/g80_dma.h b/src/g80_dma.h
new file mode 100644
index 0000000..52031da
--- /dev/null
+++ b/src/g80_dma.h
@@ -0,0 +1,14 @@
+#define SKIPS 8
+
+#define G80DmaNext(pNv, data) \
+ (pNv)->dmaBase[(pNv)->dmaCurrent++] = (data)
+
+#define G80DmaStart(pNv, tag, size) { \
+ if((pNv)->dmaFree <= (size)) \
+ G80DmaWait(pNv, size); \
+ G80DmaNext(pNv, ((size) << 18) | (tag)); \
+ (pNv)->dmaFree -= ((size) + 1); \
+}
+
+void G80DmaKickoff(G80Ptr pNv);
+void G80DmaWait(G80Ptr pNv, int size);
diff --git a/src/g80_driver.c b/src/g80_driver.c
new file mode 100644
index 0000000..2a3120f
--- /dev/null
+++ b/src/g80_driver.c
@@ -0,0 +1,916 @@
+/*
+ * 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 <string.h>
+
+#include <xf86_OSproc.h>
+#include <xf86Resources.h>
+#include <mipointer.h>
+#include <mibstore.h>
+#include <micmap.h>
+#include <xf86cmap.h>
+#include <fb.h>
+#define DPMS_SERVER
+#include <X11/extensions/dpms.h>
+
+#include "nv_const.h"
+#include "g80_type.h"
+#include "g80_cursor.h"
+#include "g80_display.h"
+#include "g80_ddc.h"
+#include "g80_dma.h"
+#include "g80_xaa.h"
+
+#define G80_REG_SIZE (1024 * 1024 * 16)
+#define G80_RESERVED_VIDMEM 0xd000
+
+static const char *fbSymbols[] = {
+ "fbPictureInit",
+ "fbScreenInit",
+ NULL
+};
+
+static const char *xaaSymbols[] = {
+ "XAACopyROP",
+ "XAACreateInfoRec",
+ "XAADestroyInfoRec",
+ "XAAFallbackOps",
+ "XAAInit",
+ "XAAPatternROP",
+ NULL
+};
+
+static const char *i2cSymbols[] = {
+ "xf86CreateI2CBusRec",
+ "xf86I2CBusInit",
+ NULL
+};
+
+static const char *ramdacSymbols[] = {
+ "xf86CreateCursorInfoRec",
+ "xf86DestroyCursorInfoRec",
+ "xf86InitCursor",
+ NULL
+};
+
+static const char *ddcSymbols[] = {
+ "xf86PrintEDID",
+ "xf86DoEDID_DDC2",
+ "xf86SetDDCproperties",
+ NULL
+};
+
+static const char *int10Symbols[] = {
+ "xf86FreeInt10",
+ "xf86InitInt10",
+ "xf86ExecX86int10",
+ NULL
+};
+
+typedef enum {
+ OPTION_HW_CURSOR,
+ OPTION_NOACCEL,
+ OPTION_BACKEND_MODE,
+} G80Opts;
+
+static const OptionInfoRec G80Options[] = {
+ { OPTION_HW_CURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_BACKEND_MODE, "BackendMode", OPTV_ANYSTR, {0}, FALSE },
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
+};
+
+static Bool
+G80GetRec(ScrnInfoPtr pScrn)
+{
+ if(pScrn->driverPrivate == NULL)
+ pScrn->driverPrivate = xcalloc(sizeof(G80Rec), 1);
+
+ return (pScrn->driverPrivate != NULL);
+}
+
+static void
+G80FreeRec(ScrnInfoPtr pScrn)
+{
+ xfree(pScrn->driverPrivate);
+ pScrn->driverPrivate = NULL;
+}
+
+static Bool
+G80PreInit(ScrnInfoPtr pScrn, int flags)
+{
+ G80Ptr pNv;
+ EntityInfoPtr pEnt;
+ pciVideoPtr pPci;
+ PCITAG pcitag;
+ ClockRangePtr clockRanges;
+ MessageType from;
+ Bool primary;
+ int i;
+ char *s;
+ const rgb zeros = {0, 0, 0};
+ const Gamma gzeros = {0.0, 0.0, 0.0};
+ CARD32 tmp;
+
+ if(flags & PROBE_DETECT) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "G80 PROBE_DETECT unimplemented\n");
+ return FALSE;
+ }
+
+ /* Check the number of entities, and fail if it isn't one. */
+ if(pScrn->numEntities != 1)
+ return FALSE;
+
+ /* Allocate the NVRec driverPrivate */
+ if(!G80GetRec(pScrn)) {
+ return FALSE;
+ }
+ pNv = G80PTR(pScrn);
+
+ /* Get the entity, and make sure it is PCI. */
+ pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ if(pEnt->location.type != BUS_PCI) goto fail;
+ pPci = xf86GetPciInfoForEntity(pEnt->index);
+ pcitag = pciTag(pPci->bus, pPci->device, pPci->func);
+ primary = xf86IsPrimaryPci(pPci);
+
+ /* The ROM size sometimes isn't read correctly, so fix it up here. */
+ if(pPci->biosSize == 0)
+ /* The BIOS is 64k */
+ pPci->biosSize = 16;
+
+ pNv->int10 = NULL;
+ pNv->int10Mode = 0;
+ if(xf86LoadSubModule(pScrn, "int10")) {
+ xf86LoaderReqSymLists(int10Symbols, NULL);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing int10\n");
+ pNv->int10 = xf86InitInt10(pEnt->index);
+ }
+
+ if(!pNv->int10) {
+ if(primary) {
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
+ "Failed to initialize the int10 module; the console "
+ "will not be restored.\n");
+ } else {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Failed to initialize the int10 module; this screen "
+ "will not be initialized.\n");
+ goto fail;
+ }
+ }
+
+ if(primary && pNv->int10) {
+ const xf86Int10InfoPtr int10 = pNv->int10;
+
+ /* Get the current video mode */
+ int10->num = 0x10;
+ int10->ax = 0x4f03;
+ int10->bx = int10->cx = int10->dx = 0;
+ xf86ExecX86int10(int10);
+ pNv->int10Mode = int10->bx & 0x3fff;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Console is VGA mode 0x%x\n",
+ pNv->int10Mode);
+ }
+
+ /* Disable VGA access */
+ xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
+ xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
+
+ pScrn->monitor = pScrn->confScreen->monitor;
+
+ if(!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb)) goto fail;
+ switch (pScrn->depth) {
+ case 8:
+ case 15:
+ case 16:
+ case 24:
+ /* OK */
+ break;
+ default:
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Given depth (%d) is not supported by this driver\n",
+ pScrn->depth);
+ goto fail;
+ }
+ xf86PrintDepthBpp(pScrn);
+
+ if(!xf86SetWeight(pScrn, zeros, zeros)) goto fail;
+ if(!xf86SetDefaultVisual(pScrn, -1)) goto fail;
+
+ /* We use a programmable clock */
+ pScrn->progClock = TRUE;
+
+ /* Process options */
+ xf86CollectOptions(pScrn, NULL);
+ if(!(pNv->Options = xalloc(sizeof(G80Options)))) goto fail;
+ memcpy(pNv->Options, G80Options, sizeof(G80Options));
+ xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pNv->Options);
+
+ from = X_DEFAULT;
+ pNv->HWCursor = TRUE;
+ if(xf86GetOptValBool(pNv->Options, OPTION_HW_CURSOR, &pNv->HWCursor))
+ from = X_CONFIG;
+ xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
+ pNv->HWCursor ? "hardware" : "software");
+ if(xf86ReturnOptValBool(pNv->Options, OPTION_NOACCEL, FALSE)) {
+ pNv->NoAccel = TRUE;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Acceleration disabled\n");
+ }
+
+ /* Set the bits per RGB for 8bpp mode */
+ if(pScrn->depth == 8)
+ pScrn->rgbBits = 8;
+
+ if(!xf86SetGamma(pScrn, gzeros)) goto fail;
+
+ /*
+ * Setup the ClockRanges, which describe what clock ranges are available,
+ * and what sort of modes they can be used for.
+ */
+ clockRanges = xnfcalloc(sizeof(ClockRange), 1);
+ clockRanges->next = NULL;
+ clockRanges->minClock = 0;
+ clockRanges->maxClock = 400000;
+ clockRanges->clockIndex = -1; /* programmable */
+ clockRanges->doubleScanAllowed = TRUE;
+ clockRanges->interlaceAllowed = TRUE;
+
+ /* Map memory */
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "MMIO registers at 0x%lx\n",
+ pPci->memBase[0]);
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Linear framebuffer at 0x%lx\n",
+ pPci->memBase[1]);
+ pScrn->memPhysBase = pPci->memBase[1];
+ pScrn->fbOffset = 0;
+
+ pNv->reg = xf86MapPciMem(pScrn->scrnIndex,
+ VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
+ pcitag, pPci->memBase[0], G80_REG_SIZE);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "MMIO registers mapped at %p\n",
+ (void*)pNv->reg);
+
+ if(xf86RegisterResources(pEnt->index, NULL, ResExclusive)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86RegisterResources() found "
+ "resource conflicts\n");
+ goto fail;
+ }
+
+ pNv->architecture = pNv->reg[0] >> 20 & 0x1ff;
+ pNv->RamAmountKBytes = pNv->RamAmountKBytes = (pNv->reg[0x0010020C/4] & 0xFFF00000) >> 10;
+ pNv->videoRam = pNv->RamAmountKBytes;
+ /* Limit videoRam to the max BAR1 size of 256MB */
+ if(pNv->videoRam <= 1024) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to determine the amount of "
+ "available video memory\n");
+ goto fail;
+ }
+ pNv->videoRam -= 1024;
+ if(pNv->videoRam > 256 * 1024)
+ pNv->videoRam = 256 * 1024;
+ pScrn->videoRam = pNv->videoRam;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Mapping %.1f of %.1f MB of video RAM\n",
+ pScrn->videoRam / 1024.0, pNv->RamAmountKBytes / 1024.0);
+ pNv->mem = xf86MapPciMem(pScrn->scrnIndex,
+ VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
+ pcitag, pPci->memBase[1], pScrn->videoRam * 1024);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Linear framebuffer mapped at %p\n",
+ (void*)pNv->mem);
+
+ pNv->table1 = (unsigned const char*)&pNv->reg[0x00800000/4];
+ tmp = pNv->reg[0x00619F04/4] >> 8;
+ if(tmp)
+ pNv->table1 -= ((pNv->RamAmountKBytes << 10) - (tmp << 16));
+ else
+ pNv->table1 -= 0x10000;
+
+ /* Probe DDC */
+ /* If no DDC info found, try DAC load detection */
+ if(!xf86LoadSubModule(pScrn, "i2c")) goto fail;
+ if(!xf86LoadSubModule(pScrn, "ddc")) goto fail;
+ xf86LoaderReqSymLists(i2cSymbols, ddcSymbols, NULL);
+ if(!G80ProbeDDC(pScrn) && !G80LoadDetect(pScrn)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No display devices found\n");
+ goto fail;
+ }
+ /* Hardcode HEAD0 for now. RandR 1.2 will move this into a Crtc struct. */
+ pNv->head = 0;
+
+ i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
+ pScrn->display->modes, clockRanges,
+ NULL, 256, 8192,
+ 512, 128, 8192,
+ pScrn->display->virtualX,
+ pScrn->display->virtualY,
+ pNv->videoRam * 1024 - G80_RESERVED_VIDMEM,
+ LOOKUP_BEST_REFRESH);
+ if(i == -1) goto fail;
+ xf86PruneDriverModes(pScrn);
+ if(i == 0 || !pScrn->modes) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
+ goto fail;
+ }
+ xf86SetCrtcForModes(pScrn, 0);
+
+ pScrn->currentMode = pScrn->modes;
+ xf86PrintModes(pScrn);
+ xf86SetDpi(pScrn, 0, 0);
+
+ /* Custom backend timings */
+ pNv->BackendMode = NULL;
+ if((s = xf86GetOptValString(pNv->Options, OPTION_BACKEND_MODE))) {
+ DisplayModePtr mode;
+
+ for(mode = pScrn->modes; ; mode = mode->next) {
+ if(!strcmp(mode->name, s))
+ break;
+ if(mode->next == pScrn->modes) {
+ mode = NULL;
+ break;
+ }
+ }
+
+ pNv->BackendMode = mode;
+
+ if(mode)
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BackendMode: Using mode "
+ "\"%s\" for display timings\n", mode->name);
+ else
+ xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Cannot honor "
+ "\"BackendMode\" option: no mode named \"%s\" "
+ "found.\n", s);
+ }
+
+ /* Load fb */
+ if(!xf86LoadSubModule(pScrn, "fb")) goto fail;
+ xf86LoaderReqSymLists(fbSymbols, NULL);
+
+ if(!pNv->NoAccel) {
+ if(!xf86LoadSubModule(pScrn, "xaa")) goto fail;
+ xf86LoaderReqSymLists(xaaSymbols, NULL);
+ }
+
+ /* Load ramdac if needed */
+ if(pNv->HWCursor) {
+ if(!xf86LoadSubModule(pScrn, "ramdac")) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to load ramdac. "
+ "Falling back to software cursor.\n");
+ pNv->HWCursor = FALSE;
+ } else {
+ xf86LoaderReqSymLists(ramdacSymbols, NULL);
+ }
+ }
+
+ return TRUE;
+
+fail:
+ if(pNv->int10) xf86FreeInt10(pNv->int10);
+ G80FreeRec(pScrn);
+ return FALSE;
+}
+
+/*
+ * Initialize the display and set the current mode.
+ */
+static Bool
+AcquireDisplay(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ if(!G80DispInit(pScrn))
+ return FALSE;
+ if(!G80CursorAcquire(pNv))
+ return FALSE;
+ if(!G80DispSetMode(pScrn, pScrn->currentMode))
+ return FALSE;
+ G80DispDPMSSet(pScrn, DPMSModeOn, 0);
+
+ return TRUE;
+}
+
+/*
+ * Tear down the display and restore the console mode.
+ */
+static Bool
+ReleaseDisplay(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80CursorRelease(pNv);
+ G80DispShutdown(pScrn);
+
+ if(pNv->int10 && pNv->int10Mode) {
+ xf86Int10InfoPtr int10 = pNv->int10;
+
+ /* Use int10 to restore the console mode */
+ int10->num = 0x10;
+ int10->ax = 0x4f02;
+ int10->bx = pNv->int10Mode | 0x8000;
+ int10->cx = int10->dx = 0;
+ xf86ExecX86int10(int10);
+ }
+
+ return TRUE;
+}
+
+static Bool
+G80CloseScreen(int scrnIndex, ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ if(pScrn->vtSema)
+ ReleaseDisplay(pScrn);
+
+ if(pNv->xaa)
+ XAADestroyInfoRec(pNv->xaa);
+ if(pNv->HWCursor)
+ xf86DestroyCursorInfoRec(pNv->CursorInfo);
+
+ if(xf86ServerIsExiting()) {
+ if(pNv->int10) xf86FreeInt10(pNv->int10);
+ xf86UnMapVidMem(pScrn->scrnIndex, pNv->mem, pNv->videoRam * 1024);
+ xf86UnMapVidMem(pScrn->scrnIndex, (void*)pNv->reg, G80_REG_SIZE);
+ pNv->reg = NULL;
+ pNv->mem = NULL;
+ }
+
+ pScrn->vtSema = FALSE;
+ pScreen->CloseScreen = pNv->CloseScreen;
+ pScreen->BlockHandler = pNv->BlockHandler;
+ return (*pScreen->CloseScreen)(scrnIndex, pScreen);
+}
+
+static void
+G80BlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask)
+{
+ ScreenPtr pScreen = screenInfo.screens[i];
+ ScrnInfoPtr pScrnInfo = xf86Screens[i];
+ G80Ptr pNv = G80PTR(pScrnInfo);
+
+ if(pNv->DMAKickoffCallback)
+ (*pNv->DMAKickoffCallback)(pScrnInfo);
+
+ pScreen->BlockHandler = pNv->BlockHandler;
+ (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
+ pScreen->BlockHandler = G80BlockHandler;
+}
+
+static Bool
+G80SaveScreen(ScreenPtr pScreen, int mode)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+
+ if(!pScrn->vtSema) return FALSE;
+
+ G80DispBlankScreen(pScrn, !xf86IsUnblank(mode));
+
+ return TRUE;
+}
+
+static void
+G80InitHW(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ CARD32 bar0_pramin = 0;
+ const int pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+ volatile CARD32 *p;
+
+ /* Clear registers */
+ for(p = &pNv->reg[0x00700000/4]; p < (const CARD32*)pNv->table1; p++)
+ *p = 0;
+
+ bar0_pramin = pNv->reg[0x00001700/4] << 16;
+
+ pNv->reg[0x00000200/4] = 0xffff00ff;
+ pNv->reg[0x00000200/4] = 0xffffffff;
+ pNv->reg[0x00002100/4] = 0xffffffff;
+ pNv->reg[0x0000250c/4] = 0x6f3cfc34;
+ pNv->reg[0x00400804/4] = 0xc0000000;
+ pNv->reg[0x00406800/4] = 0xc0000000;
+ pNv->reg[0x00400c04/4] = 0xc0000000;
+ pNv->reg[0x00401800/4] = 0xc0000000;
+ pNv->reg[0x00405018/4] = 0xc0000000;
+ pNv->reg[0x00402000/4] = 0xc0000000;
+ pNv->reg[0x00400108/4] = 0xffffffff;
+ pNv->reg[0x00400100/4] = 0xffffffff;
+
+ if(pNv->architecture != 0x50) {
+ pNv->reg[0x00700000/4] = 0x00000001;
+ pNv->reg[0x00700004/4] = bar0_pramin + 0x00200;
+ pNv->reg[0x00700020/4] = 0x00190002;
+ pNv->reg[0x00700024/4] = bar0_pramin + 0x7ffff;
+ pNv->reg[0x00700028/4] = bar0_pramin + 0x20000;
+ pNv->reg[0x00700034/4] = 0x00010000;
+ } else {
+ pNv->reg[0x00700200/4] = 0x00190002;
+ pNv->reg[0x00700204/4] = bar0_pramin + 0x7ffff;
+ pNv->reg[0x00700208/4] = bar0_pramin + 0x20000;
+ pNv->reg[0x00700214/4] = 0x00010000;
+ }
+
+ pNv->reg[0x00710004/4] = 0x00100642;
+ pNv->reg[0x00710008/4] = 0x80000011;
+ pNv->reg[0x0071000c/4] = 0x00000644;
+ pNv->reg[0x00710010/4] = 0x80000012;
+ pNv->reg[0x00710014/4] = 0x00100646;
+ pNv->reg[0x00710018/4] = 0x80000013;
+ pNv->reg[0x0071001c/4] = 0x00100648;
+ pNv->reg[0x00710020/4] = 0x80000014;
+ pNv->reg[0x00710024/4] = 0x0000064a;
+ pNv->reg[0x00706420/4] = 0x00190030;
+ pNv->reg[0x00706434/4] = 0x00010000;
+ pNv->reg[0x00706440/4] = 0x0019003d;
+ pNv->reg[0x00706444/4] = (pNv->videoRam << 10) - 0x4001;
+ pNv->reg[0x00706448/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
+ pNv->reg[0x00706454/4] = 0x00010000;
+ pNv->reg[0x00706460/4] = 0x0000502d;
+ pNv->reg[0x00706474/4] = 0x00010000;
+ pNv->reg[0x00706480/4] = 0x0019003d;
+ pNv->reg[0x00706484/4] = (pNv->videoRam << 10) - G80_RESERVED_VIDMEM;
+ pNv->reg[0x00706494/4] = 0x00010000;
+ pNv->reg[0x007064a0/4] = 0x0019003d;
+ pNv->reg[0x007064a4/4] = bar0_pramin + 0x1100f;
+ pNv->reg[0x007064a8/4] = bar0_pramin + 0x11000;
+ pNv->reg[0x007064b4/4] = 0x00010000;
+
+ if(pNv->architecture != 0x50) {
+ pNv->reg[0x00002604/4] = 0x80000002 | (bar0_pramin >> 8);
+ } else {
+ pNv->reg[0x00002604/4] = 0x80000000 | (bar0_pramin >> 12);
+ }
+
+ pNv->reg[0x00003224/4] = 0x000f0078;
+ pNv->reg[0x0000322c/4] = 0x00000644;
+ pNv->reg[0x00003234/4] = G80_RESERVED_VIDMEM - 0x5001;
+ pNv->reg[0x00003254/4] = 0x00000001;
+ pNv->reg[0x00002210/4] = 0x1c001000;
+
+ if(pNv->architecture != 0x50) {
+ pNv->reg[0x0000340c/4] = (bar0_pramin + 0x1000) >> 10;
+ pNv->reg[0x00003410/4] = (bar0_pramin >> 12);
+ }
+
+ pNv->reg[0x00400824/4] = 0x00004000;
+ pNv->reg[0x00400784/4] = 0x80000000 | (bar0_pramin >> 12);
+ pNv->reg[0x00400320/4] = 0x00000004;
+ pNv->reg[0x0040032C/4] = 0x80000000 | (bar0_pramin >> 12);
+ pNv->reg[0x00400500/4] = 0x00010001;
+ pNv->reg[0x00003250/4] = 0x00000001;
+ pNv->reg[0x00003200/4] = 0x00000001;
+ pNv->reg[0x00003220/4] = 0x00001001;
+ pNv->reg[0x00003204/4] = 0x00010001;
+
+ pNv->dmaBase = (CARD32*)(pNv->mem + (pNv->videoRam << 10) -
+ G80_RESERVED_VIDMEM);
+ memset(pNv->dmaBase, 0, SKIPS*4);
+
+ pNv->dmaPut = 0;
+ pNv->dmaCurrent = SKIPS;
+ pNv->dmaMax = (G80_RESERVED_VIDMEM - 0x5000) / 4 - 2;
+ pNv->dmaFree = pNv->dmaMax - pNv->dmaCurrent;
+
+ G80DmaStart(pNv, 0, 1);
+ G80DmaNext (pNv, 0x80000012);
+ G80DmaStart(pNv, 0x180, 3);
+ G80DmaNext (pNv, 0x80000014);
+ G80DmaNext (pNv, 0x80000013);
+ G80DmaNext (pNv, 0x80000013);
+ G80DmaStart(pNv, 0x200, 2);
+ switch(pScrn->depth) {
+ case 8: G80DmaNext (pNv, 0x000000f3); break;
+ case 15: G80DmaNext (pNv, 0x000000f8); break;
+ case 16: G80DmaNext (pNv, 0x000000e8); break;
+ case 24: G80DmaNext (pNv, 0x000000e6); break;
+ }
+ G80DmaNext (pNv, 0x00000001);
+ G80DmaStart(pNv, 0x214, 5);
+ G80DmaNext (pNv, pitch);
+ G80DmaNext (pNv, pitch);
+ G80DmaNext (pNv, pNv->offscreenHeight);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaStart(pNv, 0x230, 2);
+ switch(pScrn->depth) {
+ case 8: G80DmaNext (pNv, 0x000000f3); break;
+ case 15: G80DmaNext (pNv, 0x000000f8); break;
+ case 16: G80DmaNext (pNv, 0x000000e8); break;
+ case 24: G80DmaNext (pNv, 0x000000e6); break;
+ }
+ G80DmaNext (pNv, 0x00000001);
+ G80DmaStart(pNv, 0x244, 5);
+ G80DmaNext (pNv, pitch);
+ G80DmaNext (pNv, pitch);
+ G80DmaNext (pNv, pNv->offscreenHeight);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaNext (pNv, 0x00000000);
+ G80DmaStart(pNv, 0x260, 1);
+ G80DmaNext (pNv, 0x00000001);
+ G80DmaStart(pNv, 0x290, 1);
+ G80DmaNext (pNv, 1);
+ G80DmaStart(pNv, 0x29c, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaStart(pNv, 0x2e8, 2);
+ switch(pScrn->depth) {
+ case 8: G80DmaNext (pNv, 3); break;
+ case 15: G80DmaNext (pNv, 1); break;
+ case 16: G80DmaNext (pNv, 0); break;
+ case 24: G80DmaNext (pNv, 2); break;
+ }
+ G80DmaNext (pNv, 1);
+ G80DmaStart(pNv, 0x584, 1);
+ switch(pScrn->depth) {
+ case 8: G80DmaNext (pNv, 0xf3); break;
+ case 15: G80DmaNext (pNv, 0xf8); break;
+ case 16: G80DmaNext (pNv, 0xe8); break;
+ case 24: G80DmaNext (pNv, 0xe6); break;
+ }
+ G80DmaStart(pNv, 0x58c, 1);
+ G80DmaNext (pNv, 0x111);
+ G80DmaStart(pNv, 0x804, 1);
+ switch(pScrn->depth) {
+ case 8: G80DmaNext (pNv, 0xf3); break;
+ case 15: G80DmaNext (pNv, 0xf8); break;
+ case 16: G80DmaNext (pNv, 0xe8); break;
+ case 24: G80DmaNext (pNv, 0xe6); break;
+ }
+
+ pNv->currentRop = ~0; /* Set to something invalid */
+}
+
+#define DEPTH_SHIFT(val, w) ((val << (8 - w)) | (val >> ((w << 1) - 8)))
+#define COLOR(c) (unsigned int)(0x3fff * ((c)/255.0))
+static void
+G80LoadPalette(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors,
+ VisualPtr pVisual)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ int i, index;
+ volatile struct {
+ unsigned short red, green, blue, unused;
+ } *lut = (void*)&pNv->mem[pNv->videoRam * 1024 - 0x5000];
+
+ switch(pScrn->depth) {
+ case 15:
+ for(i = 0; i < numColors; i++) {
+ index = indices[i];
+ lut[DEPTH_SHIFT(index, 5)].red = COLOR(colors[index].red);
+ lut[DEPTH_SHIFT(index, 5)].green = COLOR(colors[index].green);
+ lut[DEPTH_SHIFT(index, 5)].blue = COLOR(colors[index].blue);
+ }
+ break;
+ case 16:
+ for(i = 0; i < numColors; i++) {
+ index = indices[i];
+ lut[DEPTH_SHIFT(index, 6)].green = COLOR(colors[index].green);
+ if(index < 32) {
+ lut[DEPTH_SHIFT(index, 5)].red = COLOR(colors[index].red);
+ lut[DEPTH_SHIFT(index, 5)].blue = COLOR(colors[index].blue);
+ }
+ }
+ break;
+ default:
+ for(i = 0; i < numColors; i++) {
+ index = indices[i];
+ lut[index].red = COLOR(colors[index].red);
+ lut[index].green = COLOR(colors[index].green);
+ lut[index].blue = COLOR(colors[index].blue);
+ }
+ break;
+ }
+}
+
+static Bool
+G80ScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
+{
+ ScrnInfoPtr pScrn;
+ G80Ptr pNv;
+ CARD32 pitch;
+ int visualMask;
+ BoxRec AvailFBArea;
+
+ /* First get the ScrnInfoRec */
+ pScrn = xf86Screens[pScreen->myNum];
+ pNv = G80PTR(pScrn);
+
+ pScrn->vtSema = TRUE;
+
+ /* DIX visual init */
+ miClearVisualTypes();
+ visualMask = miGetDefaultVisualMask(pScrn->depth);
+ if(!miSetVisualTypes(pScrn->depth, visualMask, 8, pScrn->defaultVisual))
+ return FALSE;
+ if(!miSetPixmapDepths())
+ return FALSE;
+
+ /* pad the screen pitch to 256 bytes */
+ pitch = pScrn->displayWidth * (pScrn->bitsPerPixel / 8);
+ pitch = (pitch + 0xff) & ~0xff;
+ pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
+
+ /* fb init */
+ if(!fbScreenInit(pScreen, pNv->mem,
+ pScrn->virtualX, pScrn->virtualY,
+ pScrn->xDpi, pScrn->yDpi,
+ pScrn->displayWidth, pScrn->bitsPerPixel))
+ return FALSE;
+
+ if(pScrn->bitsPerPixel > 8) {
+ VisualPtr visual;
+
+ /* Fixup RGB ordering */
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while(--visual >= pScreen->visuals) {
+ if((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ fbPictureInit(pScreen, 0, 0);
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ pNv->offscreenHeight = ((pNv->videoRam << 10) - G80_RESERVED_VIDMEM) / pitch;
+ if(pNv->offscreenHeight > 32767) pNv->offscreenHeight = 32767;
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "%.2f MB available for offscreen pixmaps\n",
+ (pNv->offscreenHeight - pScrn->virtualY) * pitch / 1024.0 / 1024.0);
+
+ AvailFBArea.x1 = 0;
+ AvailFBArea.y1 = 0;
+ AvailFBArea.x2 = pScrn->displayWidth;
+ AvailFBArea.y2 = pNv->offscreenHeight;
+ xf86InitFBManager(pScreen, &AvailFBArea);
+
+ if(!pNv->NoAccel) {
+ G80InitHW(pScrn);
+ if(!G80XAAInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Hardware acceleration initialization failed\n");
+ pNv->NoAccel = FALSE;
+ }
+ }
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+ xf86SetSilkenMouse(pScreen);
+
+ /* Initialize software cursor.
+ Must precede creation of the default colormap */
+ miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
+
+ /* Initialize hardware cursor. Must follow software cursor initialization. */
+ if(pNv->HWCursor && !G80CursorInit(pScreen)) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Hardware cursor initialization failed\n");
+ pNv->HWCursor = FALSE;
+ }
+
+ /* Initialize default colormap */
+ if(!miCreateDefColormap(pScreen))
+ return FALSE;
+
+ /* Initialize colormap layer.
+ Must follow initialization of the default colormap */
+ if(!xf86HandleColormaps(pScreen, 256, 8, G80LoadPalette, NULL,
+ CMAP_PALETTED_TRUECOLOR))
+ return FALSE;
+
+ xf86DPMSInit(pScreen, G80DispDPMSSet, 0);
+
+ /* Clear the screen */
+ if(pNv->xaa) {
+ /* Use the acceleration engine */
+ pNv->xaa->SetupForSolidFill(pScrn, 0, GXcopy, ~0);
+ pNv->xaa->SubsequentSolidFillRect(pScrn,
+ 0, 0, pScrn->displayWidth, pNv->offscreenHeight);
+ G80DmaKickoff(pNv);
+ } else {
+ /* Use a slow software clear path */
+ memset(pNv->mem, 0, pitch * pNv->offscreenHeight);
+ }
+
+ /* Initialize the display */
+ if(!AcquireDisplay(pScrn))
+ return FALSE;
+
+ pScreen->SaveScreen = G80SaveScreen;
+
+ pNv->CloseScreen = pScreen->CloseScreen;
+ pScreen->CloseScreen = G80CloseScreen;
+
+ pNv->BlockHandler = pScreen->BlockHandler;
+ pScreen->BlockHandler = G80BlockHandler;
+
+ return TRUE;
+}
+
+static void
+G80FreeScreen(int scrnIndex, int flags)
+{
+ G80FreeRec(xf86Screens[scrnIndex]);
+}
+
+static Bool
+G80SwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+ return G80DispSetMode(pScrn, mode);
+}
+
+static void
+G80AdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ if(x + pScrn->currentMode->HDisplay > pScrn->virtualX ||
+ y + pScrn->currentMode->VDisplay > pScrn->virtualY ||
+ x < 0 || y < 0)
+ /* Ignore bogus panning */
+ return;
+ G80DispAdjustFrame(pNv, x, y);
+}
+
+static Bool
+G80EnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ G80Ptr pNv = G80PTR(pScrn);
+
+ /* Reinit the hardware */
+ if(pNv->xaa)
+ G80InitHW(pScrn);
+
+ if(!AcquireDisplay(pScrn))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+G80LeaveVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+
+ ReleaseDisplay(pScrn);
+}
+
+Bool G80GetScrnInfoRec(PciChipsets *chips, int chip)
+{
+ ScrnInfoPtr pScrn;
+
+ pScrn = xf86ConfigPciEntity(NULL, 0, chip,
+ chips, NULL, NULL, NULL,
+ NULL, NULL);
+
+ if(!pScrn) return FALSE;
+
+ pScrn->driverVersion = NV_VERSION;
+ pScrn->driverName = NV_DRIVER_NAME;
+ pScrn->name = NV_NAME;
+
+ pScrn->PreInit = G80PreInit;
+ pScrn->ScreenInit = G80ScreenInit;
+ pScrn->SwitchMode = G80SwitchMode;
+ pScrn->AdjustFrame = G80AdjustFrame;
+ pScrn->EnterVT = G80EnterVT;
+ pScrn->LeaveVT = G80LeaveVT;
+ pScrn->FreeScreen = G80FreeScreen;
+ // pScrn->ValidMode = G80ValidMode;
+
+ return TRUE;
+}
diff --git a/src/g80_type.h b/src/g80_type.h
new file mode 100644
index 0000000..39d737c
--- /dev/null
+++ b/src/g80_type.h
@@ -0,0 +1,75 @@
+#include <xaa.h>
+#include <xf86.h>
+#include <xf86int10.h>
+#include <xf86Cursor.h>
+
+typedef enum Head {
+ HEAD0 = 0,
+ HEAD1
+} Head;
+
+typedef enum ORType {
+ DAC,
+ SOR
+} ORType;
+
+typedef enum ORNum {
+ DAC0 = 0,
+ DAC1 = 1,
+ DAC2 = 2,
+ SOR0 = 0,
+ SOR1 = 1
+} ORNum;
+
+typedef struct G80Rec {
+ volatile CARD32 * reg;
+ unsigned char * mem;
+
+ /* Probed data */
+ CARD32 architecture;
+ CARD32 RamAmountKBytes; /* Total vidmem */
+ CARD32 videoRam; /* Mapped vidmem */
+ const unsigned char*table1;
+ int offscreenHeight;
+ struct {
+ ORNum dac;
+ ORNum sor;
+ } i2cMap[4];
+
+ float pclk; /* Current mode pclk in kHz */
+
+ Head head;
+ ORType orType;
+ ORNum or;
+
+ xf86Int10InfoPtr int10;
+ int int10Mode; /* Console mode to restore */
+
+ /* Options */
+ OptionInfoPtr Options;
+ Bool HWCursor;
+ Bool NoAccel;
+ DisplayModePtr BackendMode;
+
+ /* Cursor */
+ xf86CursorInfoPtr CursorInfo;
+ Bool cursorVisible;
+ CARD32 tmpCursor[256]; /* Temporary 1bpp cursor image */
+
+ /* XAA */
+ XAAInfoRecPtr xaa;
+ CARD32 currentRop;
+
+ /* DMA command buffer */
+ CARD32 dmaPut;
+ CARD32 dmaCurrent;
+ CARD32 dmaFree;
+ CARD32 dmaMax;
+ CARD32 * dmaBase;
+ void (*DMAKickoffCallback)(ScrnInfoPtr);
+
+ CloseScreenProcPtr CloseScreen;
+ ScreenBlockHandlerProcPtr BlockHandler;
+} G80Rec, *G80Ptr;
+
+#define G80PTR(p) ((G80Ptr)((p)->driverPrivate))
diff --git a/src/g80_xaa.c b/src/g80_xaa.c
new file mode 100644
index 0000000..1f07444
--- /dev/null
+++ b/src/g80_xaa.c
@@ -0,0 +1,554 @@
+/*
+ * 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 <miline.h>
+
+#include "g80_type.h"
+#include "g80_dma.h"
+#include "g80_xaa.h"
+
+static void
+G80Sync(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ volatile CARD16 *pSync = (volatile CARD16*)&pNv->reg[0x00711008/4] + 1;
+
+ G80DmaStart(pNv, 0x104, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaStart(pNv, 0x100, 1);
+ G80DmaNext (pNv, 0);
+
+ *pSync = 0x8000;
+ G80DmaKickoff(pNv);
+ while(*pSync);
+}
+
+static void
+G80DMAKickoffCallback(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaKickoff(pNv);
+ pNv->DMAKickoffCallback = NULL;
+}
+
+static void
+G80SetPattern(G80Ptr pNv, int bg, int fg, int pat0, int pat1)
+{
+ G80DmaStart(pNv, 0x2f0, 4);
+ G80DmaNext (pNv, bg);
+ G80DmaNext (pNv, fg);
+ G80DmaNext (pNv, pat0);
+ G80DmaNext (pNv, pat1);
+}
+
+static void
+G80SetRopSolid(G80Ptr pNv, CARD32 rop, CARD32 planemask)
+{
+ static const int rops[] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
+ 0x30, 0xB0, 0x70, 0xF0
+ };
+
+ if(planemask != ~0) {
+ G80SetPattern(pNv, 0, planemask, ~0, ~0);
+ if(pNv->currentRop != (rop + 32)) {
+ pNv->currentRop = rop + 32;
+
+ rop = rops[rop] | 0xA;
+ G80DmaStart(pNv, 0x2a0, 1);
+ G80DmaNext (pNv, rop);
+ }
+ } else if(pNv->currentRop != rop) {
+ if(pNv->currentRop >= 16)
+ G80SetPattern(pNv, ~0, ~0, ~0, ~0);
+ pNv->currentRop = rop;
+
+ rop = rops[rop];
+ rop |= rop >> 4;
+ G80DmaStart(pNv, 0x2a0, 1);
+ G80DmaNext (pNv, rop);
+ }
+}
+
+static void inline
+G80SetClip(G80Ptr pNv, int x, int y, int w, int h)
+{
+ G80DmaStart(pNv, 0x280, 4);
+ G80DmaNext (pNv, x);
+ G80DmaNext (pNv, y);
+ G80DmaNext (pNv, w);
+ G80DmaNext (pNv, h);
+}
+
+/* Screen to screen copies */
+
+static void
+G80SetupForScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int xdir, int ydir,
+ int rop,
+ unsigned planemask,
+ int transparency_color
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ planemask |= ~0 << pScrn->depth;
+
+ G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+ G80DmaStart(pNv, 0x2ac, 1);
+ if(rop == GXcopy && planemask == ~0) {
+ G80DmaNext (pNv, 3);
+ } else {
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, rop, planemask);
+ }
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentScreenToScreenCopy(
+ ScrnInfoPtr pScrn,
+ int x1, int y1,
+ int x2, int y2,
+ int w, int h
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaStart(pNv, 0x110, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaStart(pNv, 0x8b0, 12);
+ G80DmaNext (pNv, x2);
+ G80DmaNext (pNv, y2);
+ G80DmaNext (pNv, w);
+ G80DmaNext (pNv, h);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, x1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, y1);
+
+ if(w * h >= 512)
+ G80DmaKickoff(pNv);
+}
+
+/* Solid fills */
+
+static void
+G80SetupForSolidFill(
+ ScrnInfoPtr pScrn,
+ int color,
+ int rop,
+ unsigned planemask
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ planemask |= ~0 << pScrn->depth;
+
+ G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, rop, planemask);
+ G80DmaStart(pNv, 0x580, 1);
+ G80DmaNext (pNv, 4);
+ G80DmaStart(pNv, 0x588, 1);
+ G80DmaNext (pNv, color);
+
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentFillRect(ScrnInfoPtr pScrn, int x, int y, int w, int h)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaStart(pNv, 0x600, 4);
+ G80DmaNext (pNv, x);
+ G80DmaNext (pNv, y);
+ G80DmaNext (pNv, x + w);
+ G80DmaNext (pNv, y + h);
+
+ if(w * h >= 512)
+ G80DmaKickoff(pNv);
+}
+
+/* 8x8 pattern fills */
+
+static void
+G80SetupForMono8x8PatternFill(
+ ScrnInfoPtr pScrn,
+ int patternx, int patterny,
+ int fg, int bg,
+ int rop,
+ unsigned planemask
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ static const int rops[] = {
+ 0x00, 0xA0, 0x50, 0xF0, 0x0A, 0xAA, 0x5A, 0xFA, 0x05, 0xA5, 0x55, 0xF5,
+ 0x0F, 0xAF, 0x5F, 0xFF
+ };
+
+ planemask = ~0 << pScrn->depth;
+
+ fg |= planemask;
+ if(bg == -1) bg = 0;
+ else bg |= planemask;
+
+ if(pNv->currentRop != (rop + 16)) {
+ G80DmaStart(pNv, 0x2a0, 1);
+ G80DmaNext (pNv, rops[rop]);
+ pNv->currentRop = rop + 16;
+ }
+
+ G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+ G80SetPattern(pNv, bg, fg, patternx, patterny);
+
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 1);
+ G80DmaStart(pNv, 0x580, 1);
+ G80DmaNext (pNv, 4);
+ G80DmaStart(pNv, 0x588, 1);
+ G80DmaNext (pNv, fg);
+
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentMono8x8PatternFillRect(
+ ScrnInfoPtr pScrn,
+ int patternx, int patterny,
+ int x, int y,
+ int w, int h
+)
+{
+ G80SubsequentFillRect(pScrn, x, y, w, h);
+}
+
+/* Color expansion fills */
+
+static CARD32 _color_expand_dwords;
+static int _remaining;
+static unsigned char *_storage_buffer[1];
+
+static void
+G80SetupForScanlineCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int fg, int bg,
+ int rop,
+ unsigned int planemask
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ CARD32 mask = ~0 << pScrn->depth;
+
+ planemask |= mask;
+
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, rop, planemask);
+ G80DmaStart(pNv, 0x800, 1);
+ G80DmaNext (pNv, 1);
+ G80DmaStart(pNv, 0x808, 6);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, 1);
+ G80DmaNext (pNv, 0);
+ G80DmaNext (pNv, bg | mask);
+ G80DmaNext (pNv, fg | mask);
+ G80DmaNext (pNv, (bg == -1) ? 0 : 1);
+}
+
+static void
+G80SubsequentScanlineCPUToScreenColorExpandFill(
+ ScrnInfoPtr pScrn,
+ int x, int y,
+ int w, int h,
+ int skipleft
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ int bw = (w + 31) & ~31;
+
+ _color_expand_dwords = bw >> 5;
+ _remaining = h;
+
+ G80SetClip(pNv, x + skipleft, y, w - skipleft, h);
+
+ G80DmaStart(pNv, 0x838, 10);
+ G80DmaNext (pNv, bw);
+ 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);
+
+ G80DmaStart(pNv, 0x40000860, _color_expand_dwords);
+ _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+}
+
+static void
+G80SubsequentColorExpandScanline(ScrnInfoPtr pScrn, int bufno)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ pNv->dmaCurrent += _color_expand_dwords;
+
+ if(--_remaining) {
+ G80DmaStart(pNv, 0x40000860, _color_expand_dwords);
+ _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+ } else {
+ G80DmaKickoff(pNv);
+ }
+}
+
+/* Scaline image write */
+
+static void
+G80SetupForScanlineImageWrite(
+ ScrnInfoPtr pScrn, int rop,
+ unsigned int planemask,
+ int trans_color,
+ int bpp, int depth
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ planemask |= ~0 << pScrn->depth;
+
+ G80DmaStart(pNv, 0x2ac, 1);
+ if(rop == GXcopy && planemask == ~0) {
+ G80DmaNext (pNv, 3);
+ } else {
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, rop, planemask);
+ }
+
+ G80DmaStart(pNv, 0x800, 1);
+ G80DmaNext (pNv, 0);
+}
+
+static CARD32 _image_dwords;
+
+static void
+G80SubsequentScanlineImageWriteRect(
+ ScrnInfoPtr pScrn,
+ int x, int y,
+ int w, int h,
+ int skipleft
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ int Bpp = pScrn->bitsPerPixel >> 3;
+
+ _remaining = h;
+ _image_dwords = (w * Bpp + 3) / 4;
+
+ G80SetClip(pNv, x + skipleft, y, w - skipleft, h);
+
+ G80DmaStart(pNv, 0x838, 10);
+ G80DmaNext (pNv, w);
+ 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);
+
+ G80DmaStart(pNv, 0x40000860, _image_dwords);
+ _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+}
+
+static void G80SubsequentImageWriteScanline(ScrnInfoPtr pScrn, int bufno)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ pNv->dmaCurrent += _image_dwords;
+
+ if(--_remaining) {
+ G80DmaStart(pNv, 0x40000860, _image_dwords);
+ _storage_buffer[0] = (unsigned char*)&pNv->dmaBase[pNv->dmaCurrent];
+ } else {
+ G80DmaKickoff(pNv);
+ }
+}
+
+/* Solid lines */
+
+static void
+G80SetupForSolidLine(ScrnInfoPtr pScrn, int color, int rop, unsigned planemask)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ planemask |= ~0 << pScrn->depth;
+
+ G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+ G80DmaStart(pNv, 0x2ac, 1);
+ G80DmaNext (pNv, 1);
+ G80SetRopSolid(pNv, rop, planemask);
+ G80DmaStart(pNv, 0x580, 1);
+ G80DmaNext (pNv, 1);
+ G80DmaStart(pNv, 0x588, 1);
+ G80DmaNext (pNv, color);
+
+ pNv->DMAKickoffCallback = G80DMAKickoffCallback;
+}
+
+static void
+G80SubsequentSolidHorVertLine(ScrnInfoPtr pScrn, int x, int y, int len, int dir)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80DmaStart(pNv, 0x400005e0, 2);
+ G80DmaNext (pNv, (y << 16) | (x & 0xffff));
+ if(dir == DEGREES_0) {
+ G80DmaNext (pNv, (y << 16) | ((x + len) & 0xffff));
+ } else {
+ G80DmaNext (pNv, ((y + len) << 16) | (x & 0xffff));
+ }
+}
+
+static void
+G80SubsequentSolidTwoPointLine(
+ ScrnInfoPtr pScrn,
+ int x1, int y1,
+ int x2, int y2,
+ int flags
+)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ Bool drawLast = !(flags & OMIT_LAST);
+
+ G80DmaStart(pNv, 0x400005e0, drawLast ? 4 : 2);
+ G80DmaNext (pNv, (y1 << 16) | (x1 & 0xffff));
+ G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff));
+ if(drawLast) {
+ G80DmaNext (pNv, (y2 << 16) | (x2 & 0xffff));
+ G80DmaNext (pNv, ((y2 + 1) << 16) | (x2 & 0xffff));
+ }
+}
+
+static void
+G80SetClippingRectangle(ScrnInfoPtr pScrn, int x1, int y1, int x2, int y2)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+ int h = y2 - y1 + 1;
+ int w = x2 - x1 + 1;
+
+ G80SetClip(pNv, x1, y1, w, h);
+}
+
+static void
+G80DisableClipping(ScrnInfoPtr pScrn)
+{
+ G80Ptr pNv = G80PTR(pScrn);
+
+ G80SetClip(pNv, 0, 0, 0x7fff, 0x7fff);
+}
+
+
+Bool
+G80XAAInit(ScreenPtr pScreen)
+{
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ G80Ptr pNv = G80PTR(pScrn);
+ XAAInfoRecPtr xaa;
+
+ xaa = pNv->xaa = XAACreateInfoRec();
+ if(!xaa) return FALSE;
+
+ xaa->Flags = LINEAR_FRAMEBUFFER | PIXMAP_CACHE | OFFSCREEN_PIXMAPS;
+ xaa->Sync = G80Sync;
+
+ /* Screen to screen copies */
+ xaa->ScreenToScreenCopyFlags = NO_TRANSPARENCY;
+ xaa->SetupForScreenToScreenCopy = G80SetupForScreenToScreenCopy;
+ xaa->SubsequentScreenToScreenCopy = G80SubsequentScreenToScreenCopy;
+
+ /* Solid fills */
+ xaa->SolidFillFlags = 0;
+ xaa->SetupForSolidFill = G80SetupForSolidFill;
+ xaa->SubsequentSolidFillRect = G80SubsequentFillRect;
+
+ /* 8x8 pattern fills */
+ xaa->Mono8x8PatternFillFlags = HARDWARE_PATTERN_SCREEN_ORIGIN |
+ HARDWARE_PATTERN_PROGRAMMED_BITS |
+ NO_PLANEMASK;
+ xaa->SetupForMono8x8PatternFill = G80SetupForMono8x8PatternFill;
+ xaa->SubsequentMono8x8PatternFillRect = G80SubsequentMono8x8PatternFillRect;
+
+ /* Color expansion fills */
+ xaa->ScanlineCPUToScreenColorExpandFillFlags =
+ BIT_ORDER_IN_BYTE_LSBFIRST |
+ CPU_TRANSFER_PAD_DWORD |
+ LEFT_EDGE_CLIPPING |
+ LEFT_EDGE_CLIPPING_NEGATIVE_X;
+ xaa->NumScanlineColorExpandBuffers = 1;
+ xaa->SetupForScanlineCPUToScreenColorExpandFill =
+ G80SetupForScanlineCPUToScreenColorExpandFill;
+ xaa->SubsequentScanlineCPUToScreenColorExpandFill =
+ G80SubsequentScanlineCPUToScreenColorExpandFill;
+ xaa->SubsequentColorExpandScanline =
+ G80SubsequentColorExpandScanline;
+ xaa->ScanlineColorExpandBuffers = _storage_buffer;
+
+ /* Scaline image write */
+ xaa->ScanlineImageWriteFlags = NO_GXCOPY |
+ NO_TRANSPARENCY |
+ LEFT_EDGE_CLIPPING |
+ LEFT_EDGE_CLIPPING_NEGATIVE_X;
+ xaa->NumScanlineImageWriteBuffers = 1;
+ xaa->SetupForScanlineImageWrite = G80SetupForScanlineImageWrite;
+ xaa->SubsequentScanlineImageWriteRect = G80SubsequentScanlineImageWriteRect;
+ xaa->SubsequentImageWriteScanline = G80SubsequentImageWriteScanline;
+ xaa->ScanlineImageWriteBuffers = _storage_buffer;
+
+ /* Solid lines */
+ xaa->SolidLineFlags = 0;
+ xaa->SetupForSolidLine = G80SetupForSolidLine;
+ xaa->SubsequentSolidHorVertLine = G80SubsequentSolidHorVertLine;
+ xaa->SubsequentSolidTwoPointLine = G80SubsequentSolidTwoPointLine;
+ xaa->SetClippingRectangle = G80SetClippingRectangle;
+ xaa->DisableClipping = G80DisableClipping;
+ xaa->ClippingFlags = HARDWARE_CLIP_SOLID_LINE;
+
+ miSetZeroLineBias(pScreen, OCTANT1 | OCTANT3 | OCTANT4 | OCTANT6);
+
+ return XAAInit(pScreen, xaa);
+}
diff --git a/src/g80_xaa.h b/src/g80_xaa.h
new file mode 100644
index 0000000..e2f1f63
--- /dev/null
+++ b/src/g80_xaa.h
@@ -0,0 +1 @@
+Bool G80XAAInit(ScreenPtr);
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 8f40cfa..64d45c5 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -37,6 +37,7 @@
const OptionInfoRec * RivaAvailableOptions(int chipid, int busid);
Bool RivaGetScrnInfoRec(PciChipsets *chips, int chip);
+Bool G80GetScrnInfoRec(PciChipsets *chips, int chip);
/*
* Forward definitions for the functions that make up the driver.
@@ -332,6 +333,13 @@ static SymTabRec NVKnownChipsets[] =
{ 0x10DE0244, "GeForce Go 6150" },
{ 0x10DE0247, "GeForce Go 6100" },
+#if SUPPORT_G80
+ { 0x10DE0191, "GeForce 8800 GTX" },
+ { 0x10DE0193, "GeForce 8800 GTS" },
+ { 0x10DE019D, "Quadro FX 5600" },
+ { 0x10DE019E, "Quadro FX 4600" },
+#endif
+
{-1, NULL}
};
@@ -647,6 +655,20 @@ NVGetPCIXpressChip (pciVideoPtr pVideo)
return pciid;
}
+#if SUPPORT_G80
+static Bool
+NVIsG80(int chipType)
+{
+ switch(chipType & 0xfff0) {
+ case 0x0190:
+ case 0x0400:
+ case 0x0420:
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
/* Mandatory */
static Bool
@@ -700,6 +722,8 @@ NVProbe(DriverPtr drv, int flags)
NVPciChipsets[numUsed].resList = RES_SHARED_VGA;
numUsed++;
} else if ((*ppPci)->vendor == PCI_VENDOR_NVIDIA) {
+ Bool canHandle = FALSE;
+
/* look for a compatible devices which may be newer than
the NVKnownChipsets list above. */
switch(token & 0xfff0) {
@@ -725,14 +749,23 @@ NVProbe(DriverPtr drv, int flags)
case 0x0290:
case 0x0390:
case 0x03D0:
+ canHandle = TRUE;
+ break;
+ default: break; /* we don't recognize it */
+ }
+
+#if SUPPORT_G80
+ if(NVIsG80((*ppPci)->chipType))
+ canHandle = TRUE;
+#endif
+
+ if(canHandle) {
NVChipsets[numUsed].token = pciid;
NVChipsets[numUsed].name = "Unknown NVIDIA chip";
NVPciChipsets[numUsed].numChipset = pciid;
NVPciChipsets[numUsed].PCIid = pciid;
NVPciChipsets[numUsed].resList = RES_SHARED_VGA;
numUsed++;
- break;
- default: break; /* we don't recognize it */
}
}
}
@@ -762,6 +795,11 @@ NVProbe(DriverPtr drv, int flags)
if(pPci->vendor == PCI_VENDOR_NVIDIA_SGS) {
if(RivaGetScrnInfoRec(NVPciChipsets, usedChips[i]))
foundScreen = TRUE;
+#if SUPPORT_G80
+ } else if (NVIsG80(pPci->chipType)) {
+ if(G80GetScrnInfoRec(NVPciChipsets, usedChips[i]))
+ foundScreen = TRUE;
+#endif
} else {
if(NVGetScrnInfoRec(NVPciChipsets, usedChips[i]))
foundScreen = TRUE;
diff --git a/src/nv_include.h b/src/nv_include.h
index 071a4a0..03f2997 100644
--- a/src/nv_include.h
+++ b/src/nv_include.h
@@ -6,6 +6,7 @@
#if !USE_LIBC_WRAPPER
#include <string.h>
#include <math.h>
+#include <unistd.h>
#endif
/* All drivers should typically include these */
@@ -55,7 +56,6 @@
#include "vgaHW.h"
#include "xf86Cursor.h"
-#include "xf86DDC.h"
#include "region.h"