Initial G80 support. Bump to 1.99.1.

This commit is contained in:
Aaron Plattner
2007-02-16 16:11:13 -08:00
parent dd305c3f64
commit 23383c2c2e
19 changed files with 2719 additions and 47 deletions

26
COPYING
View File

@@ -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.

View File

@@ -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.

View File

@@ -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

View File

@@ -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.
Copyright (c) 2003 - 2007 NVIDIA, Corporation
.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:
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
Copyright 1993-2003 NVIDIA, Corporation. All rights reserved.
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.
.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.
.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.

View File

@@ -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

185
src/g80_cursor.c Normal file
View File

@@ -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);
}

3
src/g80_cursor.h Normal file
View File

@@ -0,0 +1,3 @@
Bool G80CursorInit(ScreenPtr);
Bool G80CursorAcquire(G80Ptr);
void G80CursorRelease(G80Ptr);

232
src/g80_ddc.c Normal file
View File

@@ -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;
}

1
src/g80_ddc.h Normal file
View File

@@ -0,0 +1 @@
Bool G80ProbeDDC(ScrnInfoPtr pScrn);

515
src/g80_display.c Normal file
View File

@@ -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);
}

9
src/g80_display.h Normal file
View File

@@ -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);

65
src/g80_dma.c Normal file
View File

@@ -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;
}
}

14
src/g80_dma.h Normal file
View File

@@ -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);

916
src/g80_driver.c Normal file
View File

@@ -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;
}

75
src/g80_type.h Normal file
View File

@@ -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))

554
src/g80_xaa.c Normal file
View File

@@ -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);
}

1
src/g80_xaa.h Normal file
View File

@@ -0,0 +1 @@
Bool G80XAAInit(ScreenPtr);

View File

@@ -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;

View File

@@ -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"