diff options
Diffstat (limited to 'driver/xf86-video-tdfx/src/tdfx_driver.c')
-rw-r--r-- | driver/xf86-video-tdfx/src/tdfx_driver.c | 2526 |
1 files changed, 2526 insertions, 0 deletions
diff --git a/driver/xf86-video-tdfx/src/tdfx_driver.c b/driver/xf86-video-tdfx/src/tdfx_driver.c new file mode 100644 index 000000000..b9be362cb --- /dev/null +++ b/driver/xf86-video-tdfx/src/tdfx_driver.c @@ -0,0 +1,2526 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define USE_INT10 1 +#define USE_PCIVGAIO 1 + +/************************************************************************** + +Copyright 1998-1999 Precision Insight, Inc., Cedar Park, Texas. +All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sub license, 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 (including the +next paragraph) 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 NON-INFRINGEMENT. +IN NO EVENT SHALL PRECISION INSIGHT AND/OR ITS SUPPLIERS 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. + +**************************************************************************/ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/tdfx/tdfx_driver.c,v 1.104tsi Exp $ */ + +/* + * Authors: + * Daryll Strauss <daryll@precisioninsight.com> + * + */ + +/* + * This server does not support these XFree 4.0 features yet + * DDC2 (requires I2C) + * shadowFb (if requested or acceleration is off) + * Overlay planes + */ + +/* + * These are X and server generic header files. + */ +#include "xf86.h" +#include "xf86_OSproc.h" +#include "xf86Resources.h" +#include "xf86RAC.h" +#include "vbe.h" +#include "xf86cmap.h" + +/* If the driver uses port I/O directly, it needs: */ + +#include "compiler.h" + +/* Drivers using the mi implementation of backing store need: */ + +#include "mibstore.h" + +/* All drivers using the vgahw module need this */ +/* This driver needs to be modified to not use vgaHW for multihead operation */ +#include "vgaHW.h" + +/* Drivers using the mi SW cursor need: */ + +#include "mipointer.h" + +/* Drivers using the mi colourmap code need: */ + +#include "micmap.h" + +/* Required for line biases */ +#include "miline.h" + +#include "fb.h" + +/* !!! These need to be checked !!! */ +#if 0 +#define _XF86DGA_SERVER_ +#include <X11/extensions/xf86dgastr.h> +#endif + +/* The driver's own header file: */ + +#include "tdfx.h" + +#include "regionstr.h" +#include "dixstruct.h" + +#include "xf86xv.h" +#include <X11/extensions/Xv.h> + +#ifdef XF86DRI +#include "dri.h" +#endif + +/* Required Functions: */ + +static const OptionInfoRec * TDFXAvailableOptions(int chipid, int busid); +/* Print a driver identifying message. */ +static void TDFXIdentify(int flags); + +/* Identify if there is any hardware present that I know how to drive. */ +static Bool TDFXProbe(DriverPtr drv, int flags); + +/* Process the config file and see if we have a valid configuration */ +static Bool TDFXPreInit(ScrnInfoPtr pScrn, int flags); + +/* Initialize a screen */ +static Bool TDFXScreenInit(int Index, ScreenPtr pScreen, int argc, char **argv); + +/* Enter from a virtual terminal */ +static Bool TDFXEnterVT(int scrnIndex, int flags); + +/* Leave to a virtual terminal */ +static void TDFXLeaveVT(int scrnIndex, int flags); + +/* Close down each screen we initialized */ +static Bool TDFXCloseScreen(int scrnIndex, ScreenPtr pScreen); + +/* Change screensaver state */ +static Bool TDFXSaveScreen(ScreenPtr pScreen, int mode); + +/* Cleanup server private data */ +static void TDFXFreeScreen(int scrnIndex, int flags); + +/* Check if a mode is valid on the hardware */ +static ModeStatus TDFXValidMode(int scrnIndex, DisplayModePtr mode, + Bool verbose, int flags); + +static void TDFXBlockHandler(int, pointer, pointer, pointer); + +/* Switch to various Display Power Management System levels */ +static void TDFXDisplayPowerManagementSet(ScrnInfoPtr pScrn, + int PowerManagermentMode, int flags); + +_X_EXPORT DriverRec TDFX = { + TDFX_VERSION, + TDFX_DRIVER_NAME, + TDFXIdentify, + TDFXProbe, + TDFXAvailableOptions, + NULL, + 0 +}; + +/* Chipsets */ +static SymTabRec TDFXChipsets[] = { + { PCI_CHIP_BANSHEE, "3dfx Banshee"}, + { PCI_CHIP_VOODOO3, "3dfx Voodoo3"}, + { PCI_CHIP_VOODOO5, "3dfx Voodoo5"}, + { -1, NULL } +}; + +static PciChipsets TDFXPciChipsets[] = { + { PCI_CHIP_BANSHEE, PCI_CHIP_BANSHEE, RES_SHARED_VGA }, + { PCI_CHIP_VOODOO3, PCI_CHIP_VOODOO3, RES_SHARED_VGA }, + { PCI_CHIP_VOODOO5, PCI_CHIP_VOODOO5, RES_SHARED_VGA }, + { -1, -1, RES_UNDEFINED } +}; + +/* !!! Do we want an option for alternate clocking? !!! */ + +typedef enum { + OPTION_NOACCEL, + OPTION_SW_CURSOR, + OPTION_USE_PIO, + OPTION_SHOWCACHE, + OPTION_VIDEO_KEY, + OPTION_NO_SLI, + OPTION_TEXTURED_VIDEO, + OPTION_DRI +} TDFXOpts; + +static const OptionInfoRec TDFXOptions[] = { + { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE }, + { OPTION_USE_PIO, "UsePIO", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_SHOWCACHE, "ShowCache", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_VIDEO_KEY, "VideoKey", OPTV_INTEGER, {0}, FALSE}, + { OPTION_NO_SLI, "NoSLI", OPTV_BOOLEAN, {0}, FALSE}, + { OPTION_TEXTURED_VIDEO, "TexturedVideo", OPTV_BOOLEAN, {1}, FALSE}, + { OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, FALSE}, + { -1, NULL, OPTV_NONE, {0}, FALSE} +}; + +static const char *vgahwSymbols[] = { + "vgaHWEnable", + "vgaHWFreeHWRec", + "vgaHWGetHWRec", + "vgaHWGetIOBase", + "vgaHWGetIndex", + "vgaHWInit", + "vgaHWLock", + "vgaHWMapMem", + "vgaHWProtect", + "vgaHWRestore", + "vgaHWSave", + "vgaHWSeqReset", + "vgaHWUnlock", + 0 +}; + +static const char *ramdacSymbols[] = { + "xf86CreateCursorInfoRec", + "xf86InitCursor", + NULL +}; + +static const char *ddcSymbols[] = { + "xf86PrintEDID", + "xf86SetDDCproperties", + NULL +}; + +static const char *fbSymbols[] = { + "fbPictureInit", + "fbScreenInit", + NULL +}; + +static const char *xaaSymbols[] = { + "XAACreateInfoRec", + "XAADestroyInfoRec", + "XAAInit", + "XAAReverseBitOrder", + NULL +}; + +static const char *vbeSymbols[] = { + "VBEInit", + "vbeDoEDID", + "vbeFree", + NULL +}; + +static const char *int10Symbols[] = { + "xf86FreeInt10", + "xf86InitInt10", + NULL +}; + +#ifdef XF86DRI +static const char *drmSymbols[] = { + "drmAddMap", + "drmFreeVersion", + "drmGetVersion", + NULL +}; + +static const char *driSymbols[] = { + "DRICloseScreen", + "DRICreateInfoRec", + "DRIDestroyInfoRec", + "DRIFinishScreenInit", + "DRIGetSAREAPrivate", + "DRILock", + "DRIMoveBuffersHelper", + "DRIQueryVersion", + "DRIScreenInit", + "DRIUnlock", + "GlxSetVisualConfigs", + "DRICreatePCIBusID", + NULL +}; + +#endif + +#ifdef XFree86LOADER + +static MODULESETUPPROTO(tdfxSetup); + +static XF86ModuleVersionInfo tdfxVersRec = +{ + "tdfx", + MODULEVENDORSTRING, + MODINFOSTRING1, + MODINFOSTRING2, + XORG_VERSION_CURRENT, + TDFX_MAJOR_VERSION, TDFX_MINOR_VERSION, TDFX_PATCHLEVEL, + ABI_CLASS_VIDEODRV, + ABI_VIDEODRV_VERSION, + MOD_CLASS_VIDEODRV, + {0,0,0,0} +}; + +_X_EXPORT XF86ModuleData tdfxModuleData = {&tdfxVersRec, tdfxSetup, 0}; + +static pointer +tdfxSetup(pointer module, pointer opts, int *errmaj, int *errmin) +{ + static Bool setupDone = FALSE; + + /* This module should be loaded only once, but check to be sure. */ + + if (!setupDone) { + setupDone = TRUE; + xf86AddDriver(&TDFX, module, 0); + + /* + * Modules that this driver always requires may be loaded here + * by calling LoadSubModule(). + */ + + /* + * Tell the loader about symbols from other modules that this module + * might refer to. + */ + LoaderRefSymLists(vgahwSymbols, fbSymbols, xaaSymbols, + ramdacSymbols, vbeSymbols, int10Symbols, +#ifdef XF86DRI + drmSymbols, driSymbols, +#endif + NULL); + + /* + * The return value must be non-NULL on success even though there + * is no TearDownProc. + */ + return (pointer)1; + } else { + if (errmaj) *errmaj = LDR_ONCEONLY; + return NULL; + } +} + +#endif + +/* + * TDFXGetRec and TDFXFreeRec -- + * + * Private data for the driver is stored in the screen structure. + * These two functions create and destroy that private data. + * + */ +static Bool +TDFXGetRec(ScrnInfoPtr pScrn) { + if (pScrn->driverPrivate) return TRUE; + + pScrn->driverPrivate = xnfcalloc(sizeof(TDFXRec), 1); + return TRUE; +} + +static void +TDFXFreeRec(ScrnInfoPtr pScrn) { + if (!pScrn) return; + if (!pScrn->driverPrivate) return; + xfree(pScrn->driverPrivate); + pScrn->driverPrivate=0; +} + +/* + * TDFXIdentify -- + * + * Returns the string name for the driver based on the chipset. In this + * case it will always be an TDFX, so we can return a static string. + * + */ +static void +TDFXIdentify(int flags) { + xf86PrintChipsets(TDFX_NAME, "Driver for 3dfx Banshee/Voodoo3 chipsets", TDFXChipsets); +} + +static const OptionInfoRec * +TDFXAvailableOptions(int chipid, int busid) +{ + return TDFXOptions; +} + +static void +TDFXProbeDDC(ScrnInfoPtr pScrn, int index) +{ + vbeInfoPtr pVbe; + if (xf86LoadSubModule(pScrn, "vbe")) + { + pVbe = VBEInit(NULL,index); + ConfiguredMonitor = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + } +} + +/* + * TDFXProbe -- + * + * Look through the PCI bus to find cards that are TDFX boards. + * Setup the dispatch table for the rest of the driver functions. + * + */ +static Bool +TDFXProbe(DriverPtr drv, int flags) { + int i, numUsed, numDevSections, *usedChips; + GDevPtr *devSections; + Bool foundScreen = FALSE; + + TDFXTRACE("TDFXProbe start\n"); + /* + Find the config file Device sections that match this + driver, and return if there are none. + */ + if ((numDevSections = xf86MatchDevice(TDFX_DRIVER_NAME, &devSections))<=0) { + return FALSE; + } + + /* + Since these Probing is just checking the PCI data the server already + collected. + */ + if (!xf86GetPciVideoInfo()) return FALSE; + + numUsed = xf86MatchPciInstances(TDFX_NAME, PCI_VENDOR_3DFX, + TDFXChipsets, TDFXPciChipsets, + devSections, numDevSections, + drv, &usedChips); + + xfree(devSections); + if (numUsed<=0) return FALSE; + + if (flags & PROBE_DETECT) + foundScreen = TRUE; + else for (i=0; i<numUsed; i++) { + ScrnInfoPtr pScrn; + + /* Allocate new ScrnInfoRec and claim the slot */ + pScrn = NULL; + if ((pScrn = xf86ConfigPciEntity(pScrn, 0, usedChips[i], + TDFXPciChipsets, NULL, NULL, NULL, NULL, NULL))) { + + pScrn->driverVersion = TDFX_VERSION; + pScrn->driverName = TDFX_DRIVER_NAME; + pScrn->name = TDFX_NAME; + pScrn->Probe = TDFXProbe; + pScrn->PreInit = TDFXPreInit; + pScrn->ScreenInit = TDFXScreenInit; + pScrn->SwitchMode = TDFXSwitchMode; + pScrn->AdjustFrame = TDFXAdjustFrame; + pScrn->EnterVT = TDFXEnterVT; + pScrn->LeaveVT = TDFXLeaveVT; + pScrn->FreeScreen = TDFXFreeScreen; + pScrn->ValidMode = TDFXValidMode; + foundScreen = TRUE; + } + } + xfree(usedChips); + + return foundScreen; +} + +static int +TDFXCountRam(ScrnInfoPtr pScrn) { + TDFXPtr pTDFX; + int vmemSize; + int vmemType=-1; /* SDRAM or SGRAM */ + + pTDFX = TDFXPTR(pScrn); + TDFXTRACE("TDFXCountRam start\n"); + vmemSize=0; + if (pTDFX->PIOBase[0]) { + CARD32 + partSize, /* size of SGRAM chips in Mbits */ + nChips, /* # chips of SDRAM/SGRAM */ + banks, /* Number of banks of chips */ + dramInit0_strap, + dramInit1_strap, + dramInit1, + miscInit1; + + /* determine memory type: SDRAM or SGRAM */ + vmemType = MEM_TYPE_SGRAM; + dramInit1_strap = pTDFX->readLong(pTDFX, DRAMINIT1); + dramInit1_strap &= SST_MCTL_TYPE_SDRAM; + if (dramInit1_strap) vmemType = MEM_TYPE_SDRAM; + + /* set memory interface delay values and enable refresh */ + /* these apply to all RAM vendors */ + dramInit1 = 0x0; + dramInit1 |= 2<<SST_SGRAM_OFLOP_DEL_ADJ_SHIFT; + dramInit1 |= SST_SGRAM_CLK_NODELAY; + dramInit1 |= SST_DRAM_REFRESH_EN; + dramInit1 |= (0x18 << SST_DRAM_REFRESH_VALUE_SHIFT) & SST_DRAM_REFRESH_VALUE; + dramInit1 &= ~SST_MCTL_TYPE_SDRAM; + dramInit1 |= dramInit1_strap; + + /* Some information about the timing register (for later debugging) */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "DRAMINIT1 read 0x%x, programming 0x%lx (not Banshee)\n", + pTDFX->readLong(pTDFX, DRAMINIT1), (unsigned long)dramInit1); + + /* + * Here we don't whack the timing register on the Banshee boards as the + * BIOS has done a perfectly good job. As Banshee boards were made by + * different manufacturers we don't touch this, but carry on whacking it + * for Voodoo3 and Voodoo5 boards, as we've never had a problem with them. + * I guess this could be removed for all boards as we probably shouldn't + * be doing this to the V3/V5 boards too. + */ + if (pTDFX->ChipType != PCI_CHIP_BANSHEE) + pTDFX->writeLong(pTDFX, DRAMINIT1, dramInit1); + + /* determine memory size from strapping pins (dramInit0 and dramInit1) */ + dramInit0_strap = pTDFX->readLong(pTDFX, DRAMINIT0); + + if (pTDFX->ChipType<=PCI_CHIP_VOODOO3) { /* Banshee/V3 */ + if (vmemType == MEM_TYPE_SDRAM) { + vmemSize = 16; + } else { + nChips = ((dramInit0_strap & SST_SGRAM_NUM_CHIPSETS) == 0) ? 4 : 8; + + if ( (dramInit0_strap & SST_SGRAM_TYPE) == SST_SGRAM_TYPE_8MBIT ) { + partSize = 8; + } else if ( (dramInit0_strap & SST_SGRAM_TYPE) == SST_SGRAM_TYPE_16MBIT) { + partSize = 16; + } else { + ErrorF("Invalid sgram type = 0x%lx", + (dramInit0_strap & SST_SGRAM_TYPE) << SST_SGRAM_TYPE_SHIFT ); + return 0; + } + vmemSize = (nChips * partSize) / 8; /* in MBytes */ + } + } else { /* V4, V5 */ + nChips = ((dramInit0_strap & SST_SGRAM_NUM_CHIPSETS)==0) ? 4 : 8; + partSize=1<<((dramInit0_strap&0x38000000)>>28); + banks=((dramInit0_strap&BIT(30))==0) ? 2 : 4; + vmemSize=nChips*partSize*banks; + } + TDFXTRACEREG("dramInit0 = %lx dramInit1 = %lx\n", + (unsigned long)dramInit0_strap, (unsigned long)dramInit1_strap); + TDFXTRACEREG("MemConfig %d chips %ld size %ld total\n", (int)nChips, + (unsigned long)partSize, (unsigned long)vmemSize); + + /* + disable block writes for SDRAM + */ + miscInit1 = pTDFX->readLong(pTDFX, MISCINIT1); + if ( vmemType == MEM_TYPE_SDRAM ) { + miscInit1 |= SST_DISABLE_2D_BLOCK_WRITE; + } + miscInit1|=1; + pTDFX->writeLong(pTDFX, MISCINIT1, miscInit1); + } + + /* return # of KBytes of board memory */ + return vmemSize*1024; +} + +#if 0 +static int TDFXCfgToSize(int cfg) +{ + if (cfg<4) return 0x8000000<<cfg; + return 0x4000000>>(cfg-4); +} +#endif + +static int TDFXSizeToCfg(int size) +{ + switch (size) { + case 0x40000000: return 3; + case 0x20000000: return 2; + case 0x10000000: return 1; + case 0x08000000: return 0; + case 0x04000000: return 4; + case 0x02000000: return 5; + case 0x01000000: return 6; + case 0x00800000: return 7; + case 0x00400000: return 8; + default: + return -1; + } +} + +static void +TDFXFindChips(ScrnInfoPtr pScrn, pciVideoPtr match) +{ + TDFXPtr pTDFX; + pciVideoPtr *ppPci; + + pTDFX=TDFXPTR(pScrn); + pTDFX->numChips=0; + pTDFX->ChipType=match->chipType; + for (ppPci = xf86GetPciVideoInfo(); *ppPci != NULL; ppPci++) { + if ((*ppPci)->bus == match->bus && + (*ppPci)->device == match->device) { + pTDFX->PciTag[pTDFX->numChips] = pciTag((*ppPci)->bus, + (*ppPci)->device, + (*ppPci)->func); + pTDFX->PIOBase[pTDFX->numChips] = + pScrn->domainIOBase + ((*ppPci)->ioBase[2] & 0xFFFFFFFCU); + pTDFX->numChips++; + } + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXFindChips: found %d chip(s)\n", pTDFX->numChips); + /* Disable the secondary chips for now */ + pTDFX->numChips=1; +} + +static void +TDFXInitChips(ScrnInfoPtr pScrn) +{ + TDFXPtr pTDFX; + int i; +#if 0 + int v; +#endif + unsigned long cfgbits, initbits; + unsigned long mem0base, mem1base, mem0size, mem0bits, mem1size, mem1bits; + + pTDFX=TDFXPTR(pScrn); + cfgbits=pciReadLong(pTDFX->PciTag[0], CFG_PCI_DECODE); + mem0base=pciReadLong(pTDFX->PciTag[0], CFG_MEM0BASE); + mem1base=pciReadLong(pTDFX->PciTag[0], CFG_MEM1BASE); + initbits=pciReadLong(pTDFX->PciTag[0], CFG_INIT_ENABLE); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: numchips = %d\n", pTDFX->numChips); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: cfgbits = 0x%08lx, initbits = 0x%08lx\n", + cfgbits, initbits); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: mem0base = 0x%08lx, mem1base = 0x%08lx\n", + mem0base, mem1base); + mem0size=32*1024*1024; /* Registers are always 32MB */ + mem1size=pScrn->videoRam*1024*2; /* Linear mapping is 2x memory */ + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: mem0size = 0x%08lx, mem1size = 0x%08lx\n", + mem0size, mem1size); + mem0bits=TDFXSizeToCfg(mem0size); + mem1bits=TDFXSizeToCfg(mem1size)<<4; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: mem0bits = 0x%08lx, mem1bits = 0x%08lx\n", + mem0bits, mem1bits); + cfgbits=(cfgbits&~(0xFF))|mem0bits|mem1bits; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: cfgbits = 0x%08lx\n", cfgbits); + for (i=0; i<pTDFX->numChips; i++) { + initbits|=BIT(10); + pciWriteLong(pTDFX->PciTag[i], CFG_INIT_ENABLE, initbits); +#if 0 + v=pciReadWord(pTDFX->PciTag[i], CFG_PCI_COMMAND); + if (!i) + pciWriteWord(pTDFX->PciTag[i], CFG_PCI_COMMAND, v|0x3); + else + pciWriteWord(pTDFX->PciTag[i], CFG_PCI_COMMAND, v|0x2); +#endif + pTDFX->MMIOAddr[i]=mem0base+i*mem0size; + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: MMIOAddr[%d] = 0x%08lx\n", + i, pTDFX->MMIOAddr[i]); + pciWriteLong(pTDFX->PciTag[i], CFG_MEM0BASE, pTDFX->MMIOAddr[i]); + pTDFX->MMIOAddr[i]&=0xFFFFFF00; + pTDFX->LinearAddr[i]=mem1base+i*mem1size; + pciWriteLong(pTDFX->PciTag[i], CFG_MEM1BASE, pTDFX->LinearAddr[i]); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 3, + "TDFXInitChips: LinearAddr[%d] = 0x%08lx\n", + i, pTDFX->LinearAddr[i]); + pTDFX->LinearAddr[i]&=0xFFFFFF00; + pciWriteLong(pTDFX->PciTag[i], CFG_PCI_DECODE, cfgbits); + initbits&=~BIT(10); + pciWriteLong(pTDFX->PciTag[i], CFG_INIT_ENABLE, initbits); + } +} + +/* + * TDFXPreInit -- + * + * Do initial setup of the board before we know what resolution we will + * be running at. + * + */ +static Bool +TDFXPreInit(ScrnInfoPtr pScrn, int flags) +{ + TDFXPtr pTDFX; + ClockRangePtr clockRanges; + int i; + MessageType from; + int flags24; + rgb defaultWeight = {0, 0, 0}; + pciVideoPtr match; + int availableMem; + + TDFXTRACE("TDFXPreInit start\n"); + if (pScrn->numEntities != 1) return FALSE; + + /* Allocate driverPrivate */ + if (!TDFXGetRec(pScrn)) { + return FALSE; + } + + pTDFX = TDFXPTR(pScrn); + + pTDFX->initDone=FALSE; + pTDFX->pEnt = xf86GetEntityInfo(pScrn->entityList[0]); + + if (flags & PROBE_DETECT) { +#if !defined(__powerpc__) + TDFXProbeDDC(pScrn, pTDFX->pEnt->index); + return TRUE; +#else + return FALSE; +#endif + } + + if (pTDFX->pEnt->location.type != BUS_PCI) return FALSE; + + /* The vgahw module should be loaded here when needed */ + if (!xf86LoadSubModule(pScrn, "vgahw")) return FALSE; + + xf86LoaderReqSymLists(vgahwSymbols, NULL); + + /* Allocate a vgaHWRec */ + if (!vgaHWGetHWRec(pScrn)) return FALSE; + +#if USE_INT10 +#if !defined(__powerpc__) + if (xf86LoadSubModule(pScrn, "int10")) { + xf86Int10InfoPtr pInt; + + xf86LoaderReqSymLists(int10Symbols, NULL); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Softbooting the board (through the int10 interface).\n"); + pInt = xf86InitInt10(pTDFX->pEnt->index); + if (!pInt) + { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "Softbooting the board failed.\n"); + } + else + { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Softbooting the board succeeded.\n"); + xf86FreeInt10(pInt); + } + } +#endif +#endif + + match=pTDFX->PciInfo=xf86GetPciInfoForEntity(pTDFX->pEnt->index); + TDFXFindChips(pScrn, match); + pTDFX->Primary = xf86IsPrimaryPci(pTDFX->PciInfo); + + if (xf86RegisterResources(pTDFX->pEnt->index, NULL, ResExclusive)) { + TDFXFreeRec(pScrn); + return FALSE; + } + /* + * We don't need VGA resources during OPERATING state. However I'm + * not sure if they are disabled. + */ + xf86SetOperatingState(resVgaIo, pTDFX->pEnt->index, ResDisableOpr); + + /* Is VGA memory disabled during OPERATING state? */ + xf86SetOperatingState(resVgaMem, pTDFX->pEnt->index, ResUnusedOpr); + /* + * I'm sure we don't need to set these. All resources + * for these operations are exclusive. + */ + if (pTDFX->usePIO) { + pScrn->racMemFlags = 0; + pScrn->racIoFlags = RAC_FB | RAC_COLORMAP | RAC_CURSOR | RAC_VIEWPORT; + } else + pScrn->racMemFlags = 0; + + /* Set pScrn->monitor */ + pScrn->monitor = pScrn->confScreen->monitor; + + flags24=Support24bppFb | Support32bppFb | SupportConvert32to24; + if (!xf86SetDepthBpp(pScrn, 0, 0, 0, flags24)) { + return FALSE; + } else { + switch (pScrn->depth) { + case 8: + case 16: + case 24: + break; + default: + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Given depth (%d) is not supported by tdfx driver\n", + pScrn->depth); + return FALSE; + } + } + xf86PrintDepthBpp(pScrn); + + pScrn->rgbBits=8; + if (pScrn->depth>8) { + if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight)) + return FALSE; + } + + if (!xf86SetDefaultVisual(pScrn, -1)) { + return FALSE; + } else { + /* We don't currently support DirectColor at > 8bpp */ + if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual" + " (%s) is not supported at depth %d\n", + xf86GetVisualName(pScrn->defaultVisual), pScrn->depth); + return FALSE; + } + } + + /* We use a programmable clock */ + pScrn->progClock = TRUE; + + pTDFX->cpp = pScrn->bitsPerPixel/8; + + /* Process the options */ + xf86CollectOptions(pScrn, NULL); + if (!(pTDFX->Options = xalloc(sizeof(TDFXOptions)))) + return FALSE; + memcpy(pTDFX->Options, TDFXOptions, sizeof(TDFXOptions)); + xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, pTDFX->Options); + + /* + * Set the Chipset and ChipRev, allowing config file entries to + * override. + */ + if (pTDFX->pEnt->device->chipset && *pTDFX->pEnt->device->chipset) { + pScrn->chipset = pTDFX->pEnt->device->chipset; + from = X_CONFIG; + } else if (pTDFX->pEnt->device->chipID >= 0) { + pScrn->chipset = (char *)xf86TokenToString(TDFXChipsets, pTDFX->pEnt->device->chipID); + from = X_CONFIG; + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n", + pTDFX->pEnt->device->chipID); + } else { + from = X_PROBED; + pScrn->chipset = (char *)xf86TokenToString(TDFXChipsets, match->chipType); + } + if (pTDFX->pEnt->device->chipRev >= 0) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n", + pTDFX->pEnt->device->chipRev); + } + + xf86DrvMsg(pScrn->scrnIndex, from, "Chipset: \"%s\"\n", pScrn->chipset); + + if (pTDFX->pEnt->device->MemBase != 0) { + pTDFX->LinearAddr[0] = pTDFX->pEnt->device->MemBase; + from = X_CONFIG; + } else { + if (match->memBase[1] != 0) { + pTDFX->LinearAddr[0] = match->memBase[1]; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid FB address in PCI config space\n"); + TDFXFreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "Linear framebuffer at 0x%lX\n", + (unsigned long)pTDFX->LinearAddr[0]); + + if (pTDFX->pEnt->device->IOBase != 0) { + pTDFX->MMIOAddr[0] = pTDFX->pEnt->device->IOBase; + from = X_CONFIG; + } else { + if (match->memBase[0]) { + pTDFX->MMIOAddr[0] = match->memBase[0]; + from = X_PROBED; + } else { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid MMIO address in PCI config space\n"); + TDFXFreeRec(pScrn); + return FALSE; + } + } + xf86DrvMsg(pScrn->scrnIndex, from, "MMIO registers at addr 0x%lX\n", + (unsigned long)pTDFX->MMIOAddr[0]); + + if (!match->ioBase[2]) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "No valid PIO address in PCI config space\n"); + TDFXFreeRec(pScrn); + return FALSE; + } + xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "PIO registers at addr 0x%lX\n", + (unsigned long)pTDFX->PIOBase[0]); + + /* We have to use PIO to probe, because we haven't mappend yet */ + TDFXSetPIOAccess(pTDFX); + + /* Calculate memory */ + pScrn->videoRam = TDFXCountRam(pScrn); + from = X_PROBED; + if (pTDFX->pEnt->device->videoRam) { + pScrn->videoRam = pTDFX->pEnt->device->videoRam; + from = X_CONFIG; + } + + TDFXInitChips(pScrn); + + /* Multiple by two because tiled access requires more address space */ + pTDFX->FbMapSize = pScrn->videoRam*1024*2; + xf86DrvMsg(pScrn->scrnIndex, from, "VideoRAM: %d kByte Mapping %ld kByte\n", + pScrn->videoRam, pTDFX->FbMapSize/1024); + + /* Since we can do gamma correction, we call xf86SetGamma */ + { + Gamma zeros = {0.0, 0.0, 0.0}; + + if (!xf86SetGamma(pScrn, zeros)) { + return FALSE; + } + } + + pTDFX->MaxClock = 0; + if (pTDFX->pEnt->device->dacSpeeds[0]) { + switch (pScrn->bitsPerPixel) { + case 8: + pTDFX->MaxClock = pTDFX->pEnt->device->dacSpeeds[DAC_BPP8]; + break; + case 16: + pTDFX->MaxClock = pTDFX->pEnt->device->dacSpeeds[DAC_BPP16]; + break; + case 24: + pTDFX->MaxClock = pTDFX->pEnt->device->dacSpeeds[DAC_BPP24]; + break; + case 32: + pTDFX->MaxClock = pTDFX->pEnt->device->dacSpeeds[DAC_BPP32]; + break; + } + if (!pTDFX->MaxClock) + pTDFX->MaxClock = pTDFX->pEnt->device->dacSpeeds[0]; + from = X_CONFIG; + } else { + switch (pTDFX->ChipType) { + case PCI_CHIP_BANSHEE: + pTDFX->MaxClock = 270000; + break; + case PCI_CHIP_VOODOO3: + switch(match->subsysCard) { + case PCI_CARD_VOODOO3_2000: + pTDFX->MaxClock = 300000; + break; + case PCI_CARD_VOODOO3_3000: + pTDFX->MaxClock = 350000; + break; + default: + pTDFX->MaxClock = 300000; + break; + } + break; + case PCI_CHIP_VOODOO5: + pTDFX->MaxClock = 350000; + break; + } + } + clockRanges = xnfcalloc(sizeof(ClockRange), 1); + clockRanges->next=NULL; + clockRanges->minClock= 12000; /* !!! What's the min clock? !!! */ + clockRanges->maxClock=pTDFX->MaxClock; + clockRanges->clockIndex = -1; + switch (pTDFX->ChipType) { + case PCI_CHIP_BANSHEE: + clockRanges->interlaceAllowed = FALSE; + break; + case PCI_CHIP_VOODOO3: + case PCI_CHIP_VOODOO5: + clockRanges->interlaceAllowed = TRUE; + break; + default: + clockRanges->interlaceAllowed = FALSE; + break; + } + clockRanges->doubleScanAllowed = TRUE; + + /* + * Max memory available for the framebuffer is the total less the + * HW cursor space and FIFO space. + */ + availableMem = pScrn->videoRam - 4096 - + (((255 <= CMDFIFO_PAGES) ? 255 : CMDFIFO_PAGES) << 12); + + i = xf86ValidateModes(pScrn, pScrn->monitor->Modes, + pScrn->display->modes, clockRanges, + 0, 320, 2048, 16*pScrn->bitsPerPixel, + 200, 2047, + pScrn->display->virtualX, pScrn->display->virtualY, + availableMem, LOOKUP_BEST_REFRESH); + + if (i==-1) { + TDFXFreeRec(pScrn); + return FALSE; + } + + xf86PruneDriverModes(pScrn); + + if (!i || !pScrn->modes) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n"); + TDFXFreeRec(pScrn); + return FALSE; + } + + xf86SetCrtcForModes(pScrn, 0); + + pScrn->currentMode = pScrn->modes; + + xf86PrintModes(pScrn); + + xf86SetDpi(pScrn, 0, 0); + + if (!xf86LoadSubModule(pScrn, "fb")) { + TDFXFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(fbSymbols, NULL); + + if (!xf86ReturnOptValBool(pTDFX->Options, OPTION_NOACCEL, FALSE)) { + if (!xf86LoadSubModule(pScrn, "xaa")) { + TDFXFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(xaaSymbols, NULL); + } + + if (!xf86GetOptValBool(pTDFX->Options, OPTION_SHOWCACHE, &(pTDFX->ShowCache))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShowCache %s\n", pTDFX->ShowCache ? "Enabled" : "Disabled"); + } else { + pTDFX->ShowCache = FALSE; + } + + if (xf86GetOptValBool(pTDFX->Options, OPTION_TEXTURED_VIDEO, &(pTDFX->TextureXvideo))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Texture Xvideo Adaptor %s\n", pTDFX->TextureXvideo ? "Enabled" : "Disabled"); + } else { + pTDFX->TextureXvideo = FALSE; + } + + if (xf86GetOptValInteger(pTDFX->Options, OPTION_VIDEO_KEY, &(pTDFX->videoKey))) { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n", pTDFX->videoKey); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key default 0x%x\n", pTDFX->videoKey = 0x1E); + } + + if (!xf86ReturnOptValBool(pTDFX->Options, OPTION_SW_CURSOR, FALSE)) { + if (!xf86LoadSubModule(pScrn, "ramdac")) { + TDFXFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ramdacSymbols, NULL); + } + +#if USE_INT10 +#if !defined(__powerpc__) + /* Load DDC if needed */ + /* This gives us DDC1 - we should be able to get DDC2B using i2c */ + if (!xf86LoadSubModule(pScrn, "ddc")) { + TDFXFreeRec(pScrn); + return FALSE; + } + xf86LoaderReqSymLists(ddcSymbols, NULL); + + /* Initialize DDC1 if possible */ + if (xf86LoadSubModule(pScrn, "vbe")) { + xf86MonPtr pMon; + vbeInfoPtr pVbe = VBEInit(NULL,pTDFX->pEnt->index); + + xf86LoaderReqSymLists(vbeSymbols, NULL); + pMon = vbeDoEDID(pVbe, NULL); + vbeFree(pVbe); + xf86SetDDCproperties(pScrn,xf86PrintEDID(pMon)); + } +#endif +#endif + + if (xf86ReturnOptValBool(pTDFX->Options, OPTION_USE_PIO, FALSE)) { + pTDFX->usePIO=TRUE; + } + +#if X_BYTE_ORDER == X_BIG_ENDIAN + pTDFX->ModeReg.miscinit0 = pTDFX->readLong(pTDFX, MISCINIT0); + pTDFX->SavedReg.miscinit0 = pTDFX->ModeReg.miscinit0; + + switch (pScrn->bitsPerPixel) { + case 8: + pTDFX->writeFifo = TDFXWriteFifo_8; + pTDFX->ModeReg.miscinit0 &= ~BIT(30); /* LFB byte swizzle */ + pTDFX->ModeReg.miscinit0 &= ~BIT(31); /* LFB word swizzle */ + break; + case 15: + case 16: + pTDFX->writeFifo = TDFXWriteFifo_16; + pTDFX->ModeReg.miscinit0 |= BIT(30); /* LFB byte swizzle */ + pTDFX->ModeReg.miscinit0 |= BIT(31); /* LFB word swizzle */ + break; + case 24: + case 32: + pTDFX->writeFifo = TDFXWriteFifo_24; + pTDFX->ModeReg.miscinit0 |= BIT(30); /* LFB byte swizzle */ + pTDFX->ModeReg.miscinit0 &= ~BIT(31); /* LFB word swizzle */ + break; + default: + return FALSE; + break; + } + pTDFX->writeLong(pTDFX, MISCINIT0, pTDFX->ModeReg.miscinit0); +#endif + +#ifdef XF86DRI + /* Load the dri module if requested. */ + if (xf86ReturnOptValBool(pTDFX->Options, OPTION_DRI, FALSE)) { + if (xf86LoadSubModule(pScrn, "dri")) { + xf86LoaderReqSymLists(driSymbols, drmSymbols, NULL); + } + } +#endif + return TRUE; +} + +static Bool +TDFXMapMem(ScrnInfoPtr pScrn) +{ + int mmioFlags, i; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXMapMem start\n"); + pTDFX = TDFXPTR(pScrn); + + mmioFlags = VIDMEM_MMIO | VIDMEM_READSIDEEFFECT; + + for (i=0; i<pTDFX->numChips; i++) { + pTDFX->MMIOBase[i] = xf86MapPciMem(pScrn->scrnIndex, mmioFlags, + pTDFX->PciTag[i], + pTDFX->MMIOAddr[i], + TDFXIOMAPSIZE); + + if (!pTDFX->MMIOBase[i]) return FALSE; + } + + pTDFX->FbBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER, + pTDFX->PciTag[0], + pTDFX->LinearAddr[0], + pTDFX->FbMapSize); + if (!pTDFX->FbBase) return FALSE; + + return TRUE; +} + +static Bool +TDFXUnmapMem(ScrnInfoPtr pScrn) +{ + TDFXPtr pTDFX; + int i; + + TDFXTRACE("TDFXUnmapMem start\n"); + pTDFX = TDFXPTR(pScrn); + + for (i=0; i<pTDFX->numChips; i++) { + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pTDFX->MMIOBase[i], + TDFXIOMAPSIZE); + pTDFX->MMIOBase[i]=0; + } + + xf86UnMapVidMem(pScrn->scrnIndex, (pointer)pTDFX->FbBase, pTDFX->FbMapSize); + pTDFX->FbBase = 0; + return TRUE; +} + +static void +PrintRegisters(ScrnInfoPtr pScrn, TDFXRegPtr regs) +{ +#ifdef TRACE + int i; + TDFXPtr pTDFX; + vgaHWPtr pHW = VGAHWPTR(pScrn); + vgaRegPtr pVga = &VGAHWPTR(pScrn)->ModeReg; + + + pTDFX = TDFXPTR(pScrn); +#if 1 + ErrorF("VGA Registers\n"); + ErrorF("MiscOutReg = %x versus %x\n", pHW->readMiscOut(pHW), pVga->MiscOutReg); + ErrorF("EnableReg = %x\n", pHW->readEnable(pHW)); + for (i=0; i<25; i++) { + int x; + x = pHW->readCrtc(pHW, i); + ErrorF("CRTC[%d]=%d versus %d\n", i, x, pVga->CRTC[i]); + } + for (i=0; i<21; i++) { + ErrorF("Attribute[%d]=%d versus %d\n", i, pHW->readAttr(pHW, i), pVga->Attribute[i]); + } + for (i=0; i<9; i++) { + ErrorF("Graphics[%d]=%d versus %d\n", i, pHW->readGr(pHW, i), pVga->Graphics[i]); + } + for (i=0; i<5; i++) { + ErrorF("Sequencer[%d]=%d versus %d\n", i, pHW->readSeq(pHW, i), pVga->Sequencer[i]); + } +#endif +#if 1 + ErrorF("Banshee Registers\n"); + ErrorF("VidCfg = %x versus %x\n", pTDFX->readLong(pTDFX, VIDPROCCFG), regs->vidcfg); + ErrorF("DACmode = %x versus %x\n", pTDFX->readLong(pTDFX, DACMODE), regs->dacmode); + ErrorF("Vgainit0 = %x versus %x\n", pTDFX->readLong(pTDFX, VGAINIT0), regs->vgainit0); + ErrorF("Vgainit1 = %x versus %x\n", pTDFX->readLong(pTDFX, VGAINIT1), regs->vgainit1); + ErrorF("Miscinit0 = %x versus %x\n", pTDFX->readLong(pTDFX, MISCINIT0), regs->miscinit0); + ErrorF("Miscinit1 = %x versus %x\n", pTDFX->readLong(pTDFX, MISCINIT1), regs->miscinit1); + ErrorF("DramInit0 = %x\n", pTDFX->readLong(pTDFX, DRAMINIT0)); + ErrorF("DramInit1 = %x\n", pTDFX->readLong(pTDFX, DRAMINIT1)); + ErrorF("VidPLL = %x versus %x\n", pTDFX->readLong(pTDFX, PLLCTRL0), regs->vidpll); + ErrorF("screensize = %x versus %x\n", pTDFX->readLong(pTDFX, VIDSCREENSIZE), regs->screensize); + ErrorF("stride = %x versus %x\n", pTDFX->readLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE), regs->stride); + ErrorF("startaddr = %x versus %x\n", pTDFX->readLong(pTDFX, VIDDESKTOPSTARTADDR), regs->startaddr); + ErrorF("Input Status 0 = %x\n", pTDFX->readLong(pTDFX, 0xc2)); + ErrorF("Input Status 1 = %x\n", pTDFX->readLong(pTDFX, 0xda)); + ErrorF("2D Status = %x\n", pTDFX->readLong(pTDFX, SST_2D_OFFSET)); + ErrorF("3D Status = %x\n", pTDFX->readLong(pTDFX, SST_3D_OFFSET)); +#endif +#endif +} + +/* + * TDFXSave -- + * + * This function saves the video state. It reads all of the SVGA registers + * into the vgaTDFXRec data structure. There is in general no need to + * mask out bits here - just read the registers. + */ +static void +DoSave(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, TDFXRegPtr tdfxReg, Bool saveFonts) +{ + TDFXPtr pTDFX; + vgaHWPtr hwp; + int i, dummy, count; + + TDFXTRACE("TDFXDoSave start\n"); + pTDFX = TDFXPTR(pScrn); + hwp = VGAHWPTR(pScrn); + + /* + * This function will handle creating the data structure and filling + * in the generic VGA portion. + */ + if (saveFonts && pTDFX->Primary) { + /* Enable legacy VGA to access font memory. */ + dummy = pTDFX->readLong(pTDFX, VGAINIT0); + pTDFX->writeLong(pTDFX, VGAINIT0, dummy & ~SST_VGA0_LEGACY_DECODE); + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE|VGA_SR_FONTS); + pTDFX->writeLong(pTDFX, VGAINIT0, dummy); + } else + vgaHWSave(pScrn, vgaReg, VGA_SR_MODE); + + tdfxReg->ExtVga[0] = hwp->readCrtc(hwp, 0x1a); + tdfxReg->ExtVga[1] = hwp->readCrtc(hwp, 0x1b); + tdfxReg->miscinit1=pTDFX->readLong(pTDFX, MISCINIT1); + tdfxReg->vidcfg=pTDFX->readLong(pTDFX, VIDPROCCFG); + tdfxReg->vidpll=pTDFX->readLong(pTDFX, PLLCTRL0); + tdfxReg->dacmode=pTDFX->readLong(pTDFX, DACMODE); + tdfxReg->screensize=pTDFX->readLong(pTDFX, VIDSCREENSIZE); + tdfxReg->stride=pTDFX->readLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE); + tdfxReg->cursloc=pTDFX->readLong(pTDFX, HWCURPATADDR); + tdfxReg->startaddr=pTDFX->readLong(pTDFX, VIDDESKTOPSTARTADDR); + tdfxReg->clip0min=TDFXReadLongMMIO(pTDFX, SST_2D_CLIP0MIN); + tdfxReg->clip0max=TDFXReadLongMMIO(pTDFX, SST_2D_CLIP0MAX); + tdfxReg->clip1min=TDFXReadLongMMIO(pTDFX, SST_2D_CLIP1MIN); + tdfxReg->clip1max=TDFXReadLongMMIO(pTDFX, SST_2D_CLIP1MAX); + tdfxReg->srcbaseaddr=TDFXReadLongMMIO(pTDFX, SST_2D_SRCBASEADDR); + tdfxReg->dstbaseaddr=TDFXReadLongMMIO(pTDFX, SST_2D_DSTBASEADDR); + for (i=0; i<512; i++) { + count=0; + do { + TDFXWriteLongMMIO(pTDFX, DACADDR, i); + dummy=TDFXReadLongMMIO(pTDFX, DACADDR); + } while (count++<100 && dummy!=i); + tdfxReg->dactable[i]=TDFXReadLongMMIO(pTDFX, DACDATA); + } + PrintRegisters(pScrn, tdfxReg); +} + +static void +TDFXSave(ScrnInfoPtr pScrn) +{ + vgaHWPtr hwp; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXSave start\n"); + hwp = VGAHWPTR(pScrn); + pTDFX = TDFXPTR(pScrn); + /* Make sure VGA functionality is enabled */ + pTDFX->SavedReg.vgainit0=pTDFX->readLong(pTDFX, VGAINIT0); +#if 0 + pTDFX->SavedReg.vgainit1=pTDFX->readLong(pTDFX, VGAINIT1); +#endif + pTDFX->writeLong(pTDFX, VGAINIT0, pTDFX->ModeReg.vgainit0); +#if 0 + pTDFX->writeLong(pTDFX, VGAINIT1, pTDFX->ModeReg.vgainit1); +#endif + vgaHWEnable(hwp); + + DoSave(pScrn, &hwp->SavedReg, &pTDFX->SavedReg, TRUE); +} + +static void +DoRestore(ScrnInfoPtr pScrn, vgaRegPtr vgaReg, TDFXRegPtr tdfxReg, + Bool restoreFonts) { + TDFXPtr pTDFX; + vgaHWPtr hwp; + int i, dummy, count; + + TDFXTRACE("TDFXDoRestore start\n"); + pTDFX = TDFXPTR(pScrn); + hwp = VGAHWPTR(pScrn); + + pTDFX->sync(pScrn); + + vgaHWProtect(pScrn, TRUE); + + if (restoreFonts && pTDFX->Primary) { + /* Enable legacy VGA to access font memory. */ + dummy = pTDFX->readLong(pTDFX, VGAINIT0); + pTDFX->writeLong(pTDFX, VGAINIT0, dummy & ~SST_VGA0_LEGACY_DECODE); + vgaHWRestore(pScrn, vgaReg, VGA_SR_FONTS|VGA_SR_MODE); + pTDFX->writeLong(pTDFX, VGAINIT0, dummy); + } else + vgaHWRestore(pScrn, vgaReg, VGA_SR_MODE); + + hwp->writeCrtc(hwp, 0x1a, tdfxReg->ExtVga[0]); + hwp->writeCrtc(hwp, 0x1b, tdfxReg->ExtVga[1]); + pTDFX->writeLong(pTDFX, PLLCTRL0, tdfxReg->vidpll); + pTDFX->writeLong(pTDFX, DACMODE, tdfxReg->dacmode); + pTDFX->writeLong(pTDFX, VIDDESKTOPOVERLAYSTRIDE, tdfxReg->stride); + pTDFX->writeLong(pTDFX, HWCURPATADDR, tdfxReg->cursloc); + pTDFX->writeLong(pTDFX, VIDSCREENSIZE, tdfxReg->screensize); + pTDFX->writeLong(pTDFX, VIDDESKTOPSTARTADDR, tdfxReg->startaddr); + TDFXWriteLongMMIO(pTDFX, SST_2D_CLIP0MIN, tdfxReg->clip0min); + TDFXWriteLongMMIO(pTDFX, SST_2D_CLIP0MAX, tdfxReg->clip0max); + TDFXWriteLongMMIO(pTDFX, SST_2D_CLIP1MIN, tdfxReg->clip1min); + TDFXWriteLongMMIO(pTDFX, SST_2D_CLIP1MAX, tdfxReg->clip1max); +#if X_BYTE_ORDER == X_BIG_ENDIAN + pTDFX->writeLong(pTDFX, MISCINIT0, tdfxReg->miscinit0); +#endif + pTDFX->writeLong(pTDFX, VIDPROCCFG, tdfxReg->vidcfg); + TDFXWriteLongMMIO(pTDFX, SST_2D_SRCBASEADDR, tdfxReg->srcbaseaddr); + TDFXWriteLongMMIO(pTDFX, SST_2D_DSTBASEADDR, tdfxReg->dstbaseaddr); + for (i=0; i<512; i++) { + count=0; + do { + TDFXWriteLongMMIO(pTDFX, DACADDR, i); + dummy=TDFXReadLongMMIO(pTDFX, DACADDR); + } while (count++<100 && dummy!=i); + count=0; + do { + TDFXWriteLongMMIO(pTDFX, DACDATA, tdfxReg->dactable[i]); + dummy=TDFXReadLongMMIO(pTDFX, DACDATA); + } while (count++<100 && dummy!=tdfxReg->dactable[i]); + } + pTDFX->writeLong(pTDFX, VGAINIT0, tdfxReg->vgainit0); +#if 0 + pTDFX->writeLong(pTDFX, VGAINIT1, tdfxReg->vgainit1); + pTDFX->writeLong(pTDFX, MISCINIT1, tdfxReg->miscinit1); +#endif + vgaHWProtect(pScrn, FALSE); + + pTDFX->sync(pScrn); + PrintRegisters(pScrn, tdfxReg); +} + +static void +TDFXRestore(ScrnInfoPtr pScrn) { + vgaHWPtr hwp; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXRestore start\n"); + hwp = VGAHWPTR(pScrn); + pTDFX = TDFXPTR(pScrn); + + DoRestore(pScrn, &hwp->SavedReg, &pTDFX->SavedReg, TRUE); +} + +#define REFFREQ 14318.18 + +static int +CalcPLL(int freq, int *f_out, int isBanshee) { + int m, n, k, best_m, best_n, best_k, f_cur, best_error; + int minm, maxm; + + TDFXTRACE("CalcPLL start\n"); + best_error=freq; + best_n=best_m=best_k=0; + if (isBanshee) { + minm=24; + maxm=24; + } else { + minm=1; + maxm=57; /* This used to be 64, alas it seems the last 8 (funny that ?) + * values cause jittering at lower resolutions. I've not done + * any calculations to what the adjustment affects clock ranges, + * but I can still run at 1600x1200@75Hz */ + } + for (n=1; n<256; n++) { + f_cur=REFFREQ*(n+2); + if (f_cur<freq) { + f_cur=f_cur/3; + if (freq-f_cur<best_error) { + best_error=freq-f_cur; + best_n=n; + best_m=1; + best_k=0; + continue; + } + } + for (m=minm; m<maxm; m++) { + for (k=0; k<4; k++) { + f_cur=REFFREQ*(n+2)/(m+2)/(1<<k); + if (abs(f_cur-freq)<best_error) { + best_error=abs(f_cur-freq); + best_n=n; + best_m=m; + best_k=k; + } + } + } + } + n=best_n; + m=best_m; + k=best_k; + *f_out=REFFREQ*(n+2)/(m+2)/(1<<k); + return (n<<8)|(m<<2)|k; +} + +static Bool +SetupVidPLL(ScrnInfoPtr pScrn, DisplayModePtr mode) { + TDFXPtr pTDFX; + TDFXRegPtr tdfxReg; + int freq, f_out; + + TDFXTRACE("SetupVidPLL start\n"); + pTDFX = TDFXPTR(pScrn); + tdfxReg = &pTDFX->ModeReg; + freq=mode->Clock; + tdfxReg->dacmode&=~SST_DAC_MODE_2X; + tdfxReg->vidcfg&=~SST_VIDEO_2X_MODE_EN; + if (freq>TDFX2XCUTOFF) { + if (freq>pTDFX->MaxClock) { + ErrorF("Overclocked PLLs\n"); + freq=pTDFX->MaxClock; + } + tdfxReg->dacmode|=SST_DAC_MODE_2X; + tdfxReg->vidcfg|=SST_VIDEO_2X_MODE_EN; + } + tdfxReg->vidpll=CalcPLL(freq, &f_out, 0); + TDFXTRACEREG("Vid PLL freq=%d f_out=%d reg=%x\n", freq, f_out, + tdfxReg->vidpll); + return TRUE; +} + +#if 0 +static Bool +SetupMemPLL(int freq) { + TDFXPtr pTDFX; + vgaTDFXPtr tdfxReg; + int f_out; + + TDFXTRACE("SetupMemPLL start\n"); + pTDFX=TDFXPTR(); + tdfxReg=(vgaTDFXPtr)vgaNewVideoState; + tdfxReg->mempll=CalcPLL(freq, &f_out); + pTDFX->writeLong(pTDFX, PLLCTRL1, tdfxReg->mempll); + TDFXTRACEREG("Mem PLL freq=%d f_out=%d reg=%x\n", freq, f_out, + tdfxReg->mempll); + return TRUE; +} + +static Bool +SetupGfxPLL(int freq) { + TDFXPtr pTDFX; + vgaTDFXPtr tdfxReg; + int f_out; + + TDFXTRACE("SetupGfxPLL start\n"); + pTDFX=TDFXPTR(); + tdfxReg=(vgaTDFXPtr)vgaNewVideoState; + if (pTDFX->chipType==PCI_CHIP_BANSHEE) + tdfxReg->gfxpll=CalcPLL(freq, &f_out, 1); + else + tdfxReg->gfxpll=CalcPLL(freq, &f_out, 0); + pTDFX->writeLong(pTDFX, PLLCTRL2, tdfxReg->gfxpll); + TDFXTRACEREG("Gfx PLL freq=%d f_out=%d reg=%x\n", freq, f_out, + tdfxReg->gfxpll); + return TRUE; +} +#endif + +#if 0 +static Bool +TDFXInitWithBIOSData(ScrnInfoPtr pScrn) +{ + TDFXPtr pTDFX; + unsigned char *bios = NULL; + int offset1, offset2; + int i; + CARD32 uint[9]; + + pTDFX=TDFXPTR(pScrn); + + if (pTDFX->initDone) + return TRUE; + + if (pTDFX->Primary) { + uint[0] = pTDFX->readLong(pTDFX, PCIINIT0); + uint[1] = pTDFX->readLong(pTDFX, MISCINIT0); + uint[2] = pTDFX->readLong(pTDFX, MISCINIT1); + uint[3] = pTDFX->readLong(pTDFX, DRAMINIT0); + uint[4] = pTDFX->readLong(pTDFX, DRAMINIT1); + uint[5] = pTDFX->readLong(pTDFX, AGPINIT); + uint[6] = pTDFX->readLong(pTDFX, PLLCTRL1); + uint[7] = pTDFX->readLong(pTDFX, PLLCTRL2); + for (i = 0; i < 8; i++) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Primary UINT32[%d] is 0x%08lx\n", i, uint[i]); + } + return TRUE; + } + +#define T_B_SIZE (64 * 1024) + bios = xcalloc(T_B_SIZE, 1); + if (!bios) + return FALSE; + + if (!xf86ReadPciBIOS(0, pTDFX->PciTag[0], 1, bios, T_B_SIZE)) { +#if 0 + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Bad BIOS read.\n"); + xfree(bios); + return FALSE; +#endif + } + + if (bios[0] != 0x55 || bios[1] != 0xAA) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Bad BIOS signature.\n"); + xfree(bios); + return FALSE; + } + + offset1 = bios[0x50] | (bios[0x51] << 8); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Offset 1 is (0x%04x)\n", offset1); + offset2 = bios[offset1] | (bios[offset1 + 1] << 8); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Offset 2 is (0x%04x)\n", offset2); + + for (i = 0; i < 9; i++) { + int o; + + o = offset2 + i * 4; + uint[i] = bios[o] | (bios[o+1] << 8) | (bios[o+2] << 16) | (bios[o+3] << 24); + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "UINT32[%d] is 0x%08lx\n", i, uint[i]); + } + +#if 1 + uint[0] = 0x0584fb04; + uint[1] = 0x00000000; + uint[2] = 0x03000001; + uint[3] = 0x0c17a9e9; + uint[4] = 0x00202031; + uint[5] = 0x8000049e; + uint[6] = 0x00003a05; + uint[7] = 0x00000c00; +#endif + + pTDFX->writeLong(pTDFX, PCIINIT0, uint[0]); + pTDFX->writeLong(pTDFX, MISCINIT0, uint[1]); + pTDFX->writeLong(pTDFX, MISCINIT1, uint[2]); + pTDFX->writeLong(pTDFX, DRAMINIT0, uint[3]); + pTDFX->writeLong(pTDFX, DRAMINIT1, uint[4]); + pTDFX->writeLong(pTDFX, AGPINIT, uint[5]); + pTDFX->writeLong(pTDFX, PLLCTRL1, uint[6]); + pTDFX->writeLong(pTDFX, PLLCTRL2, uint[7]); +#if 0 + pTDFX->writeLong(pTDFX, DRAMCOMMAND, uint[8]); +#endif + + /* reset */ + pTDFX->writeLong(pTDFX, MISCINIT0, 0xF3); + pTDFX->writeLong(pTDFX, MISCINIT0, uint[1]); + + xfree(bios); + return TRUE; +} +#endif + + +static Bool +TDFXInitVGA(ScrnInfoPtr pScrn) +{ + TDFXPtr pTDFX; + TDFXRegPtr tdfxReg; + + TDFXTRACE("TDFXInitVGA start\n"); + pTDFX=TDFXPTR(pScrn); + if (pTDFX->initDone) return TRUE; + pTDFX->initDone=TRUE; + + tdfxReg = &pTDFX->ModeReg; + tdfxReg->vgainit0 = 0; + tdfxReg->vgainit0 |= SST_VGA0_EXTENSIONS; + tdfxReg->vgainit0 |= SST_WAKEUP_3C3 << SST_VGA0_WAKEUP_SELECT_SHIFT; +#if USE_PCIVGAIO + tdfxReg->vgainit0 |= SST_VGA0_LEGACY_DECODE; +#endif + tdfxReg->vgainit0 |= SST_ENABLE_ALT_READBACK << SST_VGA0_CONFIG_READBACK_SHIFT; + tdfxReg->vgainit0 |= SST_CLUT_SELECT_8BIT << SST_VGA0_CLUT_SELECT_SHIFT; + + tdfxReg->vgainit0 |= BIT(12); +#if 0 + tdfxReg->vgainit1 |= 0; + tdfxReg->miscinit1 = 0; +#endif + + tdfxReg->vidcfg = SST_VIDEO_PROCESSOR_EN | SST_CURSOR_X11 | SST_DESKTOP_EN | + (pTDFX->cpp-1)<<SST_DESKTOP_PIXEL_FORMAT_SHIFT; + + /* tdfxReg->vidcfg |= SST_DESKTOP_CLUT_BYPASS; */ + + tdfxReg->stride = pTDFX->stride; + + tdfxReg->clip0min = tdfxReg->clip1min = 0; + tdfxReg->clip0max = tdfxReg->clip1max = pTDFX->maxClip; + + return TRUE; +} + +static Bool +TDFXSetMode(ScrnInfoPtr pScrn, DisplayModePtr mode) { + TDFXPtr pTDFX; + TDFXRegPtr tdfxReg; + vgaRegPtr pVga; + int hbs, hbe, vbs, vbe, hse; + int hd, hss, ht, vt, vd; + + TDFXTRACE("TDFXSetMode start\n"); + + pTDFX = TDFXPTR(pScrn); + tdfxReg = &pTDFX->ModeReg; + pVga = &VGAHWPTR(pScrn)->ModeReg; + + /* Tell the board we're using a programmable clock */ + pVga->MiscOutReg |= 0xC; + + /* Calculate the CRTC values */ + hd = (mode->CrtcHDisplay>>3)-1; + hss = (mode->CrtcHSyncStart>>3); + hse = (mode->CrtcHSyncEnd>>3); + ht = (mode->CrtcHTotal>>3)-5; + hbs = (mode->CrtcHBlankStart>>3)-1; + hbe = (mode->CrtcHBlankEnd>>3)-1; + + vd = mode->CrtcVDisplay-1; + vt = mode->CrtcVTotal-2; + vbs = mode->CrtcVBlankStart-1; + vbe = mode->CrtcVBlankEnd-1; + + /* Undo the "KGA fixes" */ + pVga->CRTC[3] = (hbe&0x1F)|0x80; + pVga->CRTC[5] = (((hbe)&0x20)<<2) | (hse&0x1F); + pVga->CRTC[22] =vbe&0xFF; + + /* Handle the higher resolution modes */ + tdfxReg->ExtVga[0] = (ht&0x100)>>8 | (hd&0x100)>>6 | (hbs&0x100)>>4 | + (hbe&0x40)>>1 | (hss&0x100)>>2 | (hse&0x20)<<2; + + tdfxReg->ExtVga[1] = (vt&0x400)>>10 | (vd&0x400)>>8 | (vbs&0x400)>>6 | + (vbe&0x400)>>4; + + if (!SetupVidPLL(pScrn, mode)) return FALSE; + + /* Set the screen size */ + if (mode->Flags&V_DBLSCAN) { + pVga->CRTC[9] |= 0x80; + tdfxReg->screensize=mode->HDisplay|(mode->VDisplay<<13); + tdfxReg->vidcfg |= SST_HALF_MODE; + } else { + tdfxReg->screensize=mode->HDisplay|(mode->VDisplay<<12); + tdfxReg->vidcfg &= ~SST_HALF_MODE; + } + if (mode->Flags&V_INTERLACE) { + tdfxReg->vidcfg|=SST_INTERLACE; + } else + tdfxReg->vidcfg&=~SST_INTERLACE; + + TDFXTRACEREG("cpp=%d Hdisplay=%d Vdisplay=%d stride=%d screensize=%x\n", + pTDFX->cpp, mode->HDisplay, mode->VDisplay, tdfxReg->stride, + tdfxReg->screensize); + + return TRUE; +} + +static Bool +TDFXModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode) +{ + vgaHWPtr hwp; + TDFXPtr pTDFX; + int hd, hbs, hss, hse, hbe, ht, hskew; + Bool dbl; + + hd = hbs = hss = hse = hbe = ht = hskew = 0; + hwp = VGAHWPTR(pScrn); + pTDFX = TDFXPTR(pScrn); + + TDFXTRACE("TDFXModeInit start\n"); + dbl=FALSE; + /* Check for 2x mode and halve all the timing values */ + if (mode->Clock>TDFX2XCUTOFF) { + hd=mode->CrtcHDisplay; + hbs=mode->CrtcHBlankStart; + hss=mode->CrtcHSyncStart; + hse=mode->CrtcHSyncEnd; + hbe=mode->CrtcHBlankEnd; + ht=mode->CrtcHTotal; + hskew=mode->CrtcHSkew; + mode->CrtcHDisplay=hd>>1; + mode->CrtcHBlankStart=hbs>>1; + mode->CrtcHSyncStart=hss>>1; + mode->CrtcHSyncEnd=hse>>1; + mode->CrtcHBlankEnd=hbe>>1; + mode->CrtcHTotal=ht>>1; + mode->CrtcHSkew=hskew>>1; + dbl=TRUE; + } + + vgaHWUnlock(hwp); + + if (!vgaHWInit(pScrn, mode)) return FALSE; + + pScrn->vtSema = TRUE; + + if (!TDFXSetMode(pScrn, mode)) return FALSE; + + if (dbl) { + mode->CrtcHDisplay=hd; + mode->CrtcHBlankStart=hbs; + mode->CrtcHSyncStart=hss; + mode->CrtcHSyncEnd=hse; + mode->CrtcHBlankEnd=hbe; + mode->CrtcHTotal=ht; + mode->CrtcHSkew=hskew; + } + +#ifdef XF86DRI + if (pTDFX->directRenderingEnabled) { + DRILock(screenInfo.screens[pScrn->scrnIndex], 0); + TDFXSwapContextFifo(screenInfo.screens[pScrn->scrnIndex]); + } +#endif + DoRestore(pScrn, &hwp->ModeReg, &pTDFX->ModeReg, FALSE); +#ifdef XF86DRI + if (pTDFX->directRenderingEnabled) { + DRIUnlock(screenInfo.screens[pScrn->scrnIndex]); + } +#endif + + return TRUE; +} + +static void +TDFXLoadPalette16(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, + VisualPtr pVisual) { + TDFXPtr pTDFX; + int i, j, index, v, repeat, max; + + TDFXTRACE("TDFXLoadPalette16 start\n"); + pTDFX = TDFXPTR(pScrn); + + for (i=0; i<numColors; i++) { + index=indices[i]; + v=(colors[index/2].red<<16)|(colors[index].green<<8)|colors[index/2].blue; + max=min((index+1)<<2, 256); + for (j = index<<2; j < max; j++) + { + repeat=100; + do { + TDFXWriteLongMMIO(pTDFX, DACADDR, j); + } while (--repeat && TDFXReadLongMMIO(pTDFX, DACADDR)!=j); + if (!repeat) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Failed to set dac index, bypassing CLUT\n"); + pTDFX->ModeReg.vidcfg |= SST_DESKTOP_CLUT_BYPASS; + return; + } + + repeat=100; + do { + TDFXWriteLongMMIO(pTDFX, DACDATA, v); + } while (--repeat && TDFXReadLongMMIO(pTDFX, DACDATA)!=v); + if (!repeat) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Failed to set dac value, bypassing CLUT\n"); + pTDFX->ModeReg.vidcfg |= SST_DESKTOP_CLUT_BYPASS; + return; + } + } + } +} + +static void +TDFXLoadPalette24(ScrnInfoPtr pScrn, int numColors, int *indices, LOCO *colors, + VisualPtr pVisual) { + TDFXPtr pTDFX; + int i, index, v, repeat; + + TDFXTRACE("TDFXLoadPalette24 start\n"); + pTDFX = TDFXPTR(pScrn); + for (i=0; i<numColors; i++) { + index=indices[i]; + v=(colors[index].red<<16)|(colors[index].green<<8)|colors[index].blue; + repeat=100; + do { + TDFXWriteLongMMIO(pTDFX, DACADDR, index); + } while (--repeat && TDFXReadLongMMIO(pTDFX, DACADDR)!=index); + if (!repeat) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Failed to set dac index, " + "bypassing CLUT\n"); + pTDFX->ModeReg.vidcfg |= SST_DESKTOP_CLUT_BYPASS; + return; + } + repeat=100; + do { + TDFXWriteLongMMIO(pTDFX, DACDATA, v); + } while (--repeat && TDFXReadLongMMIO(pTDFX, DACDATA)!=v); + if (!repeat) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Failed to set dac value, " + "bypassing CLUT\n"); + pTDFX->ModeReg.vidcfg |= SST_DESKTOP_CLUT_BYPASS; + return; + } + } +} + +#define TILE_WIDTH 128 +#define TILE_HEIGHT 32 + +static int +calcBufferStride(int xres, Bool tiled, int cpp) +{ + int strideInTiles; + + if (tiled == TRUE) { + /* Calculate tile width stuff */ + strideInTiles = (xres+TILE_WIDTH-1)/TILE_WIDTH; + + return strideInTiles*cpp*TILE_WIDTH; + } else { + return xres*cpp; + } +} /* calcBufferStride */ + +static int +calcBufferHeightInTiles(int yres) +{ + int heightInTiles; /* Height of buffer in tiles */ + + + /* Calculate tile height stuff */ + heightInTiles = yres >> 5; + + if (yres & (TILE_HEIGHT - 1)) + heightInTiles++; + + return heightInTiles; + +} /* calcBufferHeightInTiles */ + +#if 0 +static int +calcBufferSizeInTiles(int xres, int yres, int cpp) { + int bufSizeInTiles; /* Size of buffer in tiles */ + + bufSizeInTiles = + calcBufferHeightInTiles(yres) * (calcBufferStride(xres, TRUE, cpp) >> 7); + + return bufSizeInTiles; + +} /* calcBufferSizeInTiles */ +#endif + +static int +calcBufferSize(int xres, int yres, Bool tiled, int cpp) +{ + int stride, height, bufSize; + + if (tiled) { + stride = calcBufferStride(xres, tiled, cpp); + height = TILE_HEIGHT * calcBufferHeightInTiles(yres); + } else { + stride = xres*cpp; + height = yres; + } + + bufSize = stride * height; + + return bufSize; + +} /* calcBufferSize */ + +static void allocateMemory(ScrnInfoPtr pScrn) { + TDFXPtr pTDFX; + int memRemaining, fifoSize, screenSizeInTiles, cursorSize; + int fbSize; + int verb; + char *str; + + pTDFX = TDFXPTR(pScrn); + + if (pTDFX->cpp!=3) { + screenSizeInTiles=calcBufferSize(pScrn->virtualX, pScrn->virtualY, + TRUE, pTDFX->cpp); + } + else { + /* cpp==3 needs to bump up to 4 */ + screenSizeInTiles=calcBufferSize(pScrn->virtualX, pScrn->virtualY, + TRUE, 4); + } + + /* + * Layout is: + * cursor, fifo, fb, tex, bb, db + */ + + fbSize = (pScrn->virtualY + pTDFX->pixmapCacheLinesMin) * pTDFX->stride; + + memRemaining=((pScrn->videoRam<<10) - 1) &~ 0xFFF; + /* Note that a page is 4096 bytes, and a */ + /* tile is 32 x 128 = 4096 bytes. So, */ + /* page and tile boundaries are the same */ + /* Place the depth offset first, forcing */ + /* it to be on an *odd* page boundary. */ + pTDFX->depthOffset = (memRemaining - screenSizeInTiles) &~ 0xFFF; + if ((pTDFX->depthOffset & (0x1 << 12)) == 0) { +#if 1 + if (pTDFX->depthOffset > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Changing depth offset from 0x%08x to 0x%08x\n", + pTDFX->depthOffset, + pTDFX->depthOffset - (0x1 << 12)); + } +#endif + pTDFX->depthOffset -= (0x1 << 12); + } + /* Now, place the back buffer, forcing it */ + /* to be on an *even* page boundary. */ + pTDFX->backOffset = (pTDFX->depthOffset - screenSizeInTiles) &~ 0xFFF; + if (pTDFX->backOffset & (0x1 << 12)) { +#if 1 + if (pTDFX->backOffset > 0) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Changing back offset from 0x%08x to 0x%08x\n", + pTDFX->backOffset, + pTDFX->backOffset - (0x1 << 12)); + } +#endif + pTDFX->backOffset -= (0x1 << 12); + } + /* Give the cmd fifo at least */ + /* CMDFIFO_PAGES pages, but no more than */ + /* 64. NOTE: Don't go higher than 64, as */ + /* there is suspect code in Glide3 ! */ + fifoSize = ((64 <= CMDFIFO_PAGES) ? 64 : CMDFIFO_PAGES) << 12; + + /* We give 4096 bytes to the cursor */ + cursorSize = 4096; + pTDFX->cursorOffset = 0; + + pTDFX->fifoOffset = pTDFX->cursorOffset + cursorSize; + pTDFX->fifoSize = fifoSize; + /* Now, place the front buffer, forcing */ + /* it to be on a page boundary too, just */ + /* for giggles. */ + pTDFX->fbOffset = pTDFX->fifoOffset + pTDFX->fifoSize; + pTDFX->texOffset = pTDFX->fbOffset + fbSize; + if (pTDFX->depthOffset <= pTDFX->texOffset || + pTDFX->backOffset <= pTDFX->texOffset) { + /* + * pTDFX->texSize < 0 means that the DRI is disabled. pTDFX->backOffset + * is used to calculate the maximum amount of memory available for + * 2D offscreen use. With DRI disabled, set this to the top of memory. + */ + + pTDFX->texSize = -1; + pTDFX->backOffset = pScrn->videoRam * 1024; + pTDFX->depthOffset = -1; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Not enough video memory available for textures and depth buffer\n" + "\tand/or back buffer. Disabling DRI. To use DRI try lower\n" + "\tresolution modes and/or a smaller virtual screen size\n"); + } else { + pTDFX->texSize = pTDFX->backOffset - pTDFX->texOffset; + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Textures Memory %0.02f MB\n", + (float)pTDFX->texSize/1024.0/1024.0); + } + +/* This could be set to 2 or 3 */ +#define OFFSET_VERB 1 + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, OFFSET_VERB, + "Cursor Offset: [0x%08X,0x%08X)\n", + pTDFX->cursorOffset, + pTDFX->cursorOffset + cursorSize); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, OFFSET_VERB, + "Fifo Offset: [0x%08X, 0x%08X)\n", + pTDFX->fifoOffset, + pTDFX->fifoOffset + pTDFX->fifoSize); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, OFFSET_VERB, + "Front Buffer Offset: [0x%08X, 0x%08X)\n", + pTDFX->fbOffset, + pTDFX->fbOffset + + (pScrn->virtualY+pTDFX->pixmapCacheLinesMin)*pTDFX->stride); + if (pTDFX->texSize > 0) { + verb = OFFSET_VERB; + str = ""; + } else { + verb = 3; + str = "(NOT USED) "; + } + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verb, + "%sTexture Offset: [0x%08X, 0x%08X)\n", str, + pTDFX->texOffset, + pTDFX->texOffset + pTDFX->texSize); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verb, + "%sBackOffset: [0x%08X, 0x%08X)\n", str, + pTDFX->backOffset, + pTDFX->backOffset + screenSizeInTiles); + xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, verb, + "%sDepthOffset: [0x%08X, 0x%08X)\n", str, + pTDFX->depthOffset, + pTDFX->depthOffset + screenSizeInTiles); +} + +static Bool +TDFXScreenInit(int scrnIndex, ScreenPtr pScreen, int argc, char **argv) { + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + TDFXPtr pTDFX; + VisualPtr visual; + BoxRec MemBox; +#ifdef XF86DRI + MessageType driFrom = X_DEFAULT; +#endif + int scanlines; + + TDFXTRACE("TDFXScreenInit start\n"); + pScrn = xf86Screens[pScreen->myNum]; + pTDFX = TDFXPTR(pScrn); + hwp = VGAHWPTR(pScrn); + + if (!TDFXMapMem(pScrn)) return FALSE; + pScrn->memPhysBase = (int)pTDFX->LinearAddr[0]; + + if (!pTDFX->usePIO) TDFXSetMMIOAccess(pTDFX); + +#if USE_PCIVGAIO + hwp->PIOOffset = pTDFX->PIOBase[0] - 0x300; +#endif + vgaHWGetIOBase(hwp); + /* Map VGA memory only for primary cards (to save/restore textmode data). */ + if (pTDFX->Primary) { + if (!vgaHWMapMem(pScrn)) + return FALSE; + } + + pTDFX->stride = pScrn->displayWidth*pTDFX->cpp; + + /* enough to do DVD */ + pTDFX->pixmapCacheLinesMin = ((720*480*pTDFX->cpp) + + pTDFX->stride - 1)/pTDFX->stride; + + if (pTDFX->ChipType > PCI_CHIP_VOODOO3) { + if ((pTDFX->pixmapCacheLinesMin + pScrn->virtualY) > 4095) + pTDFX->pixmapCacheLinesMin = 4095 - pScrn->virtualY; + } else { + if ((pTDFX->pixmapCacheLinesMin + pScrn->virtualY) > 2047) + pTDFX->pixmapCacheLinesMin = 2047 - pScrn->virtualY; + } + + allocateMemory(pScrn); + + pScrn->fbOffset = pTDFX->fbOffset; + +#if 0 + if (pTDFX->numChips>1) { + if (xf86ReturnOptValBool(pTDFX->Options, OPTION_NO_SLI, FALSE)) { + TDFXSetupSLI(pScrn, FALSE, 0); + } else { + TDFXSetupSLI(pScrn, TRUE, 0); + } + } +#endif + + TDFXSetLFBConfig(pTDFX); + + /* We initialize in the state that our FIFO is up to date */ + pTDFX->syncDone=TRUE; + if (!TDFXInitFifo(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to initialize private\n"); + return FALSE; + } + + scanlines = (pTDFX->backOffset - pTDFX->fbOffset) / pTDFX->stride; + if(pTDFX->ChipType < PCI_CHIP_VOODOO5) { + if (scanlines > 2047) + scanlines = 2047; + } else { + /* MaxClip seems to have only 12 bits => 0->4095 */ + if (scanlines > 4095) + scanlines = 4095; + } + + pTDFX->pixmapCacheLinesMax = scanlines - pScrn->virtualY; + + /* + * Note, pTDFX->pixmapCacheLinesMax may be smaller than + * pTDFX->pixmapCacheLinesMin when pTDFX->texSize < 0. DRI is disabled + * in that case, so pTDFX->pixmapCacheLinesMin isn't used when that's true. + */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Minimum %d, Maximum %d lines of offscreen memory available\n", + pTDFX->pixmapCacheLinesMin, pTDFX->pixmapCacheLinesMax); + + MemBox.y1 = 0; + MemBox.x1 = 0; + MemBox.x2 = pScrn->displayWidth; + MemBox.y2 = scanlines; + + pTDFX->maxClip = MemBox.x2 | (MemBox.y2 << 16); + +#if 0 + TDFXInitWithBIOSData(pScrn); +#endif + TDFXInitVGA(pScrn); + TDFXSave(pScrn); + if (!TDFXModeInit(pScrn, pScrn->currentMode)) return FALSE; + + TDFXSetLFBConfig(pTDFX); + + miClearVisualTypes(); + + if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth), + pScrn->rgbBits, pScrn->defaultVisual)) + return FALSE; + + miSetPixmapDepths (); + + pTDFX->NoAccel=xf86ReturnOptValBool(pTDFX->Options, OPTION_NOACCEL, FALSE); +#ifdef XF86DRI + /* + * Setup DRI after visuals have been established, but before fbScreenInit + * is called. fbScreenInit will eventually call into the drivers + * InitGLXVisuals call back. + */ + if (!xf86ReturnOptValBool(pTDFX->Options, OPTION_DRI, TRUE) || pTDFX->NoAccel) { + pTDFX->directRenderingEnabled = FALSE; + driFrom = X_CONFIG; + } else if (pTDFX->texSize < 0) { + pTDFX->directRenderingEnabled = FALSE; + driFrom = X_PROBED; + } else { + pTDFX->directRenderingEnabled = TDFXDRIScreenInit(pScreen); + } +#endif + + switch (pScrn->bitsPerPixel) { + case 8: + case 16: + case 24: + case 32: + if (!fbScreenInit(pScreen, pTDFX->FbBase+pTDFX->fbOffset, + pScrn->virtualX, pScrn->virtualY, + pScrn->xDpi, pScrn->yDpi, + pScrn->displayWidth, pScrn->bitsPerPixel)) + return FALSE; + break; + default: + xf86DrvMsg(scrnIndex, X_ERROR, + "Internal error: invalid bpp (%d) in TDFXScrnInit\n", + pScrn->bitsPerPixel); + return FALSE; + } + + if (pScrn->bitsPerPixel>8) { + 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; + } + } + } + + /* must be after RGB ordering fixed */ + fbPictureInit (pScreen, 0, 0); + + xf86SetBlackWhitePixels(pScreen); + + TDFXDGAInit(pScreen); + + xf86InitFBManager(pScreen, &MemBox); + + if (!pTDFX->NoAccel) { + if (!TDFXAccelInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware acceleration initialization failed\n"); + } + } + + miInitializeBackingStore(pScreen); + xf86SetBackingStore(pScreen); + xf86SetSilkenMouse(pScreen); + + miDCInitialize(pScreen, xf86GetPointerScreenFuncs()); + + if (!xf86ReturnOptValBool(pTDFX->Options, OPTION_SW_CURSOR, FALSE)) { + if (!TDFXCursorInit(pScreen)) { + xf86DrvMsg(pScrn->scrnIndex, X_ERROR, + "Hardware cursor initialization failed\n"); + } + } + + if (!miCreateDefColormap(pScreen)) return FALSE; + + if (pScrn->bitsPerPixel==16) { + if (!xf86HandleColormaps(pScreen, 256, 8, TDFXLoadPalette16, 0, + CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } else { + if (!xf86HandleColormaps(pScreen, 256, 8, TDFXLoadPalette24, 0, + CMAP_PALETTED_TRUECOLOR|CMAP_RELOAD_ON_MODE_SWITCH)) + return FALSE; + } + + TDFXAdjustFrame(scrnIndex, 0, 0, 0); + + xf86DPMSInit(pScreen, TDFXDisplayPowerManagementSet, 0); + + /* Initialize Xv support */ + TDFXInitVideo (pScreen); + + pScreen->SaveScreen = TDFXSaveScreen; + pTDFX->CloseScreen = pScreen->CloseScreen; + pScreen->CloseScreen = TDFXCloseScreen; + + pTDFX->BlockHandler = pScreen->BlockHandler; + pScreen->BlockHandler = TDFXBlockHandler; + + /* + * DRICloseScreen isn't called thru a wrapper but explicitely + * in of TDFXCloseScreen() before the rest is unwrapped + */ + +#ifdef XF86DRI + if (pTDFX->directRenderingEnabled) { + /* Now that mi, fb, drm and others have done their thing, + * complete the DRI setup. + */ + pTDFX->directRenderingEnabled = TDFXDRIFinishScreenInit(pScreen); + } + if (pTDFX->directRenderingEnabled) { + xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n"); + } else { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n"); + } +#endif + + if (serverGeneration == 1) + xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options); + + return TRUE; +} + +Bool +TDFXSwitchMode(int scrnIndex, DisplayModePtr mode, int flags) { + ScrnInfoPtr pScrn; + + TDFXTRACE("TDFXSwitchMode start\n"); + pScrn=xf86Screens[scrnIndex]; + return TDFXModeInit(pScrn, mode); +} + +void +TDFXAdjustFrame(int scrnIndex, int x, int y, int flags) { + ScrnInfoPtr pScrn; + TDFXPtr pTDFX; + TDFXRegPtr tdfxReg; + + TDFXTRACE("TDFXAdjustFrame start\n"); + pScrn = xf86Screens[scrnIndex]; + pTDFX = TDFXPTR(pScrn); + + if (pTDFX->ShowCache && y && pScrn->vtSema) + y += pScrn->virtualY - 1; + + tdfxReg = &pTDFX->ModeReg; + if(pTDFX->ShowCache && y && pScrn->vtSema) + y += pScrn->virtualY - 1; + tdfxReg->startaddr = pTDFX->fbOffset+y*pTDFX->stride+(x*pTDFX->cpp); + TDFXTRACE("TDFXAdjustFrame to x=%d y=%d offset=%d\n", x, y, tdfxReg->startaddr); + pTDFX->writeLong(pTDFX, VIDDESKTOPSTARTADDR, tdfxReg->startaddr); +} + +static Bool +TDFXEnterVT(int scrnIndex, int flags) { + ScrnInfoPtr pScrn; + ScreenPtr pScreen; +#ifdef XF86DRI + TDFXPtr pTDFX; +#endif + + TDFXTRACE("TDFXEnterVT start\n"); + pScrn = xf86Screens[scrnIndex]; + pScreen = screenInfo.screens[scrnIndex]; + TDFXInitFifo(pScreen); +#ifdef XF86DRI + pTDFX = TDFXPTR(pScrn); + if (pTDFX->directRenderingEnabled) { + DRIUnlock(pScreen); + } +#endif + if (!TDFXModeInit(pScrn, pScrn->currentMode)) return FALSE; + TDFXAdjustFrame(scrnIndex, pScrn->frameX0, pScrn->frameY0, 0); + return TRUE; +} + +static void +TDFXLeaveVT(int scrnIndex, int flags) { + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + ScreenPtr pScreen; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXLeaveVT start\n"); + pScrn = xf86Screens[scrnIndex]; + hwp=VGAHWPTR(pScrn); + TDFXRestore(pScrn); + vgaHWLock(hwp); + pScreen = screenInfo.screens[scrnIndex]; + pTDFX = TDFXPTR(pScrn); + pTDFX->sync(pScrn); + TDFXShutdownFifo(pScreen); +#ifdef XF86DRI + if (pTDFX->directRenderingEnabled) { + DRILock(pScreen, 0); + } +#endif +} + +static Bool +TDFXCloseScreen(int scrnIndex, ScreenPtr pScreen) +{ + ScrnInfoPtr pScrn; + vgaHWPtr hwp; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXCloseScreen start\n"); + pScrn = xf86Screens[scrnIndex]; + hwp = VGAHWPTR(pScrn); + pTDFX = TDFXPTR(pScrn); + +#ifdef XF86DRI + if (pTDFX->directRenderingEnabled) { + TDFXDRICloseScreen(pScreen); + pTDFX->directRenderingEnabled=FALSE; + } +#endif + + TDFXShutdownFifo(pScreen); + + if (pScrn->vtSema) { + TDFXRestore(pScrn); + vgaHWLock(hwp); + TDFXUnmapMem(pScrn); + vgaHWUnmapMem(pScrn); + } + + if (pTDFX->AccelInfoRec) XAADestroyInfoRec(pTDFX->AccelInfoRec); + pTDFX->AccelInfoRec=0; + if (pTDFX->DGAModes) xfree(pTDFX->DGAModes); + pTDFX->DGAModes=0; + if (pTDFX->scanlineColorExpandBuffers[0]) + xfree(pTDFX->scanlineColorExpandBuffers[0]); + pTDFX->scanlineColorExpandBuffers[0]=0; + if (pTDFX->scanlineColorExpandBuffers[1]) + xfree(pTDFX->scanlineColorExpandBuffers[1]); + pTDFX->scanlineColorExpandBuffers[1]=0; + if (pTDFX->overlayAdaptor) + xfree(pTDFX->overlayAdaptor); + pTDFX->overlayAdaptor=0; + if (pTDFX->textureAdaptor) + xfree(pTDFX->textureAdaptor); + pTDFX->textureAdaptor=0; + + pScrn->vtSema=FALSE; + + pScreen->BlockHandler = pTDFX->BlockHandler; + pScreen->CloseScreen = pTDFX->CloseScreen; + return (*pScreen->CloseScreen)(scrnIndex, pScreen); +} + +static void +TDFXFreeScreen(int scrnIndex, int flags) { + TDFXTRACE("TDFXFreeScreen start\n"); + TDFXFreeRec(xf86Screens[scrnIndex]); + if (xf86LoaderCheckSymbol("vgaHWFreeHWRec")) + vgaHWFreeHWRec(xf86Screens[scrnIndex]); +} + +static ModeStatus +TDFXValidMode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags) { + ScrnInfoPtr pScrn; + TDFXPtr pTDFX; + + TDFXTRACE("TDFXValidMode start\n"); + if ((mode->HDisplay>2048) || (mode->VDisplay>1536)) + return MODE_BAD; + /* Banshee doesn't support interlace, but Voodoo 3 and higher do. */ + pScrn = xf86Screens[scrnIndex]; + pTDFX = TDFXPTR(pScrn); + if (mode->Flags&V_INTERLACE) { + switch (pTDFX->ChipType) { + case PCI_CHIP_BANSHEE: + return MODE_BAD; + break; + case PCI_CHIP_VOODOO3: + case PCI_CHIP_VOODOO5: + return MODE_OK; + break; + default: + return MODE_BAD; + break; + } + } + /* In clock doubled mode widths must be divisible by 16 instead of 8 */ + if ((mode->Clock>TDFX2XCUTOFF) && (mode->HDisplay%16)) + return MODE_BAD; + return MODE_OK; +} + +/* replacement of vgaHWBlankScreen(pScrn, unblank) which doesn't unblank + * the screen if it is already unblanked. */ +static void +TDFXBlankScreen(ScrnInfoPtr pScrn, Bool unblank) +{ + vgaHWPtr hwp = VGAHWPTR(pScrn); + unsigned char scrn; + + TDFXTRACE("TDFXBlankScreen start\n"); + + scrn = hwp->readSeq(hwp, 0x01); + + if (unblank) { + if((scrn & 0x20) == 0) return; + scrn &= ~0x20; /* enable screen */ + } else { + scrn |= 0x20; /* blank screen */ + } + + vgaHWSeqReset(hwp, TRUE); + hwp->writeSeq(hwp, 0x01, scrn); /* change mode */ + vgaHWSeqReset(hwp, FALSE); +} + +static Bool +TDFXSaveScreen(ScreenPtr pScreen, int mode) +{ + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + Bool unblank; + + TDFXTRACE("TDFXSaveScreen start\n"); + + unblank = xf86IsUnblank(mode); + + if (unblank) + SetTimeSinceLastInputEvent(); + + if (pScrn->vtSema) { + TDFXBlankScreen(pScrn, unblank); + } + return TRUE; +} + +static void +TDFXBlockHandler(int i, pointer blockData, pointer pTimeout, pointer pReadmask) +{ + ScreenPtr pScreen = screenInfo.screens[i]; + ScrnInfoPtr pScrn = xf86Screens[i]; + TDFXPtr pTDFX = TDFXPTR(pScrn); + + pScreen->BlockHandler = pTDFX->BlockHandler; + (*pScreen->BlockHandler) (i, blockData, pTimeout, pReadmask); + pScreen->BlockHandler = TDFXBlockHandler; + + if(pTDFX->VideoTimerCallback) { + (*pTDFX->VideoTimerCallback)(pScrn, currentTime.milliseconds); + } +} + +static void +TDFXDisplayPowerManagementSet(ScrnInfoPtr pScrn, int PowerManagementMode, + int flags) { + TDFXPtr pTDFX; + int dacmode, state=0; + + TDFXTRACE("TDFXDPMS start\n"); + pTDFX = TDFXPTR(pScrn); + dacmode=pTDFX->readLong(pTDFX, DACMODE); + switch (PowerManagementMode) { + case DPMSModeOn: + /* Screen: On; HSync: On, VSync: On */ + state=0; + break; + case DPMSModeStandby: + /* Screen: Off; HSync: Off, VSync: On */ + state=BIT(3); + break; + case DPMSModeSuspend: + /* Screen: Off; HSync: On, VSync: Off */ + state=BIT(1); + break; + case DPMSModeOff: + /* Screen: Off; HSync: Off, VSync: Off */ + state=BIT(1)|BIT(3); + break; + } + dacmode&=~(BIT(1)|BIT(3)); + dacmode|=state; + pTDFX->writeLong(pTDFX, DACMODE, dacmode); +} |