diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2007-02-16 16:11:13 -0800 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2007-03-08 18:02:07 -0800 |
commit | 23383c2c2e1aa590f69197b1860053d5cb710cf7 (patch) | |
tree | 51f52a41d53fdc28521381708f513538e0e9f3ca | |
parent | dd305c3f64f9267d54324d734f1028bfc00e474f (diff) |
Initial G80 support. Bump to 1.99.1.
-rw-r--r-- | COPYING | 26 | ||||
-rw-r--r-- | configure.ac | 13 | ||||
-rw-r--r-- | man/Makefile.am | 9 | ||||
-rw-r--r-- | man/nv.man | 80 | ||||
-rw-r--r-- | src/Makefile.am | 24 | ||||
-rw-r--r-- | src/g80_cursor.c | 185 | ||||
-rw-r--r-- | src/g80_cursor.h | 3 | ||||
-rw-r--r-- | src/g80_ddc.c | 232 | ||||
-rw-r--r-- | src/g80_ddc.h | 1 | ||||
-rw-r--r-- | src/g80_display.c | 515 | ||||
-rw-r--r-- | src/g80_display.h | 9 | ||||
-rw-r--r-- | src/g80_dma.c | 65 | ||||
-rw-r--r-- | src/g80_dma.h | 14 | ||||
-rw-r--r-- | src/g80_driver.c | 916 | ||||
-rw-r--r-- | src/g80_type.h | 75 | ||||
-rw-r--r-- | src/g80_xaa.c | 554 | ||||
-rw-r--r-- | src/g80_xaa.h | 1 | ||||
-rw-r--r-- | src/nv_driver.c | 42 | ||||
-rw-r--r-- | src/nv_include.h | 2 |
19 files changed, 2719 insertions, 47 deletions
@@ -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 @@ -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" |