Files
xf86-video-nv/src/g80_driver.c
2008-04-28 14:45:11 -07:00

1030 lines
31 KiB
C

/*
* 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 <xf86RandR12.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_dma.h"
#include "g80_output.h"
#include "g80_exa.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 *exaSymbols[] = {
"exaDriverAlloc",
"exaDriverInit",
"exaDriverFini",
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_ACCEL_METHOD,
OPTION_FP_DITHER,
} G80Opts;
static const OptionInfoRec G80Options[] = {
{ OPTION_HW_CURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE },
{ OPTION_FP_DITHER, "FPDither", OPTV_BOOLEAN, {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
G80ResizeScreen(ScrnInfoPtr pScrn, int width, int height)
{
ScreenPtr pScreen = pScrn->pScreen;
G80Ptr pNv = G80PTR(pScrn);
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
int pitch = width * (pScrn->bitsPerPixel / 8);
int i;
pitch = (pitch + 255) & ~255;
pScrn->virtualX = width;
pScrn->virtualY = height;
/* Can resize if XAA is disabled or EXA is enabled */
if(!pNv->xaa || pNv->exa) {
(*pScrn->pScreen->GetScreenPixmap)(pScrn->pScreen)->devKind = pitch;
pScrn->displayWidth = pitch / (pScrn->bitsPerPixel / 8);
/* Re-set the modes so the new pitch is taken into account */
for(i = 0; i < xf86_config->num_crtc; i++) {
xf86CrtcPtr crtc = xf86_config->crtc[i];
if(crtc->enabled)
xf86CrtcSetMode(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y);
}
}
/*
* If EXA is enabled, use exaOffscreenAlloc to carve out a chunk of memory
* for the screen.
*/
if(pNv->exa) {
if(pNv->exaScreenArea)
exaOffscreenFree(pScreen, pNv->exaScreenArea);
pNv->exaScreenArea = exaOffscreenAlloc(pScreen, pitch * pScrn->virtualY,
256, TRUE, NULL, NULL);
if(!pNv->exaScreenArea || pNv->exaScreenArea->offset != 0) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Failed to reserve EXA memory for the screen or EXA "
"returned an area with a nonzero offset. Don't be "
"surprised if your screen is corrupt.\n");
}
}
return TRUE;
}
static const xf86CrtcConfigFuncsRec randr12_screen_funcs = {
.resize = G80ResizeScreen,
};
static Bool
G80PreInit(ScrnInfoPtr pScrn, int flags)
{
G80Ptr pNv;
EntityInfoPtr pEnt;
#if XSERVER_LIBPCIACCESS
struct pci_device *pPci;
int err;
void *p;
#else
pciVideoPtr pPci;
PCITAG pcitag;
#endif
MessageType from;
Bool primary;
const rgb zeros = {0, 0, 0};
const Gamma gzeros = {0.0, 0.0, 0.0};
char *s;
CARD32 tmp;
memType BAR1sizeKB;
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);
#if XSERVER_LIBPCIACCESS
/* Need this to unmap */
pNv->pPci = pPci;
#endif
primary = xf86IsPrimaryPci(pPci);
/* The ROM size sometimes isn't read correctly, so fix it up here. */
#if XSERVER_LIBPCIACCESS
if(pPci->rom_size == 0)
/* The BIOS is 64k */
pPci->rom_size = 64 * 1024;
#else
if(pPci->biosSize == 0)
/* The BIOS is 64k */
pPci->biosSize = 16;
#endif
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");
}
s = xf86GetOptValString(pNv->Options, OPTION_ACCEL_METHOD);
if(!s || !strcasecmp(s, "xaa"))
pNv->AccelMethod = XAA;
else if(!strcasecmp(s, "exa"))
pNv->AccelMethod = EXA;
else {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Unrecognized AccelMethod "
"\"%s\".\n", s);
goto fail;
}
pNv->Dither = xf86ReturnOptValBool(pNv->Options, OPTION_FP_DITHER, FALSE);
/* Set the bits per RGB for 8bpp mode */
if(pScrn->depth == 8)
pScrn->rgbBits = 8;
if(!xf86SetGamma(pScrn, gzeros)) goto fail;
/* Map memory */
pScrn->memPhysBase = MEMBASE(pPci, 1);
pScrn->fbOffset = 0;
#if XSERVER_LIBPCIACCESS
err = pci_device_map_range(pPci, pPci->regions[0].base_addr, G80_REG_SIZE,
PCI_DEV_MAP_FLAG_WRITABLE, &p);
if(err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to map MMIO registers: %s\n", strerror(err));
goto fail;
}
pNv->reg = p;
#else
pcitag = pciTag(pPci->bus, pPci->device, pPci->func);
pNv->reg = xf86MapPciMem(pScrn->scrnIndex,
VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
pcitag, pPci->memBase[0], G80_REG_SIZE);
#endif
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;
tmp = pNv->reg[0x0010020C/4];
pNv->videoRam = pNv->RamAmountKBytes = tmp >> 10 | (tmp & 1) << 22;
/* Determine the size of BAR1 */
/* Some configs have BAR1 < total RAM < 256 MB */
#if XSERVER_LIBPCIACCESS
BAR1sizeKB = pPci->regions[1].size / 1024;
#else
BAR1sizeKB = 1UL << (pPci->size[1] - 10);
#endif
if(BAR1sizeKB > 256 * 1024) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "BAR1 is > 256 MB, which is "
"probably wrong. Clamping to 256 MB.\n");
BAR1sizeKB = 256 * 1024;
}
/* Limit videoRam to the size of BAR1 */
if(pNv->videoRam <= 1024 || BAR1sizeKB == 0) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to determine the amount of "
"available video memory\n");
goto fail;
}
pNv->videoRam -= 1024;
if(pNv->videoRam > BAR1sizeKB)
pNv->videoRam = BAR1sizeKB;
pScrn->videoRam = pNv->videoRam;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Total video RAM: %.1f MB\n",
pNv->RamAmountKBytes / 1024.0);
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " BAR1 size: %.1f MB\n",
BAR1sizeKB / 1024.0);
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, " Mapped memory: %.1f MB\n",
pScrn->videoRam / 1024.0);
#if XSERVER_LIBPCIACCESS
err = pci_device_map_range(pPci, pPci->regions[1].base_addr,
pScrn->videoRam * 1024,
PCI_DEV_MAP_FLAG_WRITABLE |
PCI_DEV_MAP_FLAG_WRITE_COMBINE,
&p);
if(err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to map framebuffer: %s\n", strerror(err));
goto fail;
}
pNv->mem = p;
#else
pNv->mem = xf86MapPciMem(pScrn->scrnIndex,
VIDMEM_MMIO | VIDMEM_READSIDEEFFECT,
pcitag, pPci->memBase[1], pScrn->videoRam * 1024);
#endif
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;
xf86CrtcConfigInit(pScrn, &randr12_screen_funcs);
xf86CrtcSetSizeRange(pScrn, 320, 200, 8192, 8192);
if(!xf86LoadSubModule(pScrn, "i2c")) goto fail;
if(!xf86LoadSubModule(pScrn, "ddc")) goto fail;
xf86LoaderReqSymLists(i2cSymbols, ddcSymbols, NULL);
if(!G80DispPreInit(pScrn)) goto fail;
/* Read the DDC routing table and create outputs */
if(!G80CreateOutputs(pScrn)) goto fail;
/* Create the crtcs */
G80DispCreateCrtcs(pScrn);
/* We can grow the desktop if XAA is disabled */
if(!xf86InitialConfiguration(pScrn, pNv->NoAccel || pNv->AccelMethod == EXA)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"No valid initial configuration found\n");
goto fail;
}
pScrn->displayWidth = (pScrn->virtualX + 255) & ~255;
if(!xf86RandR12PreInit(pScrn)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "RandR initialization failure\n");
goto fail;
}
if(!pScrn->modes) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes\n");
goto fail;
}
pScrn->currentMode = pScrn->modes;
xf86PrintModes(pScrn);
xf86SetDpi(pScrn, 0, 0);
/* Load fb */
if(!xf86LoadSubModule(pScrn, "fb")) goto fail;
xf86LoaderReqSymLists(fbSymbols, NULL);
if(!pNv->NoAccel) {
switch(pNv->AccelMethod) {
case XAA:
if(!xf86LoadSubModule(pScrn, "xaa")) goto fail;
xf86LoaderReqSymLists(xaaSymbols, NULL);
break;
case EXA:
if(!xf86LoadSubModule(pScrn, "exa")) goto fail;
xf86LoaderReqSymLists(exaSymbols, NULL);
break;
}
}
/* 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)
{
if(!G80DispInit(pScrn))
return FALSE;
if(!G80CursorAcquire(pScrn))
return FALSE;
xf86SetDesiredModes(pScrn);
return TRUE;
}
/*
* Tear down the display and restore the console mode.
*/
static Bool
ReleaseDisplay(ScrnInfoPtr pScrn)
{
G80Ptr pNv = G80PTR(pScrn);
G80CursorRelease(pScrn);
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->exa) {
if(pNv->exaScreenArea) {
exaOffscreenFree(pScreen, pNv->exaScreenArea);
pNv->exaScreenArea = NULL;
}
exaDriverFini(pScrn->pScreen);
}
xf86_cursors_fini(pScreen);
if(xf86ServerIsExiting()) {
if(pNv->int10) xf86FreeInt10(pNv->int10);
#if XSERVER_LIBPCIACCESS
pci_device_unmap_range(pNv->pPci, pNv->mem, pNv->videoRam * 1024);
pci_device_unmap_range(pNv->pPci, (void*)pNv->reg, G80_REG_SIZE);
#else
xf86UnMapVidMem(pScrn->scrnIndex, pNv->mem, pNv->videoRam * 1024);
xf86UnMapVidMem(pScrn->scrnIndex, (void*)pNv->reg, G80_REG_SIZE);
#endif
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);
G80OutputResetCachedStatus(pScrnInfo);
pScreen->BlockHandler = pNv->BlockHandler;
(*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask);
pScreen->BlockHandler = G80BlockHandler;
}
static Bool
G80SaveScreen(ScreenPtr pScreen, int mode)
{
return FALSE;
}
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, i;
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);
/* 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);
pNv->reg[0x00001708/4] = 0;
for(i = 0; i < 8; i++)
pNv->reg[0x00001900/4 + i] = 0;
if(!pNv->NoAccel) {
G80InitHW(pScrn);
switch(pNv->AccelMethod) {
case XAA:
if(!G80XAAInit(pScreen)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"XAA hardware acceleration initialization failed\n");
return FALSE;
}
break;
case EXA:
if(!G80ExaInit(pScreen, pScrn)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"EXA hardware acceleration initialization failed\n");
return FALSE;
}
break;
}
}
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, xf86DPMSSet, 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;
if(!xf86CrtcScreenInit(pScreen))
return FALSE;
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 xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
}
static void
G80AdjustFrame(int scrnIndex, int x, int y, int flags)
{
}
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;
}