xenocara/driver/xf86-video-savage/src/savage_driver.c
2008-10-12 21:24:21 +00:00

4863 lines
133 KiB
C

/*
* Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
* Copyright (c) 2003-2006, X.Org Foundation
*
* 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,
* FITESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
*
* Except as contained in this notice, the name of the copyright holder(s)
* and author(s) shall not be used in advertising or otherwise to promote
* the sale, use or other dealings in this Software without prior written
* authorization from the copyright holder(s) and author(s).
*/
/**
* \file savage_driver.c
*
* \author Tim Roberts <timr@probo.com>
* \author Ani Joshi <ajoshi@unixbox.com>
*
* \todo Add credits for the 3.3.x authors.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <unistd.h>
#include <errno.h>
#include "xf86RAC.h"
#include "shadowfb.h"
#include "globals.h"
#define DPMS_SERVER
#include <X11/extensions/dpms.h>
#include "xf86xv.h"
#include "savage_driver.h"
#include "savage_regs.h"
#include "savage_bci.h"
#include "savage_streams.h"
#define TRANSPARENCY_KEY 0xff;
#ifdef XF86DRI
#define _XF86DRI_SERVER_
#include "savage_dri.h"
#include "savage_sarea.h"
#endif
/*
* prototypes
*/
static void SavageEnableMMIO(ScrnInfoPtr pScrn);
static void SavageDisableMMIO(ScrnInfoPtr pScrn);
static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid);
static void SavageIdentify(int flags);
#ifdef XSERVER_LIBPCIACCESS
static Bool SavagePciProbe(DriverPtr drv, int entity_num,
struct pci_device *dev, intptr_t match_data);
#else
static Bool SavageProbe(DriverPtr drv, int flags);
static int LookupChipID(PciChipsets* pset, int ChipID);
#endif
static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags);
static Bool SavageEnterVT(int scrnIndex, int flags);
static void SavageLeaveVT(int scrnIndex, int flags);
static void SavageSave(ScrnInfoPtr pScrn);
static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr, SavageRegPtr, Bool);
static void SavageInitStatus(ScrnInfoPtr pScrn);
static void SavageInitShadowStatus(ScrnInfoPtr pScrn);
static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
char **argv);
static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen);
static ModeStatus SavageValidMode(int index, DisplayModePtr mode,
Bool verbose, int flags);
void SavageDGAInit(ScreenPtr);
static Bool SavageMapMem(ScrnInfoPtr pScrn);
static void SavageUnmapMem(ScrnInfoPtr pScrn, int All);
static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen);
static Bool SavageSaveScreen(ScreenPtr pScreen, int mode);
static void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors,
int *indicies, LOCO *colors,
VisualPtr pVisual);
static void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors,
int *indicies, LOCO *colors,
VisualPtr pVisual);
static void SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b);
static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
int min_n2, int max_n2, long freq_min,
long freq_max, unsigned int *mdiv,
unsigned int *ndiv, unsigned int *r);
void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file);
void SavagePrintRegs(ScrnInfoPtr pScrn);
static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags);
static Bool SavageDDC1(int scrnIndex);
static unsigned int SavageDDC1Read(ScrnInfoPtr pScrn);
static void SavageProbeDDC(ScrnInfoPtr pScrn, int index);
static void SavageGetTvMaxSize(SavagePtr psav);
static Bool SavagePanningCheck(ScrnInfoPtr pScrn, DisplayModePtr pMode);
#ifdef XF86DRI
static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn);
#endif
static void SavageResetStreams(ScrnInfoPtr pScrn);
extern ScrnInfoPtr gpScrn;
#define iabs(a) ((int)(a)>0?(a):(-(a)))
/*#define TRACEON*/
#ifdef TRACEON
#define TRACE(prms) ErrorF prms
#else
#define TRACE(prms)
#endif
int gSavageEntityIndex = -1;
#ifdef XSERVER_LIBPCIACCESS
#define SAVAGE_DEVICE_MATCH(d, i) \
{ 0x5333, (d), PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, (i) }
static const struct pci_id_match savage_device_match[] = {
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE4, S3_SAVAGE4),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE3D, S3_SAVAGE3D),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE3D_MV, S3_SAVAGE3D),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE2000, S3_SAVAGE2000),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_MX_MV, S3_SAVAGE_MX),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_MX, S3_SAVAGE_MX),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_IX_MV, S3_SAVAGE_MX),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SAVAGE_IX, S3_SAVAGE_MX),
SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_PM, S3_PROSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_KM, S3_PROSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_S3TWISTER_P, S3_TWISTER),
SAVAGE_DEVICE_MATCH(PCI_CHIP_S3TWISTER_K, S3_TWISTER),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX128, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX64, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_MX64C, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX128SDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX128DDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX64SDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IX64DDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IXCSDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_SUPSAV_IXCDDR, S3_SUPERSAVAGE),
SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_DDR, S3_PROSAVAGEDDR),
SAVAGE_DEVICE_MATCH(PCI_CHIP_PROSAVAGE_DDRK, S3_PROSAVAGEDDR),
{ 0, 0, 0 },
};
#endif
/* Supported chipsets */
static SymTabRec SavageChips[] = {
{ PCI_CHIP_SAVAGE4, "Savage4" },
{ PCI_CHIP_SAVAGE3D, "Savage3D" },
{ PCI_CHIP_SAVAGE3D_MV, "Savage3D-MV" },
{ PCI_CHIP_SAVAGE2000, "Savage2000" },
{ PCI_CHIP_SAVAGE_MX_MV, "Savage/MX-MV" },
{ PCI_CHIP_SAVAGE_MX, "Savage/MX" },
{ PCI_CHIP_SAVAGE_IX_MV, "Savage/IX-MV" },
{ PCI_CHIP_SAVAGE_IX, "Savage/IX" },
{ PCI_CHIP_PROSAVAGE_PM, "ProSavage PM133" },
{ PCI_CHIP_PROSAVAGE_KM, "ProSavage KM133" },
{ PCI_CHIP_S3TWISTER_P, "Twister PN133" },
{ PCI_CHIP_S3TWISTER_K, "Twister KN133" },
{ PCI_CHIP_SUPSAV_MX128, "SuperSavage/MX 128" },
{ PCI_CHIP_SUPSAV_MX64, "SuperSavage/MX 64" },
{ PCI_CHIP_SUPSAV_MX64C, "SuperSavage/MX 64C" },
{ PCI_CHIP_SUPSAV_IX128SDR, "SuperSavage/IX 128" },
{ PCI_CHIP_SUPSAV_IX128DDR, "SuperSavage/IX 128" },
{ PCI_CHIP_SUPSAV_IX64SDR, "SuperSavage/IX 64" },
{ PCI_CHIP_SUPSAV_IX64DDR, "SuperSavage/IX 64" },
{ PCI_CHIP_SUPSAV_IXCSDR, "SuperSavage/IXC 64" },
{ PCI_CHIP_SUPSAV_IXCDDR, "SuperSavage/IXC 64" },
{ PCI_CHIP_PROSAVAGE_DDR, "ProSavage DDR" },
{ PCI_CHIP_PROSAVAGE_DDRK, "ProSavage DDR-K" },
{ -1, NULL }
};
static SymTabRec SavageChipsets[] = {
{ S3_SAVAGE3D, "Savage3D" },
{ S3_SAVAGE4, "Savage4" },
{ S3_SAVAGE2000, "Savage2000" },
{ S3_SAVAGE_MX, "MobileSavage" },
{ S3_PROSAVAGE, "ProSavage" },
{ S3_TWISTER, "Twister"},
{ S3_PROSAVAGEDDR, "ProSavageDDR"},
{ S3_SUPERSAVAGE, "SuperSavage" },
{ -1, NULL }
};
#ifndef XSERVER_LIBPCIACCESS
/* This table maps a PCI device ID to a chipset family identifier. */
static PciChipsets SavagePciChipsets[] = {
{ S3_SAVAGE3D, PCI_CHIP_SAVAGE3D, RES_SHARED_VGA },
{ S3_SAVAGE3D, PCI_CHIP_SAVAGE3D_MV, RES_SHARED_VGA },
{ S3_SAVAGE4, PCI_CHIP_SAVAGE4, RES_SHARED_VGA },
{ S3_SAVAGE2000, PCI_CHIP_SAVAGE2000, RES_SHARED_VGA },
{ S3_SAVAGE_MX, PCI_CHIP_SAVAGE_MX_MV, RES_SHARED_VGA },
{ S3_SAVAGE_MX, PCI_CHIP_SAVAGE_MX, RES_SHARED_VGA },
{ S3_SAVAGE_MX, PCI_CHIP_SAVAGE_IX_MV, RES_SHARED_VGA },
{ S3_SAVAGE_MX, PCI_CHIP_SAVAGE_IX, RES_SHARED_VGA },
{ S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_PM, RES_SHARED_VGA },
{ S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_KM, RES_SHARED_VGA },
{ S3_TWISTER, PCI_CHIP_S3TWISTER_P, RES_SHARED_VGA },
{ S3_TWISTER, PCI_CHIP_S3TWISTER_K, RES_SHARED_VGA },
{ S3_PROSAVAGEDDR, PCI_CHIP_PROSAVAGE_DDR, RES_SHARED_VGA },
{ S3_PROSAVAGEDDR, PCI_CHIP_PROSAVAGE_DDRK, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX128, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX64, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_MX64C, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX128SDR, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX128DDR, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX64SDR, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IX64DDR, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IXCSDR, RES_SHARED_VGA },
{ S3_SUPERSAVAGE, PCI_CHIP_SUPSAV_IXCDDR, RES_SHARED_VGA },
{ -1, -1, RES_UNDEFINED }
};
#endif
typedef enum {
OPTION_PCI_BURST
,OPTION_PCI_RETRY
,OPTION_NOACCEL
,OPTION_ACCELMETHOD
,OPTION_LCD_CENTER
,OPTION_LCDCLOCK
,OPTION_MCLK
,OPTION_REFCLK
,OPTION_SHOWCACHE
,OPTION_SWCURSOR
,OPTION_HWCURSOR
,OPTION_SHADOW_FB
,OPTION_ROTATE
,OPTION_USEBIOS
,OPTION_SHADOW_STATUS
,OPTION_CRT_ONLY
,OPTION_TV_ON
,OPTION_TV_PAL
,OPTION_FORCE_INIT
,OPTION_OVERLAY
,OPTION_T_KEY
,OPTION_DISABLE_XVMC
,OPTION_DISABLE_TILE
,OPTION_DISABLE_COB
,OPTION_BCI_FOR_XV
,OPTION_DVI
,OPTION_BUS_TYPE
,OPTION_DMA_TYPE
,OPTION_DMA_MODE
,OPTION_AGP_MODE
,OPTION_AGP_SIZE
,OPTION_DRI
,OPTION_IGNORE_EDID
} SavageOpts;
static const OptionInfoRec SavageOptions[] =
{
{ OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING, {0}, FALSE },
{ OPTION_HWCURSOR, "HWCursor", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_SWCURSOR, "SWCursor", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ROTATE, "Rotate", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_USEBIOS, "UseBIOS", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_LCDCLOCK, "LCDClock", OPTV_FREQ, {0}, FALSE },
{ OPTION_SHADOW_STATUS, "ShadowStatus", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_CRT_ONLY, "CrtOnly", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_TV_ON, "TvOn", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_TV_PAL, "PAL", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_FORCE_INIT,"ForceInit", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_OVERLAY, "Overlay", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_T_KEY, "TransparencyKey", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_FORCE_INIT, "ForceInit", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DISABLE_XVMC, "DisableXVMC", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DISABLE_TILE, "DisableTile", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DISABLE_COB, "DisableCOB", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_BCI_FOR_XV, "BCIforXv", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_DVI, "DVI", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_IGNORE_EDID, "IgnoreEDID", OPTV_BOOLEAN, {0}, FALSE },
#ifdef XF86DRI
{ OPTION_BUS_TYPE, "BusType", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_DMA_TYPE, "DmaType", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_DMA_MODE, "DmaMode", OPTV_ANYSTR, {0}, FALSE },
{ OPTION_AGP_MODE, "AGPMode", OPTV_INTEGER, {0}, FALSE },
{ OPTION_AGP_SIZE, "AGPSize", OPTV_INTEGER, {0}, FALSE },
{ OPTION_DRI, "DRI", OPTV_BOOLEAN, {0}, TRUE },
#endif
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
_X_EXPORT DriverRec SAVAGE =
{
SAVAGE_VERSION,
SAVAGE_DRIVER_NAME,
SavageIdentify,
#ifdef XSERVER_LIBPCIACCESS
NULL,
#else
SavageProbe,
#endif
SavageAvailableOptions,
NULL,
0,
NULL,
#ifdef XSERVER_LIBPCIACCESS
savage_device_match,
SavagePciProbe
#endif
};
static const char *vgaHWSymbols[] = {
"vgaHWBlankScreen",
"vgaHWCopyReg",
"vgaHWGetHWRec",
"vgaHWGetIOBase",
"vgaHWGetIndex",
"vgaHWInit",
"vgaHWLock",
"vgaHWProtect",
"vgaHWRestore",
"vgaHWSave",
"vgaHWSaveScreen",
"vgaHWSetMmioFuncs",
"vgaHWSetStdFuncs",
"vgaHWUnmapMem",
"vgaHWddc1SetSpeedWeak",
#if 0
"vgaHWFreeHWRec",
"vgaHWMapMem",
"vgaHWUnlock",
#endif
NULL
};
#ifdef XF86DRI
static const char *drmSymbols[] = {
"drmAvailable",
"drmAddBufs",
"drmAddMap",
"drmCtlInstHandler",
"drmGetInterruptFromBusID",
"drmFreeVersion",
"drmGetVersion",
"drmMap",
"drmUnmap",
"drmMapBufs",
"drmUnmapBufs",
"drmAgpAcquire",
"drmAgpRelease",
"drmAgpEnable",
"drmAgpAlloc",
"drmAgpFree",
"drmAgpBind",
"drmAgpUnbind",
"drmAgpGetMode",
"drmAgpBase",
"drmAgpSize",
"drmAgpVendorId",
"drmAgpDeviceId",
"drmMGAInitDMA",
"drmMGACleanupDMA",
"drmMGAFlushDMA",
"drmMGAEngineReset",
NULL
};
static const char *driSymbols[] = {
"DRIGetDrawableIndex",
"DRIFinishScreenInit",
"DRIDestroyInfoRec",
"DRICloseScreen",
"DRIDestroyInfoRec",
"DRIScreenInit",
"DRIDestroyInfoRec",
"DRICreateInfoRec",
"DRILock",
"DRIUnlock",
"DRIGetSAREAPrivate",
"DRIGetContext",
"DRIQueryVersion",
"DRIAdjustFrame",
"DRIOpenFullScreen",
"DRICloseFullScreen",
"GlxSetVisualConfigs",
NULL
};
#endif
static const char *ramdacSymbols[] = {
"xf86CreateCursorInfoRec",
#if 0
"xf86DestroyCursorInfoRec",
#endif
"xf86InitCursor",
NULL
};
static const char *int10Symbols[] = {
"xf86ExecX86int10",
"xf86Int10AllocPages",
"xf86int10Addr",
"xf86Int10FreePages"
};
static const char *vbeSymbols[] = {
"VBEInit",
"vbeDoEDID",
#if 0
"vbeFree",
#endif
NULL
};
static const char *vbeOptSymbols[] = {
"vbeModeInit",
"VBESetVBEMode",
"VBEGetVBEInfo",
"VBEFreeVBEInfo",
NULL
};
static const char *ddcSymbols[] = {
"xf86DoEDID_DDC1",
"xf86DoEDID_DDC2",
"xf86PrintEDID",
"xf86SetDDCproperties",
NULL
};
static const char *i2cSymbols[] = {
"xf86CreateI2CBusRec",
"xf86I2CBusInit",
"xf86CreateI2CDevRec",
"xf86I2CDevInit",
"xf86I2CWriteByte",
"xf86I2CWriteBytes",
"xf86I2CReadByte",
"xf86I2CReadBytes",
"xf86I2CWriteRead",
"xf86DestroyI2CDevRec",
NULL
};
static const char *xaaSymbols[] = {
"XAAGetCopyROP",
"XAAGetCopyROP_PM",
"XAACreateInfoRec",
"XAADestroyInfoRec",
"XAAFillSolidRects",
"XAAHelpPatternROP",
"XAAHelpSolidROP",
"XAAInit",
"XAAScreenIndex",
NULL
};
static const char *exaSymbols[] = {
"exaDriverAlloc",
"exaDriverInit",
"exaDriverFini",
"exaOffscreenAlloc",
"exaOffscreenFree",
"exaGetPixmapOffset",
"exaGetPixmapPitch",
"exaGetPixmapSize",
NULL
};
static const char *shadowSymbols[] = {
"ShadowFBInit",
NULL
};
static const char *fbSymbols[] = {
"fbPictureInit",
"fbScreenInit",
NULL
};
#ifdef XFree86LOADER
static MODULESETUPPROTO(SavageSetup);
static XF86ModuleVersionInfo SavageVersRec = {
"savage",
MODULEVENDORSTRING,
MODINFOSTRING1,
MODINFOSTRING2,
XORG_VERSION_CURRENT,
SAVAGE_VERSION_MAJOR, SAVAGE_VERSION_MINOR, SAVAGE_PATCHLEVEL,
ABI_CLASS_VIDEODRV,
ABI_VIDEODRV_VERSION,
MOD_CLASS_VIDEODRV,
{0, 0, 0, 0}
};
_X_EXPORT XF86ModuleData savageModuleData = {
&SavageVersRec,
SavageSetup,
NULL
};
static pointer SavageSetup(pointer module, pointer opts, int *errmaj,
int *errmin)
{
static Bool setupDone = FALSE;
if (!setupDone) {
setupDone = TRUE;
xf86AddDriver(&SAVAGE, module, 1);
LoaderRefSymLists(vgaHWSymbols, fbSymbols, ramdacSymbols,
xaaSymbols,
exaSymbols,
shadowSymbols, vbeSymbols, vbeOptSymbols,
#ifdef XF86DRI
drmSymbols, driSymbols,
#endif
int10Symbols, i2cSymbols, ddcSymbols, NULL);
return (pointer) 1;
} else {
if (errmaj)
*errmaj = LDR_ONCEONLY;
return NULL;
}
}
#endif /* XFree86LOADER */
static SavageEntPtr SavageEntPriv(ScrnInfoPtr pScrn)
{
DevUnion *pPriv;
SavagePtr psav = SAVPTR(pScrn);
pPriv = xf86GetEntityPrivate(psav->pEnt->index,
gSavageEntityIndex);
return pPriv->ptr;
}
/*
* I'd rather have these wait macros be inline, but S3 has made it
* darned near impossible. The bit fields are in a different place in
* all three families, the status register has a different address in the
* three families, and even the idle vs busy sense flipped in the Sav2K.
*/
static void
ResetBCI2K( SavagePtr psav )
{
CARD32 cob = INREG( 0x48c18 );
/* if BCI is enabled and BCI is busy... */
if(
(cob & 0x00000008) &&
! (ALT_STATUS_WORD0 & 0x00200000)
)
{
ErrorF( "Resetting BCI, stat = %08lx...\n",
(unsigned long) ALT_STATUS_WORD0);
/* Turn off BCI */
OUTREG( 0x48c18, cob & ~8 );
usleep(10000);
/* Turn it back on */
OUTREG( 0x48c18, cob );
usleep(10000);
}
}
static Bool
ShadowWait( SavagePtr psav )
{
BCI_GET_PTR;
int loop = 0;
if( !psav->NoPCIRetry )
return 0;
psav->ShadowCounter = (psav->ShadowCounter + 1) & 0xffff;
if (psav->ShadowCounter == 0)
psav->ShadowCounter++; /* 0 is reserved for the BIOS
to avoid confusion in the DRM */
BCI_SEND( psav->dwBCIWait2DIdle );
BCI_SEND( 0x98000000 + psav->ShadowCounter );
while(
(int)(psav->ShadowVirtual[psav->eventStatusReg] & 0xffff) !=
psav->ShadowCounter && (loop++ < MAXLOOP)
)
;
return loop >= MAXLOOP;
}
static Bool
ShadowWaitQueue( SavagePtr psav, int v )
{
int loop = 0;
CARD32 slots = MAXFIFO - v;
if (slots >= psav->bciThresholdHi)
slots = psav->bciThresholdHi;
else
return ShadowWait( psav );
/* Savage 2000 reports only entries filled in the COB, not the on-chip
* queue. Also it reports in qword units instead of dwords. */
if (psav->Chipset == S3_SAVAGE2000)
slots = (slots - 32) / 4;
while( ((psav->ShadowVirtual[0] & psav->bciUsedMask) >= slots) && (loop++ < MAXLOOP))
;
return loop >= MAXLOOP;
}
/* Wait until "v" queue entries are free */
static int
WaitQueue3D( SavagePtr psav, int v )
{
int loop = 0;
CARD32 slots = MAXFIFO - v;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitQueue = ShadowWaitQueue;
return ShadowWaitQueue(psav, v);
}
else
{
loop &= STATUS_WORD0;
while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
;
}
return loop >= MAXLOOP;
}
static int
WaitQueue4( SavagePtr psav, int v )
{
int loop = 0;
CARD32 slots = MAXFIFO - v;
if( !psav->NoPCIRetry )
return 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitQueue = ShadowWaitQueue;
return ShadowWaitQueue(psav, v);
}
else
while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP));
return loop >= MAXLOOP;
}
static int
WaitQueue2K( SavagePtr psav, int v )
{
int loop = 0;
CARD32 slots = (MAXFIFO - v) / 4;
if( !psav->NoPCIRetry )
return 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitQueue = ShadowWaitQueue;
return ShadowWaitQueue(psav, v);
}
else
while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP))
;
if( loop >= MAXLOOP )
ResetBCI2K(psav);
return loop >= MAXLOOP;
}
/* Wait until GP is idle and queue is empty */
static int
WaitIdleEmpty3D(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdleEmpty = ShadowWait;
return ShadowWait(psav);
}
loop &= STATUS_WORD0;
while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) );
return loop >= MAXLOOP;
}
static int
WaitIdleEmpty4(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdleEmpty = ShadowWait;
return ShadowWait(psav);
}
/* which is right?*/
/*while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) );*/ /* tim */
while (((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) && (loop++ < MAXLOOP)); /* S3 */
return loop >= MAXLOOP;
}
static int
WaitIdleEmpty2K(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdleEmpty = ShadowWait;
return ShadowWait(psav);
}
loop &= ALT_STATUS_WORD0;
while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) );
if( loop >= MAXLOOP )
ResetBCI2K(psav);
return loop >= MAXLOOP;
}
/* Wait until GP is idle */
static int
WaitIdle3D(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdle = ShadowWait;
return ShadowWait(psav);
}
while( (!(STATUS_WORD0 & 0x00080000)) && (loop++ < MAXLOOP) );
return loop >= MAXLOOP;
}
static int
WaitIdle4(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdle = ShadowWait;
return ShadowWait(psav);
}
/* which is right?*/
/*while( (!(ALT_STATUS_WORD0 & 0x00800000)) && (loop++ < MAXLOOP) );*/ /* tim */
while (((ALT_STATUS_WORD0 & 0x00E00000)!=0x00E00000) && (loop++ < MAXLOOP)); /* S3 */
return loop >= MAXLOOP;
}
static int
WaitIdle2K(SavagePtr psav)
{
int loop = 0;
mem_barrier();
if( psav->ShadowVirtual )
{
psav->WaitIdle = ShadowWait;
return ShadowWait(psav);
}
loop &= ALT_STATUS_WORD0;
while( (ALT_STATUS_WORD0 & 0x00900000) && (loop++ < MAXLOOP) );
return loop >= MAXLOOP;
}
static Bool SavageGetRec(ScrnInfoPtr pScrn)
{
if (pScrn->driverPrivate)
return TRUE;
pScrn->driverPrivate = xnfcalloc(sizeof(SavageRec), 1);
return TRUE;
}
static void SavageFreeRec(ScrnInfoPtr pScrn)
{
TRACE(( "SavageFreeRec(%x)\n", pScrn->driverPrivate ));
if (!pScrn->driverPrivate)
return;
SavageUnmapMem(pScrn, 1);
xfree(pScrn->driverPrivate);
pScrn->driverPrivate = NULL;
}
static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid)
{
return SavageOptions;
}
static void SavageIdentify(int flags)
{
xf86PrintChipsets("SAVAGE",
"driver (version " SAVAGE_DRIVER_VERSION ") for S3 Savage chipsets",
SavageChips);
}
#ifdef XSERVER_LIBPCIACCESS
static Bool SavagePciProbe(DriverPtr drv, int entity_num,
struct pci_device *dev, intptr_t match_data)
{
ScrnInfoPtr pScrn;
if ((match_data < S3_SAVAGE3D) || (match_data > S3_SAVAGE2000)) {
return FALSE;
}
pScrn = xf86ConfigPciEntity(NULL, 0, entity_num, NULL,
RES_SHARED_VGA, NULL, NULL, NULL, NULL);
if (pScrn != NULL) {
EntityInfoPtr pEnt;
SavagePtr psav;
pScrn->driverVersion = SAVAGE_VERSION;
pScrn->driverName = SAVAGE_DRIVER_NAME;
pScrn->name = "SAVAGE";
pScrn->Probe = NULL;
pScrn->PreInit = SavagePreInit;
pScrn->ScreenInit = SavageScreenInit;
pScrn->SwitchMode = SavageSwitchMode;
pScrn->AdjustFrame = SavageAdjustFrame;
pScrn->EnterVT = SavageEnterVT;
pScrn->LeaveVT = SavageLeaveVT;
pScrn->FreeScreen = NULL;
pScrn->ValidMode = SavageValidMode;
if (!SavageGetRec(pScrn))
return FALSE;
psav = SAVPTR(pScrn);
psav->PciInfo = dev;
psav->Chipset = match_data;
pEnt = xf86GetEntityInfo(entity_num);
/* MX, IX, SuperSavage cards support Dual-Head, mark the entity as
* sharable.
*/
if (pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE) {
DevUnion *pPriv;
SavageEntPtr pSavageEnt;
xf86SetEntitySharable(entity_num);
if (gSavageEntityIndex == -1)
gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
pPriv = xf86GetEntityPrivate(pEnt->index, gSavageEntityIndex);
if (!pPriv->ptr) {
int j;
int instance = xf86GetNumEntityInstances(pEnt->index);
for (j = 0; j < instance; j++)
xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
pSavageEnt = pPriv->ptr;
pSavageEnt->HasSecondary = FALSE;
} else {
pSavageEnt = pPriv->ptr;
pSavageEnt->HasSecondary = TRUE;
}
}
}
return (pScrn != NULL);
}
#else
static Bool SavageProbe(DriverPtr drv, int flags)
{
int i;
GDevPtr *devSections = NULL;
int *usedChips;
int numDevSections;
int numUsed;
Bool foundScreen = FALSE;
/* sanity checks */
if ((numDevSections = xf86MatchDevice("savage", &devSections)) <= 0)
return FALSE;
if (xf86GetPciVideoInfo() == NULL) {
if (devSections)
xfree(devSections);
return FALSE;
}
numUsed = xf86MatchPciInstances("SAVAGE", PCI_VENDOR_S3,
SavageChipsets, SavagePciChipsets,
devSections, numDevSections, drv,
&usedChips);
if (devSections)
xfree(devSections);
devSections = NULL;
if (numUsed <= 0)
return FALSE;
if (flags & PROBE_DETECT)
foundScreen = TRUE;
else
for (i=0; i<numUsed; i++) {
EntityInfoPtr pEnt = xf86GetEntityInfo(usedChips[i]);;
ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, usedChips[i],
NULL, RES_SHARED_VGA,
NULL, NULL, NULL, NULL);
if (pScrn != NULL) {
SavagePtr psav;
pScrn->driverVersion = SAVAGE_VERSION;
pScrn->driverName = SAVAGE_DRIVER_NAME;
pScrn->name = "SAVAGE";
pScrn->Probe = SavageProbe;
pScrn->PreInit = SavagePreInit;
pScrn->ScreenInit = SavageScreenInit;
pScrn->SwitchMode = SavageSwitchMode;
pScrn->AdjustFrame = SavageAdjustFrame;
pScrn->EnterVT = SavageEnterVT;
pScrn->LeaveVT = SavageLeaveVT;
pScrn->FreeScreen = NULL;
pScrn->ValidMode = SavageValidMode;
foundScreen = TRUE;
if (!SavageGetRec(pScrn))
return FALSE;
psav = SAVPTR(pScrn);
psav->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
if (pEnt->device->chipset && *pEnt->device->chipset) {
psav->Chipset = xf86StringToToken(SavageChipsets,
pEnt->device->chipset);
} else if (pEnt->device->chipID >= 0) {
psav->Chipset = LookupChipID(SavagePciChipsets,
pEnt->device->chipID);
} else {
psav->Chipset = LookupChipID(SavagePciChipsets,
psav->PciInfo->chipType);
}
}
pEnt = xf86GetEntityInfo(usedChips[i]);
/* MX, IX, SuperSavage cards support Dual-Head, mark the entity as sharable*/
if(pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE)
{
DevUnion *pPriv;
SavageEntPtr pSavageEnt;
xf86SetEntitySharable(usedChips[i]);
if (gSavageEntityIndex == -1)
gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
pPriv = xf86GetEntityPrivate(pEnt->index,
gSavageEntityIndex);
if (!pPriv->ptr) {
int j;
int instance = xf86GetNumEntityInstances(pEnt->index);
for (j = 0; j < instance; j++)
xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
pSavageEnt = pPriv->ptr;
pSavageEnt->HasSecondary = FALSE;
} else {
pSavageEnt = pPriv->ptr;
pSavageEnt->HasSecondary = TRUE;
}
}
xfree(pEnt);
}
xfree(usedChips);
return foundScreen;
}
static int LookupChipID( PciChipsets* pset, int ChipID )
{
/* Is there a function to do this for me? */
while( pset->numChipset >= 0 )
{
if( pset->PCIid == ChipID )
return pset->numChipset;
pset++;
}
return -1;
}
#endif
static void SavageDoDDC(ScrnInfoPtr pScrn)
{
SavagePtr psav= SAVPTR(pScrn);
pointer ddc;
/* Do the DDC dance. */ /* S3/VIA's DDC code */
ddc = xf86LoadSubModule(pScrn, "ddc");
if (ddc) {
xf86LoaderReqSymLists(ddcSymbols, NULL);
switch( psav->Chipset ) {
case S3_SAVAGE3D:
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
case S3_SAVAGE2000:
psav->DDCPort = 0xAA;
psav->I2CPort = 0xA0;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_TWISTER:
case S3_PROSAVAGEDDR:
psav->DDCPort = 0xB1;
psav->I2CPort = 0xA0;
break;
}
if (!SavageDDC1(pScrn->scrnIndex)) {
/* DDC1 failed,switch to DDC2 */
if (xf86LoadSubModule(pScrn, "i2c")) {
xf86LoaderReqSymLists(i2cSymbols,NULL);
if (SavageI2CInit(pScrn)) {
unsigned char tmp;
xf86MonPtr pMon;
InI2CREG(tmp,psav->DDCPort);
OutI2CREG(tmp | 0x13,psav->DDCPort);
pMon = xf86PrintEDID(xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C));
if (!psav->IgnoreEDID) xf86SetDDCproperties(pScrn, pMon);
OutI2CREG(tmp,psav->DDCPort);
}
}
}
}
}
/* Copied from ddc/Property.c via nv */
static DisplayModePtr
SavageModesAdd(DisplayModePtr Modes, DisplayModePtr Additions)
{
if (!Modes) {
if (Additions)
return Additions;
else
return NULL;
}
if (Additions) {
DisplayModePtr Mode = Modes;
while (Mode->next)
Mode = Mode->next;
Mode->next = Additions;
Additions->prev = Mode;
}
return Modes;
}
/* borrowed from nv */
static void
SavageAddPanelMode(ScrnInfoPtr pScrn)
{
SavagePtr psav= SAVPTR(pScrn);
DisplayModePtr Mode = NULL;
Mode = xf86CVTMode(psav->PanelX, psav->PanelY, 60.00, TRUE, FALSE);
Mode->type = M_T_DRIVER | M_T_PREFERRED;
pScrn->monitor->Modes = SavageModesAdd(pScrn->monitor->Modes, Mode);
if ((pScrn->monitor->nHsync == 0) &&
(pScrn->monitor->nVrefresh == 0)) {
if (!Mode->HSync)
Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
if (!Mode->VRefresh)
Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
((float) (Mode->HTotal * Mode->VTotal));
if (Mode->HSync < pScrn->monitor->hsync[0].lo)
pScrn->monitor->hsync[0].lo = Mode->HSync;
if (Mode->HSync > pScrn->monitor->hsync[0].hi)
pScrn->monitor->hsync[0].hi = Mode->HSync;
if (Mode->VRefresh < pScrn->monitor->vrefresh[0].lo)
pScrn->monitor->vrefresh[0].lo = Mode->VRefresh;
if (Mode->VRefresh > pScrn->monitor->vrefresh[0].hi)
pScrn->monitor->vrefresh[0].hi = Mode->VRefresh;
pScrn->monitor->nHsync = 1;
pScrn->monitor->nVrefresh = 1;
}
}
static void SavageGetPanelInfo(ScrnInfoPtr pScrn)
{
SavagePtr psav= SAVPTR(pScrn);
vgaHWPtr hwp;
unsigned char cr6b;
int panelX, panelY;
char * sTechnology = "Unknown";
enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
ActiveCRT = 0x01,
ActiveLCD = 0x02,
ActiveTV = 0x04,
ActiveCRT2 = 0x20,
ActiveDUO = 0x80
};
hwp = VGAHWPTR(pScrn);
/* Check LCD panel information */
cr6b = hwp->readCrtc( hwp, 0x6b );
panelX = (hwp->readSeq(hwp, 0x61) +
((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
panelY = hwp->readSeq(hwp, 0x69) +
((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
/* OK, I admit it. I don't know how to limit the max dot clock
* for LCD panels of various sizes. I thought I copied the formula
* from the BIOS, but many users have informed me of my folly.
*
* Instead, I'll abandon any attempt to automatically limit the
* clock, and add an LCDClock option to XF86Config. Some day,
* I should come back to this.
*/
if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
{
sTechnology = "TFT";
}
else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
{
sTechnology = "DSTN";
}
else
{
sTechnology = "STN";
}
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"%dx%d %s LCD panel detected %s\n",
panelX, panelY, sTechnology,
cr6b & ActiveLCD ? "and active" : "but not active");
if( cr6b & ActiveLCD ) {
/* If the LCD is active and panel expansion is enabled, */
/* we probably want to kill the HW cursor. */
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"- Limiting video mode to %dx%d\n",
panelX, panelY );
psav->PanelX = panelX;
psav->PanelY = panelY;
do {
DisplayModePtr native = xf86CVTMode(panelX, panelY, 60.0, 0, 0);
if (!native)
break;
if (!pScrn->monitor->nHsync) {
pScrn->monitor->nHsync = 1;
pScrn->monitor->hsync[0].lo = 31.5;
pScrn->monitor->hsync[0].hi = (float)native->Clock /
(float)native->HTotal;
}
if (!pScrn->monitor->nVrefresh) {
pScrn->monitor->nVrefresh = 1;
pScrn->monitor->vrefresh[0].lo = 56.0;
pScrn->monitor->vrefresh[0].hi = (float)native->Clock * 1000.0 /
(float)native->HTotal /
(float)native->VTotal;
}
if (!pScrn->monitor->maxPixClock)
pScrn->monitor->maxPixClock = native->Clock;
xfree(native);
} while (0);
if( psav->LCDClock > 0.0 )
{
psav->maxClock = psav->LCDClock * 1000.0;
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"- Limiting dot clock to %1.2f MHz\n",
psav->LCDClock );
}
} else {
psav->DisplayType = MT_CRT;
}
}
static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags)
{
EntityInfoPtr pEnt;
SavagePtr psav;
MessageType from = X_DEFAULT;
int i;
ClockRangePtr clockRanges;
char *s = NULL;
unsigned char config1, m, n, n1, n2, sr8, cr66 = 0, tmp;
int mclk;
vgaHWPtr hwp;
int vgaCRIndex, vgaCRReg;
Bool dvi;
TRACE(("SavagePreInit(%d)\n", flags));
gpScrn = pScrn;
if (flags & PROBE_DETECT) {
SavageProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
return TRUE;
}
if (!xf86LoadSubModule(pScrn, "vgahw"))
return FALSE;
xf86LoaderReqSymLists(vgaHWSymbols, NULL);
if (!vgaHWGetHWRec(pScrn))
return FALSE;
#if 0
/* Here we can alter the number of registers saved and restored by the
* standard vgaHWSave and Restore routines.
*/
vgaHWSetRegCounts( pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX, VGA_NUM_ATTR );
#endif
pScrn->monitor = pScrn->confScreen->monitor;
/*
* We support depths of 8, 15, 16 and 24.
* We support bpp of 8, 16, and 32.
*/
if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
return FALSE;
else {
int requiredBpp;
int altBpp = 0;
switch (pScrn->depth) {
case 8:
case 16:
requiredBpp = pScrn->depth;
break;
case 15:
requiredBpp = 16;
break;
case 24:
requiredBpp = 32;
altBpp = 24;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Given depth (%d) is not supported by this driver\n",
pScrn->depth);
return FALSE;
}
if(
(pScrn->bitsPerPixel != requiredBpp) &&
(pScrn->bitsPerPixel != altBpp)
) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Depth %d must specify %d bpp; %d was given\n",
pScrn->depth, requiredBpp, pScrn->bitsPerPixel );
return FALSE;
}
}
xf86PrintDepthBpp(pScrn);
if (pScrn->depth > 8) {
rgb zeros = {0, 0, 0};
if (!xf86SetWeight(pScrn, zeros, zeros))
return FALSE;
else {
/* TODO check weight returned is supported */
;
}
}
if (!xf86SetDefaultVisual(pScrn, -1)) {
return FALSE;
} else {
/* We don't currently support DirectColor at 16bpp */
if (pScrn->bitsPerPixel == 16 && 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;
}
}
pScrn->progClock = TRUE;
if (!SavageGetRec(pScrn))
return FALSE;
psav = SAVPTR(pScrn);
hwp = VGAHWPTR(pScrn);
vgaHWGetIOBase(hwp);
psav->vgaIOBase = hwp->IOBase;
xf86CollectOptions(pScrn, NULL);
if (pScrn->depth == 8)
pScrn->rgbBits = 8;
if (!(psav->Options = xalloc(sizeof(SavageOptions))))
return FALSE;
memcpy(psav->Options, SavageOptions, sizeof(SavageOptions));
xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, psav->Options);
xf86GetOptValBool(psav->Options, OPTION_IGNORE_EDID, &psav->IgnoreEDID);
xf86GetOptValBool(psav->Options, OPTION_PCI_BURST, &psav->pci_burst);
if (psav->pci_burst) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Option: pci_burst - PCI burst read enabled\n");
}
psav->NoPCIRetry = 1; /* default */
if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_RETRY, FALSE)) {
if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_BURST, FALSE)) {
psav->NoPCIRetry = 0;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
} else
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires \"pci_burst\"\n");
}
xf86GetOptValBool( psav->Options, OPTION_SHADOW_FB, &psav->shadowFB );
if (psav->shadowFB) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: shadow FB enabled\n");
}
psav->primStreamBpp = pScrn->bitsPerPixel;
if ((s = xf86GetOptValString(psav->Options, OPTION_ROTATE))) {
if(!xf86NameCmp(s, "CW")) {
/* accel is disabled below for shadowFB */
/* RandR is disabled when the Rotate option is used (does
* not work well together and scrambles the screen) */
psav->shadowFB = TRUE;
psav->rotate = 1;
xf86DisableRandR();
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Rotating screen clockwise"
"- acceleration and RandR disabled\n");
} else if(!xf86NameCmp(s, "CCW")) {
psav->shadowFB = TRUE;
psav->rotate = -1;
xf86DisableRandR();
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Rotating screen counter clockwise"
" - acceleration and RandR disabled\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
"value for Option \"Rotate\"\n", s);
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Valid options are \"CW\" or \"CCW\"\n");
}
}
if (xf86GetOptValBool(psav->Options, OPTION_NOACCEL, &psav->NoAccel))
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"Option: NoAccel - Acceleration Disabled\n");
if (psav->shadowFB && !psav->NoAccel) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"HW acceleration not supported with \"shadowFB\".\n");
psav->NoAccel = TRUE;
}
if(!psav->NoAccel) {
from = X_DEFAULT;
char *strptr;
if((strptr = (char *)xf86GetOptValString(psav->Options, OPTION_ACCELMETHOD))) {
if(!xf86NameCmp(strptr,"XAA")) {
from = X_CONFIG;
psav->useEXA = FALSE;
} else if(!xf86NameCmp(strptr,"EXA")) {
from = X_CONFIG;
psav->useEXA = TRUE;
}
}
xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
psav->useEXA ? "EXA" : "XAA");
}
if ((s = xf86GetOptValString(psav->Options, OPTION_OVERLAY))) {
if (psav->shadowFB) {
xf86DrvMsg(pScrn->scrnIndex,X_INFO,
"Option \"Overlay\" not supported with shadowFB\n");
} else {
if (pScrn->depth == 8) {
if (!*s || !xf86NameCmp(s, "24")) {
psav->overlayDepth = 24;
psav->NoAccel = TRUE; /* Preliminary */
pScrn->colorKey = TRANSPARENCY_KEY;
pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
} else if (!xf86NameCmp(s, "16")) {
psav->overlayDepth = 16;
psav->NoAccel = TRUE; /* Preliminary */
pScrn->colorKey = TRANSPARENCY_KEY;
pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
} else {
xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
"\"%s\" Ingnoring\n",s);
}
} else if (pScrn->depth != 15) {
psav->overlayDepth = 8;
psav->NoAccel = TRUE; /* Preliminary */
pScrn->colorKey = TRANSPARENCY_KEY;
pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
if (*s && (xf86NameCmp(s, "8")))
xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
"\"%s\" for depth %i overlay depth must be 8\n",
s,pScrn->depth);
} else {
xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Overlay not "
"supported for depth 15\n");
}
if (psav->overlayDepth) {
xf86DrvMsg(pScrn->scrnIndex,X_INFO,"%i/%i Overlay enabled\n",
pScrn->depth,psav->overlayDepth);
psav->primStreamBpp = 8;
}
}
}
if (pScrn->bitsPerPixel == 24 && !psav->NoAccel) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"HW acceleration not possible with depth 32 and bpp 24.\n");
psav->NoAccel = TRUE;
}
/*
* The SWCursor setting takes priority over HWCursor. The default
* if neither is specified is HW, unless ShadowFB is specified,
* then SW.
*/
from = X_DEFAULT;
psav->hwcursor = psav->shadowFB ? FALSE : TRUE;
if (xf86GetOptValBool(psav->Options, OPTION_HWCURSOR, &psav->hwcursor))
from = X_CONFIG;
if (xf86ReturnOptValBool(psav->Options, OPTION_SWCURSOR, FALSE)) {
psav->hwcursor = FALSE;
from = X_CONFIG;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
psav->hwcursor ? "HW" : "SW");
from = X_DEFAULT;
psav->UseBIOS = TRUE;
if (xf86GetOptValBool(psav->Options, OPTION_USEBIOS, &psav->UseBIOS) )
from = X_CONFIG;
xf86DrvMsg(pScrn->scrnIndex, from, "%ssing video BIOS to set modes\n",
psav->UseBIOS ? "U" : "Not u" );
psav->LCDClock = 0.0;
if( xf86GetOptValFreq( psav->Options, OPTION_LCDCLOCK, OPTUNITS_MHZ, &psav->LCDClock ) )
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"Option: LCDClock %1.2f MHz\n", psav->LCDClock );
if( xf86GetOptValBool( psav->Options, OPTION_SHADOW_STATUS, &psav->ShadowStatus)) {
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"Option: ShadowStatus %sabled\n", psav->ShadowStatus ? "en" : "dis" );
psav->ForceShadowStatus = TRUE;
} else
psav->ForceShadowStatus = FALSE;
/* If ShadowStatus is off it will be automatically enabled for DRI.
* If DRI initialization fails fall back to ConfigShadowStatus. */
psav->ConfigShadowStatus = psav->ShadowStatus;
if( xf86GetOptValBool( psav->Options, OPTION_CRT_ONLY, &psav->CrtOnly))
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"Option: CrtOnly enabled\n" );
if( xf86GetOptValBool( psav->Options, OPTION_TV_ON, &psav->TvOn)) {
psav->PAL = FALSE;
SavageGetTvMaxSize(psav);
}
if( xf86GetOptValBool( psav->Options, OPTION_TV_PAL, &psav->PAL)) {
SavageGetTvMaxSize(psav);
psav->TvOn = TRUE;
}
if( psav->TvOn )
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"TV enabled in %s format\n",
psav->PAL ? "PAL" : "NTSC" );
psav->ForceInit = 0;
if( xf86GetOptValBool( psav->Options, OPTION_FORCE_INIT, &psav->ForceInit))
xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
"Option: ForceInit enabled\n" );
if (pScrn->numEntities > 1) {
SavageFreeRec(pScrn);
return FALSE;
}
pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
if (pEnt->resources) {
xfree(pEnt);
SavageFreeRec(pScrn);
return FALSE;
}
psav->EntityIndex = pEnt->index;
if (xf86LoadSubModule(pScrn, "vbe")) {
xf86LoaderReqSymLists(vbeSymbols, NULL);
psav->pVbe = VBEInit(NULL, pEnt->index);
}
xf86RegisterResources(pEnt->index, NULL, ResNone);
xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
from = X_DEFAULT;
if (pEnt->device->chipset && *pEnt->device->chipset) {
pScrn->chipset = pEnt->device->chipset;
psav->ChipId = pEnt->device->chipID;
from = X_CONFIG;
} else if (pEnt->device->chipID >= 0) {
psav->ChipId = pEnt->device->chipID;
pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
psav->Chipset);
from = X_CONFIG;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
pEnt->device->chipID);
} else {
from = X_PROBED;
psav->ChipId = DEVICE_ID(psav->PciInfo);
pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
psav->Chipset);
}
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chip: id %04x, \"%s\"\n",
psav->ChipId, xf86TokenToString( SavageChips, psav->ChipId ) );
if (pEnt->device->chipRev >= 0) {
psav->ChipRev = pEnt->device->chipRev;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
psav->ChipRev);
} else
psav->ChipRev = CHIP_REVISION(psav->PciInfo);
xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
if (pEnt->device->videoRam != 0)
pScrn->videoRam = pEnt->device->videoRam;
xfree(pEnt);
#ifndef XSERVER_LIBPCIACCESS
psav->PciTag = pciTag(psav->PciInfo->bus, psav->PciInfo->device,
psav->PciInfo->func);
#endif
/* Set AGP Mode from config */
/* We support 1X 2X and 4X */
#ifdef XF86DRI
#ifdef XSERVER_LIBPCIACCESS
/* Try to read the AGP capabilty block from the device. If there is
* no AGP info, the device is PCI.
*/
psav->IsPCI = (pci_device_get_agp_info(psav->PciInfo) == NULL);
#else
/* AGP/PCI (FK: copied from radeon_driver.c) */
/* Proper autodetection of an AGP capable device requires examining
* PCI config registers to determine if the device implements extended
* PCI capabilities, and then walking the capability list as indicated
* in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP
* capability is present. The procedure is outlined as follows:
*
* 1) Test bit 4 (CAP_LIST) of the PCI status register of the device
* to determine wether or not this device implements any extended
* capabilities. If this bit is zero, then the device is a PCI 2.1
* or earlier device and is not AGP capable, and we can conclude it
* to be a PCI device.
*
* 2) If bit 4 of the status register is set, then the device implements
* extended capabilities. There is an 8 bit wide capabilities pointer
* register located at offset 0x34 in PCI config space which points to
* the first capability in a linked list of extended capabilities that
* this device implements. The lower two bits of this register are
* reserved and MBZ so must be masked out.
*
* 3) The extended capabilities list is formed by one or more extended
* capabilities structures which are aligned on DWORD boundaries.
* The first byte of the structure is the capability ID (CAP_ID)
* indicating what extended capability this structure refers to. The
* second byte of the structure is an offset from the beginning of
* PCI config space pointing to the next capability in the linked
* list (NEXT_PTR) or NULL (0x00) at the end of the list. The lower
* two bits of this pointer are reserved and MBZ. By examining the
* CAP_ID of each capability and walking through the list, we will
* either find the AGP_CAP_ID (0x02) indicating this device is an
* AGP device, or we'll reach the end of the list, indicating it is
* a PCI device.
*
* Mike A. Harris <mharris@redhat.com>
*
* References:
* - PCI Local Bus Specification Revision 2.2, Chapter 6
* - AGP Interface Specification Revision 2.0, Section 6.1.5
*/
psav->IsPCI = TRUE;
if (pciReadLong(psav->PciTag, PCI_CMD_STAT_REG) & SAVAGE_CAP_LIST) {
CARD32 cap_ptr, cap_id;
cap_ptr = pciReadLong(psav->PciTag,
SAVAGE_CAPABILITIES_PTR_PCI_CONFIG)
& SAVAGE_CAP_PTR_MASK;
while(cap_ptr != SAVAGE_CAP_ID_NULL) {
cap_id = pciReadLong(psav->PciTag, cap_ptr);
if ((cap_id & 0xff) == SAVAGE_CAP_ID_AGP) {
psav->IsPCI = FALSE;
break;
}
cap_ptr = (cap_id >> 8) & SAVAGE_CAP_PTR_MASK;
}
}
#endif
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%s card detected\n",
(psav->IsPCI) ? "PCI" : "AGP");
if ((s = xf86GetOptValString(psav->Options, OPTION_BUS_TYPE))) {
if (strcmp(s, "AGP") == 0) {
if (psav->IsPCI) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"BusType AGP not available on PCI card\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to AGP\n");
}
} else if (strcmp(s, "PCI") == 0) {
psav->IsPCI = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to PCI\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Invalid BusType option, using %s DMA\n",
psav->IsPCI ? "PCI" : "AGP");
}
}
psav->AgpDMA = !psav->IsPCI;
if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_TYPE))) {
if (strcmp(s, "AGP") == 0) {
if (psav->IsPCI) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"AGP DMA not available on PCI card, using PCI DMA\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using AGP DMA\n");
}
} else if (strcmp(s, "PCI") == 0) {
psav->AgpDMA = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using PCI DMA\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
"Invalid DmaType option, using %s DMA\n",
psav->AgpDMA ? "AGP" : "PCI");
}
} else {
xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
"Using %s DMA\n", psav->AgpDMA ? "AGP" : "PCI");
}
psav->CommandDMA = TRUE;
psav->VertexDMA = TRUE;
from = X_DEFAULT;
if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_MODE))) {
from = X_CONFIG;
if (strcmp(s, "Command") == 0)
psav->VertexDMA = FALSE;
else if (strcmp(s, "Vertex") == 0)
psav->CommandDMA = FALSE;
else if (strcmp(s, "None") == 0)
psav->VertexDMA = psav->CommandDMA = FALSE;
else if (strcmp(s, "Any") != 0) {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid DmaMode option\n");
from = X_DEFAULT;
}
}
if (psav->CommandDMA && S3_SAVAGE3D_SERIES(psav->Chipset)) {
xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
"Savage3D/MX/IX does not support command DMA.\n");
psav->CommandDMA = FALSE;
}
if ((psav->CommandDMA || psav->VertexDMA) &&
psav->Chipset == S3_SUPERSAVAGE) {
xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
"DMA is not supported on SuperSavages.\n");
psav->CommandDMA = psav->VertexDMA = FALSE;
}
if (psav->CommandDMA && psav->VertexDMA)
xf86DrvMsg(pScrn->scrnIndex, from,
"Will try command and vertex DMA mode\n");
else if (psav->CommandDMA && !psav->VertexDMA)
xf86DrvMsg(pScrn->scrnIndex, from,
"Will try only command DMA mode\n");
else if (!psav->CommandDMA && psav->VertexDMA)
xf86DrvMsg(pScrn->scrnIndex, from,
"Will try only vertex DMA mode\n");
else
xf86DrvMsg(pScrn->scrnIndex, from,
"DMA disabled\n");
if (!psav->IsPCI) {
from = X_DEFAULT;
psav->agpMode = SAVAGE_DEFAULT_AGP_MODE;
/*psav->agpMode = SAVAGE_MAX_AGP_MODE;*/
psav->agpSize = 16;
if (xf86GetOptValInteger(psav->Options,
OPTION_AGP_MODE, &(psav->agpMode))) {
if (psav->agpMode < 1) {
psav->agpMode = 1;
}
if (psav->agpMode > SAVAGE_MAX_AGP_MODE) {
psav->agpMode = SAVAGE_MAX_AGP_MODE;
}
if ((psav->agpMode > 2) &&
(psav->Chipset == S3_SAVAGE3D ||
psav->Chipset == S3_SAVAGE_MX))
psav->agpMode = 2; /* old savages only support 2x */
from = X_CONFIG;
}
xf86DrvMsg(pScrn->scrnIndex, from, "Using AGP %dx mode\n",
psav->agpMode);
from = X_DEFAULT;
if (xf86GetOptValInteger(psav->Options,
OPTION_AGP_SIZE, (int *)&(psav->agpSize))) {
switch (psav->agpSize) {
case 4:
case 8:
case 16:
case 32:
case 64:
case 128:
case 256:
from = X_CONFIG;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Illegal AGP size: %d MB, defaulting to 16 MB\n", psav->agpSize);
psav->agpSize = 16;
}
}
xf86DrvMsg(pScrn->scrnIndex, from,
"Using %d MB AGP aperture\n", psav->agpSize);
} else {
psav->agpMode = 0;
psav->agpSize = 0;
}
#endif
/* we can use Option "DisableTile TRUE" to disable tile mode */
psav->bDisableTile = FALSE;
if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_TILE,&psav->bDisableTile)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Option: %s Tile Mode and Program it \n",(psav->bDisableTile?"Disable":"Enable"));
}
#ifdef XF86DRI
/* disabled by default...doesn't seem to work */
psav->bDisableXvMC = TRUE; /* if you want to free up more mem for DRI,etc. */
if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_XVMC, &psav->bDisableXvMC)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Option: %s Hardware XvMC support\n",(psav->bDisableXvMC?"Disable":"Enable"));
}
#endif
psav->disableCOB = FALSE; /* if you are having problems on savage4+ */
if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_COB, &psav->disableCOB)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Option: %s the COB\n",(psav->disableCOB?"Disable":"Enable"));
}
if (psav->Chipset == S3_PROSAVAGE ||
psav->Chipset == S3_TWISTER ||
psav->Chipset == S3_PROSAVAGEDDR)
psav->BCIforXv = TRUE;
else
psav->BCIforXv = FALSE; /* use the BCI for Xv */
if (xf86GetOptValBool(psav->Options, OPTION_BCI_FOR_XV, &psav->BCIforXv)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"Option: %s use of the BCI for Xv\n",(psav->BCIforXv?"Enable":"Disable"));
}
psav->dvi = FALSE;
if (xf86GetOptValBool(psav->Options, OPTION_DVI, &psav->dvi)) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"%s DVI port support (Savage4 only)\n",(psav->dvi?"Force":"Disable"));
}
/* Add more options here. */
psav = SAVPTR(pScrn);
psav->IsSecondary = FALSE;
psav->IsPrimary = FALSE;
psav->pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
if (xf86IsEntityShared(psav->pEnt->index)) {
if (xf86IsPrimInitDone(psav->pEnt->index)) {
SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
psav->IsSecondary = TRUE;
pSavageEnt->pSecondaryScrn = pScrn;
psav->TvOn = pSavageEnt->TvOn;
} else {
SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
xf86SetPrimInitDone(psav->pEnt->index);
psav->IsPrimary = TRUE;
pSavageEnt->pPrimaryScrn = pScrn;
pSavageEnt->TvOn = psav->TvOn;
}
}
switch(psav->Chipset) {
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
psav->HasCRTC2 = TRUE;
break;
default:
psav->HasCRTC2 = FALSE;
}
if ((psav->IsSecondary || psav->IsPrimary) && !psav->UseBIOS) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "BIOS currently required for Dualhead mode setting.\n");
return FALSE;
}
if (psav->IsSecondary &&
(pScrn->bitsPerPixel > 16) &&
!psav->NoAccel &&
(psav->Chipset == S3_SAVAGE_MX)) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No acceleration in Dualhead mode at depth 24\n");
return FALSE;
}
/* maybe throw in some more sanity checks here */
if (!SavageMapMem(pScrn)) {
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
vgaCRIndex = psav->vgaIOBase + 4;
vgaCRReg = psav->vgaIOBase + 5;
xf86EnableIO();
/* unprotect CRTC[0-7] */
VGAOUT8(vgaCRIndex, 0x11);
tmp = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, tmp & 0x7f);
/* unlock extended regs */
VGAOUT16(vgaCRIndex, 0x4838);
VGAOUT16(vgaCRIndex, 0xa039);
VGAOUT16(0x3c4, 0x0608);
VGAOUT8(vgaCRIndex, 0x40);
tmp = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, tmp & ~0x01);
/* unlock sys regs */
VGAOUT8(vgaCRIndex, 0x38);
VGAOUT8(vgaCRReg, 0x48);
{
Gamma zeros = {0.0, 0.0, 0.0};
if (!xf86SetGamma(pScrn, zeros)) {
vbeFree(psav->pVbe);
psav->pVbe = NULL;
SavageFreeRec(pScrn);
return FALSE;
}
}
/* Unlock system registers. */
VGAOUT16(vgaCRIndex, 0x4838);
/* Next go on to detect amount of installed ram */
VGAOUT8(vgaCRIndex, 0x36); /* for register CR36 (CONFG_REG1), */
config1 = VGAIN8(vgaCRReg); /* get amount of vram installed */
/* Compute the amount of video memory and offscreen memory. */
if (!pScrn->videoRam) {
static const unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
static const unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
static const unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
switch( psav->Chipset ) {
case S3_SAVAGE3D:
pScrn->videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
break;
case S3_SAVAGE4:
/*
* The Savage4 has one ugly special case to consider. On
* systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
* when it really means 8MB. Why do it the same when you
* can do it different...
*/
VGAOUT8(vgaCRIndex, 0x68); /* memory control 1 */
if( (VGAIN8(vgaCRReg) & 0xC0) == (0x01 << 6) )
RamSavage4[1] = 8;
/*FALLTHROUGH*/
case S3_SAVAGE2000:
pScrn->videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
break;
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
pScrn->videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
break;
case S3_PROSAVAGE:
case S3_PROSAVAGEDDR:
case S3_TWISTER:
pScrn->videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
break;
default:
/* How did we get here? */
pScrn->videoRam = 0;
break;
}
psav->videoRambytes = pScrn->videoRam * 1024;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"probed videoram: %dk\n",
pScrn->videoRam);
} else {
psav->videoRambytes = pScrn->videoRam * 1024;
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
"videoram = %dk\n",
pScrn->videoRam);
}
/* Get video RAM */
if( !pScrn->videoRam && psav->pVbe )
{
/* If VBE is available, ask it about onboard memory. */
VbeInfoBlock* vib;
vib = VBEGetVBEInfo( psav->pVbe );
pScrn->videoRam = vib->TotalMemory * 64;
VBEFreeVBEInfo( vib );
/* VBE often cuts 64k off of the RAM total. */
if( pScrn->videoRam & 64 )
pScrn->videoRam += 64;
psav->videoRambytes = pScrn->videoRam * 1024;
}
/*
* If we're running with acceleration, compute the command overflow
* buffer location. The command overflow buffer must END at a
* 4MB boundary; for all practical purposes, that means the very
* end of the frame buffer.
*/
if (psav->NoAccel) {
psav->cobIndex = 0;
psav->cobSize = 0;
}
else if( ((S3_SAVAGE4_SERIES(psav->Chipset)) ||
(S3_SUPERSAVAGE == psav->Chipset)) && psav->disableCOB ) {
/*
* The Savage4 and ProSavage have COB coherency bugs which render
* the buffer useless.
*/
/*
psav->cobIndex = 2;
psav->cobSize = 0x8000 << psav->cobIndex;
*/
psav->cobIndex = 0;
psav->cobSize = 0;
psav->bciThresholdHi = 32;
psav->bciThresholdLo = 0;
} else {
/* We use 128kB for the COB on all other chips. */
psav->cobSize = 0x20000;
if (S3_SAVAGE3D_SERIES(psav->Chipset) ||
psav->Chipset == S3_SAVAGE2000) {
psav->cobIndex = 7; /* rev.A savage4 apparently also uses 7 */
} else {
psav->cobIndex = 2;
}
/* max command size: 2560 entries */
psav->bciThresholdHi = psav->cobSize/4 + 32 - 2560;
psav->bciThresholdLo = psav->bciThresholdHi - 2560;
}
/* align cob to 128k */
psav->cobOffset = (psav->videoRambytes - psav->cobSize) & ~0x1ffff;
/* The cursor must be aligned on a 4k boundary. */
psav->CursorKByte = (psav->cobOffset >> 10) - 4;
psav->endfb = (psav->CursorKByte << 10) - 1;
if (psav->IsPrimary) {
pScrn->videoRam /= 2;
psav->videoRambytes = pScrn->videoRam * 1024;
psav->CursorKByte = (psav->videoRambytes >> 10) - 4;
psav->endfb = (psav->CursorKByte << 10) - 1;
psav->videoRambytes *= 2;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Using %dk of videoram for primary head\n",
pScrn->videoRam);
}
if(psav->IsSecondary)
{
pScrn->videoRam /= 2;
/*psav->videoRambytes = pScrn->videoRam * 1024;*/
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Using %dk of videoram for secondary head\n",
pScrn->videoRam);
}
pScrn->fbOffset = (psav->IsSecondary)
? pScrn->videoRam * 1024 : 0;
/* reset graphics engine to avoid memory corruption */
VGAOUT8(vgaCRIndex, 0x66);
cr66 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr66 | 0x02);
usleep(10000);
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, cr66 & ~0x02); /* clear reset flag */
usleep(10000);
/* Set status word positions based on chip type. */
SavageInitStatus(pScrn);
/* check for DVI/flat panel */
dvi = FALSE;
if (psav->Chipset == S3_SAVAGE4) {
unsigned char sr30 = 0x00;
VGAOUT8(0x3c4, 0x30);
/* clear bit 1 */
VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x02);
sr30 = VGAIN8(0x3c5);
if (sr30 & 0x02 /*0x04 */) {
dvi = TRUE;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Digital Flat Panel Detected\n");
}
}
if( (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
S3_MOBILE_TWISTER_SERIES(psav->Chipset)) && !psav->CrtOnly ) {
psav->DisplayType = MT_LCD;
} else if (dvi || ((psav->Chipset == S3_SAVAGE4) && psav->dvi)) {
psav->DisplayType = MT_DFP;
} else {
psav->DisplayType = MT_CRT;
}
if (psav->IsSecondary)
psav->DisplayType = MT_CRT;
/* Do the DDC dance. */
SavageDoDDC(pScrn);
/* set up ramdac max clock - might be altered by SavageGetPanelInfo */
if (pScrn->bitsPerPixel >= 24)
psav->maxClock = 220000;
else
psav->maxClock = 250000;
/* detect current mclk */
VGAOUT8(0x3c4, 0x08);
sr8 = VGAIN8(0x3c5);
VGAOUT8(0x3c5, 0x06);
VGAOUT8(0x3c4, 0x10);
n = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x11);
m = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x08);
VGAOUT8(0x3c5, sr8);
m &= 0x7f;
n1 = n & 0x1f;
n2 = (n >> 5) & 0x03;
mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
mclk / 1000.0);
pScrn->maxHValue = 2048 << 3; /* 11 bits of h_total 8-pixel units */
pScrn->maxVValue = 2048; /* 11 bits of v_total */
pScrn->virtualX = pScrn->display->virtualX;
pScrn->virtualY = pScrn->display->virtualY;
/* Check LCD panel information */
if(psav->DisplayType == MT_LCD)
{
SavageGetPanelInfo(pScrn);
SavageAddPanelMode(pScrn);
}
#if 0
if (psav->CrtOnly && !psav->UseBIOS) {
VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10); /* disable FP */
if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) /*||
S3_MOBILE_TWISTER_SERIES(psav->Chipset)*/) { /* not sure this works on mobile prosavage */
VGAOUT8(0x3c4, 0x31);
VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x04); /* make sure crtc1 is crt source */
}
}
#endif
if( psav->UseBIOS )
{
/* Go probe the BIOS for all the modes and refreshes at this depth. */
if( psav->ModeTable )
{
SavageFreeBIOSModeTable( psav, &psav->ModeTable );
}
psav->ModeTable = SavageGetBIOSModeTable( psav, psav->primStreamBpp );
if( !psav->ModeTable || !psav->ModeTable->NumModes ) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Failed to fetch any BIOS modes. Disabling BIOS.\n");
psav->UseBIOS = FALSE;
}
else
/*if( xf86Verbose )*/
{
SavageModeEntryPtr pmt;
xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
"Found %d modes at this depth:\n",
psav->ModeTable->NumModes);
for(
i = 0, pmt = psav->ModeTable->Modes;
i < psav->ModeTable->NumModes;
i++, pmt++ )
{
int j;
ErrorF( " [%03x] %d x %d",
pmt->VesaMode, pmt->Width, pmt->Height );
for( j = 0; j < pmt->RefreshCount; j++ )
{
ErrorF( ", %dHz", pmt->RefreshRate[j] );
}
ErrorF( "\n");
}
}
}
clockRanges = xnfalloc(sizeof(ClockRange));
clockRanges->next = NULL;
clockRanges->minClock = 10000;
clockRanges->maxClock = psav->maxClock;
clockRanges->clockIndex = -1;
clockRanges->interlaceAllowed = TRUE;
clockRanges->doubleScanAllowed = TRUE;
clockRanges->ClockDivFactor = 1.0;
clockRanges->ClockMulFactor = 1.0;
i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
pScrn->display->modes, clockRanges, NULL,
256, 2048, 16 * pScrn->bitsPerPixel,
128, 2048,
pScrn->virtualX, pScrn->virtualY,
psav->videoRambytes, LOOKUP_BEST_REFRESH);
if (i == -1) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
xf86PruneDriverModes(pScrn);
if (i == 0 || pScrn->modes == NULL) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
pScrn->currentMode = pScrn->modes;
xf86PrintModes(pScrn);
xf86SetDpi(pScrn, 0, 0);
if (xf86LoadSubModule(pScrn, "fb") == NULL) {
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
xf86LoaderReqSymLists(fbSymbols, NULL);
if( !psav->NoAccel ) {
char *modName = NULL;
const char **symNames = NULL;
if (psav->useEXA) {
modName = "exa";
symNames = exaSymbols;
XF86ModReqInfo req;
int errmaj, errmin;
memset(&req, 0, sizeof(req));
req.majorversion = 2;
req.minorversion = 0;
if( !LoadSubModule(pScrn->module, modName,
NULL, NULL, NULL, &req, &errmaj, &errmin) ) {
LoaderErrorMsg(NULL, modName, errmaj, errmin);
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
} else {
modName = "xaa";
symNames = xaaSymbols;
if( !xf86LoadSubModule(pScrn, modName) ) {
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
}
xf86LoaderReqSymLists(symNames, NULL );
}
if (psav->hwcursor) {
if (!xf86LoadSubModule(pScrn, "ramdac")) {
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
xf86LoaderReqSymLists(ramdacSymbols, NULL);
}
if (psav->shadowFB) {
if (!xf86LoadSubModule(pScrn, "shadowfb")) {
SavageFreeRec(pScrn);
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return FALSE;
}
xf86LoaderReqSymLists(shadowSymbols, NULL);
}
vbeFree(psav->pVbe);
psav->pVbe = NULL;
return TRUE;
}
static Bool SavageEnterVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
#ifdef XF86DRI
SavagePtr psav= SAVPTR(pScrn);
ScreenPtr pScreen;
SAVAGESAREAPrivPtr pSAREAPriv;
#endif
TRACE(("SavageEnterVT(%d)\n", flags));
gpScrn = pScrn;
SavageEnableMMIO(pScrn);
#ifdef XF86DRI
if (psav->directRenderingEnabled) {
pScreen = screenInfo.screens[scrnIndex];
pSAREAPriv = (SAVAGESAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
/* Assume that 3D state was clobbered, invalidate it by
* changing ctxOwner in the sarea. */
pSAREAPriv->ctxOwner = DRIGetContext(pScreen);
DRIUnlock(pScreen);
psav->LockHeld = 0;
}
#endif
if (!SAVPTR(pScrn)->IsSecondary)
SavageSave(pScrn);
if(SavageModeInit(pScrn, pScrn->currentMode)) {
/* some BIOSes seem to enable HW cursor on PM resume */
if (!SAVPTR(pScrn)->hwc_on)
SavageHideCursor( pScrn );
return TRUE;
}
return FALSE;
}
static void SavageLeaveVT(int scrnIndex, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
vgaRegPtr vgaSavePtr = &hwp->SavedReg;
SavageRegPtr SavageSavePtr = &psav->SavedReg;
#ifdef XF86DRI
ScreenPtr pScreen;
#endif
TRACE(("SavageLeaveVT(%d)\n", flags));
gpScrn = pScrn;
#ifdef XF86DRI
if (psav->directRenderingEnabled) {
pScreen = screenInfo.screens[scrnIndex];
DRILock(pScreen, 0);
psav->LockHeld = 1;
}
#endif
if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
SavageStreamsOff(pScrn);
SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
SavageResetStreams(pScrn);
SavageDisableMMIO(pScrn);
}
static void SavageSave(ScrnInfoPtr pScrn)
{
unsigned char cr3a, cr53, cr66;
vgaHWPtr hwp = VGAHWPTR(pScrn);
vgaRegPtr vgaSavePtr = &hwp->SavedReg;
SavagePtr psav = SAVPTR(pScrn);
SavageRegPtr save = &psav->SavedReg;
unsigned short vgaCRReg = psav->vgaIOBase + 5;
unsigned short vgaCRIndex = psav->vgaIOBase + 4;
TRACE(("SavageSave()\n"));
VGAOUT16(vgaCRIndex, 0x4838);
VGAOUT16(vgaCRIndex, 0xa039);
VGAOUT16(0x3c4, 0x0608);
VGAOUT8(vgaCRIndex, 0x66);
cr66 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr66 | 0x80);
VGAOUT8(vgaCRIndex, 0x3a);
cr3a = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr3a | 0x80);
VGAOUT8(vgaCRIndex, 0x53);
cr53 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr53 & 0x7f);
if (xf86IsPrimaryPci(psav->PciInfo))
vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
else
vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, cr66);
VGAOUT8(vgaCRIndex, 0x3a);
VGAOUT8(vgaCRReg, cr3a);
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, cr66);
VGAOUT8(vgaCRIndex, 0x3a);
VGAOUT8(vgaCRReg, cr3a);
/* unlock extended seq regs */
VGAOUT8(0x3c4, 0x08);
save->SR08 = VGAIN8(0x3c5);
VGAOUT8(0x3c5, 0x06);
/* now save all the extended regs we need */
VGAOUT8(vgaCRIndex, 0x31);
save->CR31 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x32);
save->CR32 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x34);
save->CR34 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x36);
save->CR36 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x3a);
save->CR3A = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x40);
save->CR40 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x42);
save->CR42 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x45);
save->CR45 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x50);
save->CR50 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x51);
save->CR51 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x53);
save->CR53 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x58);
save->CR58 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x60);
save->CR60 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x66);
save->CR66 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x67);
save->CR67 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x68);
save->CR68 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x69);
save->CR69 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x6f);
save->CR6F = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x33);
save->CR33 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x86);
save->CR86 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x88);
save->CR88 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x90);
save->CR90 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x91);
save->CR91 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0xb0);
save->CRB0 = VGAIN8(vgaCRReg) | 0x80;
/* extended mode timing regs */
VGAOUT8(vgaCRIndex, 0x3b);
save->CR3B = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x3c);
save->CR3C = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x43);
save->CR43 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x5d);
save->CR5D = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x5e);
save->CR5E = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x65);
save->CR65 = VGAIN8(vgaCRReg);
/* save seq extended regs for DCLK PLL programming */
VGAOUT8(0x3c4, 0x0e);
save->SR0E = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x0f);
save->SR0F = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x10);
save->SR10 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x11);
save->SR11 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x12);
save->SR12 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x13);
save->SR13 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x29);
save->SR29 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x15);
save->SR15 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x30);
save->SR30 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x18);
save->SR18 = VGAIN8(0x3c5);
VGAOUT8(0x3c4, 0x1b);
save->SR1B = VGAIN8(0x3c5);
/* Save flat panel expansion registers. */
if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
int i;
for( i = 0; i < 8; i++ ) {
VGAOUT8(0x3c4, 0x54+i);
save->SR54[i] = VGAIN8(0x3c5);
}
}
VGAOUT8(vgaCRIndex, 0x66);
cr66 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr66 | 0x80);
VGAOUT8(vgaCRIndex, 0x3a);
cr3a = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr3a | 0x80);
/* now save MIU regs */
if( ! S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
save->MMPR0 = INREG(FIFO_CONTROL_REG);
save->MMPR1 = INREG(MIU_CONTROL_REG);
save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
save->MMPR3 = INREG(MISC_TIMEOUT_REG);
}
VGAOUT8(vgaCRIndex, 0x3a);
VGAOUT8(vgaCRReg, cr3a);
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, cr66);
if (!psav->ModeStructInit) {
vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
memcpy(&psav->ModeReg, save, sizeof(SavageRegRec));
psav->ModeStructInit = TRUE;
}
#if 0
if (xf86GetVerbosity() > 1)
SavagePrintRegs(pScrn);
#endif
return;
}
static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
SavageRegPtr restore, Bool Entering)
{
unsigned char tmp, cr3a, cr66;
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
int vgaCRIndex, vgaCRReg, vgaIOBase;
vgaIOBase = hwp->IOBase;
vgaCRIndex = vgaIOBase + 4;
vgaCRReg = vgaIOBase + 5;
TRACE(("SavageWriteMode(%x)\n", restore->mode));
#ifdef XF86DRI
if (psav->directRenderingEnabled) {
DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
psav->LockHeld = 1;
}
#endif
if (psav->IsSecondary) {
/* Set up the mode. Don't clear video RAM. */
SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
SavageSetGBD(pScrn);
return;
}
if( Entering &&
(!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
)
SavageInitialize2DEngine(pScrn);
/*
* If we figured out a VESA mode number for this timing, just use
* the S3 BIOS to do the switching, with a few additional tweaks.
*/
if( psav->UseBIOS && restore->mode > 0x13 )
{
int width;
unsigned short cr6d;
unsigned short cr79 = 0;
/* Set up the mode. Don't clear video RAM. */
SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
/* Restore the DAC. */
vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
/* Unlock the extended registers. */
#if 0
/* Which way is better? */
hwp->writeCrtc( hwp, 0x38, 0x48 );
hwp->writeCrtc( hwp, 0x39, 0xa0 );
hwp->writeSeq( hwp, 0x08, 0x06 );
#endif
VGAOUT16(vgaCRIndex, 0x4838);
VGAOUT16(vgaCRIndex, 0xA039);
VGAOUT16(0x3c4, 0x0608);
/* Enable linear addressing. */
VGAOUT16(vgaCRIndex, 0x1358);
/* Disable old MMIO. */
VGAOUT8(vgaCRIndex, 0x53);
VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & ~0x10);
/* Disable HW cursor */
VGAOUT16(vgaCRIndex, 0x0045);
/* Set the color mode. */
VGAOUT8(vgaCRIndex, 0x67);
VGAOUT8(vgaCRReg, restore->CR67);
/* Enable gamma correction, set CLUT to 8 bit */
VGAOUT8(0x3c4, 0x1b);
if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive
&& ! psav->FBStart2nd )
VGAOUT8(0x3c5, 0x18 );
else
VGAOUT8(0x3c5, 0x10 );
/* We may need TV/panel fixups here. See s3bios.c line 2904. */
/* Set FIFO fetch delay. */
VGAOUT8(vgaCRIndex, 0x85);
VGAOUT8(vgaCRReg, (VGAIN8(vgaCRReg) & 0xf8) | 0x03);
/* Patch CR79. These values are magical. */
if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
{
VGAOUT8(vgaCRIndex, 0x6d);
cr6d = VGAIN8(vgaCRReg);
cr79 = 0x04;
if( pScrn->displayWidth >= 1024 )
{
if(psav->primStreamBpp == 32 )
{
if( restore->refresh >= 130 )
cr79 = 0x03;
else if( pScrn->displayWidth >= 1280 )
cr79 = 0x02;
else if(
(pScrn->displayWidth == 1024) &&
(restore->refresh >= 75)
)
{
if( cr6d && LCD_ACTIVE )
cr79 = 0x05;
else
cr79 = 0x08;
}
}
else if( psav->primStreamBpp == 16)
{
/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
* screen artifacts with that value. Let's keep it low for now.
* if( restore->refresh >= 130 )
* cr79 = 0x13;
* else
*/
if( pScrn->displayWidth == 1024 )
{
if( cr6d && LCD_ACTIVE )
cr79 = 0x08;
else
cr79 = 0x0e;
}
}
}
}
if( (psav->Chipset != S3_SAVAGE2000) &&
!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
VGAOUT16(vgaCRIndex, (cr79 << 8) | 0x79);
/* Make sure 16-bit memory access is enabled. */
VGAOUT16(vgaCRIndex, 0x0c31);
/* Enable the graphics engine. */
VGAOUT16(vgaCRIndex, 0x0140);
/* Handle the pitch. */
VGAOUT8(vgaCRIndex, 0x50);
VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
VGAOUT16(vgaCRIndex, ((width & 0xff) << 8) | 0x13 );
VGAOUT16(vgaCRIndex, ((width & 0x300) << 4) | 0x51 );
/* Some non-S3 BIOSes enable block write even on non-SGRAM devices. */
switch( psav->Chipset )
{
case S3_SAVAGE2000:
VGAOUT8(vgaCRIndex, 0x73);
VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & 0xdf );
break;
case S3_SAVAGE3D:
case S3_SAVAGE4:
VGAOUT8(vgaCRIndex, 0x68);
if( !(VGAIN8(vgaCRReg) & 0x80) )
{
/* Not SGRAM; disable block write. */
VGAOUT8(vgaCRIndex, 0x88);
VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0x10);
}
break;
}
/* set the correct clock for some BIOSes */
VGAOUT8(VGA_MISC_OUT_W,
VGAIN8(VGA_MISC_OUT_R) | 0x0C);
/* Some BIOSes turn on clock doubling on non-doubled modes */
if (pScrn->bitsPerPixel < 24) {
VGAOUT8(vgaCRIndex, 0x67);
if (!(VGAIN8(vgaCRReg) & 0x10)) {
VGAOUT8(0x3c4, 0x15);
VGAOUT8(0x3c5, VGAIN8(0x3C5) & ~0x10);
VGAOUT8(0x3c4, 0x18);
VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x80);
}
}
SavageInitialize2DEngine(pScrn);
VGAOUT16(vgaCRIndex, 0x0140);
SavageSetGBD(pScrn);
#ifdef XF86DRI
if (psav->directRenderingEnabled)
DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
psav->LockHeld = 0;
#endif
return;
}
VGAOUT8(0x3c2, 0x23);
VGAOUT16(vgaCRIndex, 0x4838);
VGAOUT16(vgaCRIndex, 0xa039);
VGAOUT16(0x3c4, 0x0608);
vgaHWProtect(pScrn, TRUE);
/* will we be reenabling STREAMS for the new mode? */
psav->STREAMSRunning = 0;
/* reset GE to make sure nothing is going on */
VGAOUT8(vgaCRIndex, 0x66);
if(VGAIN8(vgaCRReg) & 0x01)
SavageGEReset(pScrn,0,__LINE__,__FILE__);
/*
* Some Savage/MX and /IX systems go nuts when trying to exit the
* server after WindowMaker has displayed a gradient background. I
* haven't been able to find what causes it, but a non-destructive
* switch to mode 3 here seems to eliminate the issue.
*/
if( ((restore->CR31 & 0x0a) == 0) && psav->pVbe ) {
SavageSetTextMode( psav );
}
VGAOUT8(vgaCRIndex, 0x67);
(void) VGAIN8(vgaCRReg);
/*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no STREAMS yet old and new */
/* restore extended regs */
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, restore->CR66);
VGAOUT8(vgaCRIndex, 0x3a);
VGAOUT8(vgaCRReg, restore->CR3A);
VGAOUT8(vgaCRIndex, 0x31);
VGAOUT8(vgaCRReg, restore->CR31);
VGAOUT8(vgaCRIndex, 0x32);
VGAOUT8(vgaCRReg, restore->CR32);
VGAOUT8(vgaCRIndex, 0x58);
VGAOUT8(vgaCRReg, restore->CR58);
VGAOUT8(vgaCRIndex, 0x53);
VGAOUT8(vgaCRReg, restore->CR53 & 0x7f);
VGAOUT16(0x3c4, 0x0608);
/* Restore DCLK registers. */
VGAOUT8(0x3c4, 0x0e);
VGAOUT8(0x3c5, restore->SR0E);
VGAOUT8(0x3c4, 0x0f);
VGAOUT8(0x3c5, restore->SR0F);
VGAOUT8(0x3c4, 0x29);
VGAOUT8(0x3c5, restore->SR29);
VGAOUT8(0x3c4, 0x15);
VGAOUT8(0x3c5, restore->SR15);
/* Restore flat panel expansion registers. */
if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
int i;
for( i = 0; i < 8; i++ ) {
VGAOUT8(0x3c4, 0x54+i);
VGAOUT8(0x3c5, restore->SR54[i]);
}
}
/* restore the standard vga regs */
if (xf86IsPrimaryPci(psav->PciInfo))
vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
else
vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
/* extended mode timing registers */
VGAOUT8(vgaCRIndex, 0x53);
VGAOUT8(vgaCRReg, restore->CR53);
VGAOUT8(vgaCRIndex, 0x5d);
VGAOUT8(vgaCRReg, restore->CR5D);
VGAOUT8(vgaCRIndex, 0x5e);
VGAOUT8(vgaCRReg, restore->CR5E);
VGAOUT8(vgaCRIndex, 0x3b);
VGAOUT8(vgaCRReg, restore->CR3B);
VGAOUT8(vgaCRIndex, 0x3c);
VGAOUT8(vgaCRReg, restore->CR3C);
VGAOUT8(vgaCRIndex, 0x43);
VGAOUT8(vgaCRReg, restore->CR43);
VGAOUT8(vgaCRIndex, 0x65);
VGAOUT8(vgaCRReg, restore->CR65);
/* restore the desired video mode with cr67 */
VGAOUT8(vgaCRIndex, 0x67);
/*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no streams for new and old streams engines */
/* other mode timing and extended regs */
VGAOUT8(vgaCRIndex, 0x34);
VGAOUT8(vgaCRReg, restore->CR34);
VGAOUT8(vgaCRIndex, 0x40);
VGAOUT8(vgaCRReg, restore->CR40);
VGAOUT8(vgaCRIndex, 0x42);
VGAOUT8(vgaCRReg, restore->CR42);
VGAOUT8(vgaCRIndex, 0x45);
VGAOUT8(vgaCRReg, restore->CR45);
VGAOUT8(vgaCRIndex, 0x50);
VGAOUT8(vgaCRReg, restore->CR50);
VGAOUT8(vgaCRIndex, 0x51);
VGAOUT8(vgaCRReg, restore->CR51);
/* memory timings */
VGAOUT8(vgaCRIndex, 0x36);
VGAOUT8(vgaCRReg, restore->CR36);
VGAOUT8(vgaCRIndex, 0x60);
VGAOUT8(vgaCRReg, restore->CR60);
VGAOUT8(vgaCRIndex, 0x68);
VGAOUT8(vgaCRReg, restore->CR68);
VerticalRetraceWait();
VGAOUT8(vgaCRIndex, 0x69);
VGAOUT8(vgaCRReg, restore->CR69);
VGAOUT8(vgaCRIndex, 0x6f);
VGAOUT8(vgaCRReg, restore->CR6F);
VGAOUT8(vgaCRIndex, 0x33);
VGAOUT8(vgaCRReg, restore->CR33);
VGAOUT8(vgaCRIndex, 0x86);
VGAOUT8(vgaCRReg, restore->CR86);
VGAOUT8(vgaCRIndex, 0x88);
VGAOUT8(vgaCRReg, restore->CR88);
VGAOUT8(vgaCRIndex, 0x90);
VGAOUT8(vgaCRReg, restore->CR90);
VGAOUT8(vgaCRIndex, 0x91);
VGAOUT8(vgaCRReg, restore->CR91);
if( psav->Chipset == S3_SAVAGE4 )
{
VGAOUT8(vgaCRIndex, 0xb0);
VGAOUT8(vgaCRReg, restore->CRB0);
}
VGAOUT8(vgaCRIndex, 0x32);
VGAOUT8(vgaCRReg, restore->CR32);
/* unlock extended seq regs */
VGAOUT8(0x3c4, 0x08);
VGAOUT8(0x3c5, 0x06);
/* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
* we should leave the default SR10 and SR11 values there.
*/
if (restore->SR10 != 255) {
VGAOUT8(0x3c4, 0x10);
VGAOUT8(0x3c5, restore->SR10);
VGAOUT8(0x3c4, 0x11);
VGAOUT8(0x3c5, restore->SR11);
}
/* restore extended seq regs for dclk */
VGAOUT8(0x3c4, 0x0e);
VGAOUT8(0x3c5, restore->SR0E);
VGAOUT8(0x3c4, 0x0f);
VGAOUT8(0x3c5, restore->SR0F);
VGAOUT8(0x3c4, 0x12);
VGAOUT8(0x3c5, restore->SR12);
VGAOUT8(0x3c4, 0x13);
VGAOUT8(0x3c5, restore->SR13);
VGAOUT8(0x3c4, 0x29);
VGAOUT8(0x3c5, restore->SR29);
VGAOUT8(0x3c4, 0x18);
VGAOUT8(0x3c5, restore->SR18);
VGAOUT8(0x3c4, 0x1b);
if( psav->DGAactive )
VGAOUT8(0x3c5, restore->SR1B & ~0x08 );
else
VGAOUT8(0x3c5, restore->SR1B);
/* load new m, n pll values for dclk & mclk */
VGAOUT8(0x3c4, 0x15);
tmp = VGAIN8(0x3c5) & ~0x21;
VGAOUT8(0x3c5, tmp | 0x03);
VGAOUT8(0x3c5, tmp | 0x23);
VGAOUT8(0x3c5, tmp | 0x03);
VGAOUT8(0x3c5, restore->SR15);
usleep( 100 );
VGAOUT8(0x3c4, 0x30);
VGAOUT8(0x3c5, restore->SR30);
VGAOUT8(0x3c4, 0x08);
VGAOUT8(0x3c5, restore->SR08);
/* now write out cr67 in full, possibly starting STREAMS */
VerticalRetraceWait();
VGAOUT8(vgaCRIndex, 0x67);
#if 0
VGAOUT8(vgaCRReg, 0x50);
usleep(10000);
VGAOUT8(vgaCRIndex, 0x67);
#endif
VGAOUT8(vgaCRReg, restore->CR67);
VGAOUT8(vgaCRIndex, 0x66);
cr66 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr66 | 0x80);
VGAOUT8(vgaCRIndex, 0x3a);
cr3a = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, cr3a | 0x80);
if (Entering)
SavageGEReset(pScrn,0,__LINE__,__FILE__);
if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
{
VerticalRetraceWait();
OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
OUTREG(MIU_CONTROL_REG, restore->MMPR1);
OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
}
/* If we're going into graphics mode and acceleration was enabled, */
/* go set up the BCI buffer and the global bitmap descriptor. */
#if 0
if( Entering && (!psav->NoAccel) )
{
VGAOUT8(vgaCRIndex, 0x50);
VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
SavageInitialize2DEngine(pScrn);
}
#endif
VGAOUT8(vgaCRIndex, 0x66);
VGAOUT8(vgaCRReg, cr66);
VGAOUT8(vgaCRIndex, 0x3a);
VGAOUT8(vgaCRReg, cr3a);
if( Entering ) {
SavageInitialize2DEngine(pScrn);
VGAOUT16(vgaCRIndex, 0x0140);
SavageSetGBD(pScrn);
}
vgaHWProtect(pScrn, FALSE);
#ifdef XF86DRI
if (psav->directRenderingEnabled)
DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
psav->LockHeld = 0;
#endif
return;
}
static Bool SavageMapMem(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
int err;
TRACE(("SavageMapMem()\n"));
if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
#ifdef XSERVER_LIBPCIACCESS
psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
+ psav->PciInfo->regions[0].base_addr;
psav->FbRegion.base = psav->PciInfo->regions[0].base_addr;
#else
psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
+ psav->PciInfo->memBase[0];
psav->FbRegion.base = psav->PciInfo->memBase[0];
#endif
} else {
#ifdef XSERVER_LIBPCIACCESS
psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
+ psav->PciInfo->regions[0].base_addr;
psav->FbRegion.base = psav->PciInfo->regions[1].base_addr;
#else
psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
+ psav->PciInfo->memBase[0];
psav->FbRegion.base = psav->PciInfo->memBase[1];
#endif
}
psav->MmioRegion.size = SAVAGE_NEWMMIO_REGSIZE;
psav->FbRegion.size = psav->videoRambytes;
/* On Paramount and Savage 2000, aperture 0 is PCI base 2. On other
* chipsets it's in the same BAR as the framebuffer.
*/
psav->ApertureRegion.size = (psav->IsPrimary || psav->IsSecondary)
? (0x01000000 * 2) : (0x01000000 * 5);
if ((psav->Chipset == S3_SUPERSAVAGE)
|| (psav->Chipset == S3_SAVAGE2000)) {
#ifdef XSERVER_LIBPCIACCESS
psav->ApertureRegion.base = psav->PciInfo->regions[2].base_addr;
if (psav->ApertureRegion.size > psav->PciInfo->regions[2].size)
psav->ApertureRegion.size = psav->PciInfo->regions[2].size;
#else
psav->ApertureRegion.base = psav->PciInfo->memBase[2];
#endif
} else {
psav->ApertureRegion.base = psav->FbRegion.base + 0x02000000;
}
if (psav->FbRegion.size != 0) {
#ifdef XSERVER_LIBPCIACCESS
err = pci_device_map_range(psav->PciInfo, psav->FbRegion.base,
psav->FbRegion.size,
(PCI_DEV_MAP_FLAG_WRITABLE
| PCI_DEV_MAP_FLAG_WRITE_COMBINE),
& psav->FbRegion.memory);
#else
psav->FbRegion.memory =
xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
psav->PciTag, psav->FbRegion.base,
psav->FbRegion.size);
err = (psav->FbRegion.memory == NULL) ? errno : 0;
#endif
if (err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Internal error: could not map framebuffer range (%d, %s).\n",
err, strerror(err));
return FALSE;
}
psav->FBBase = psav->FbRegion.memory;
psav->FBStart = (psav->IsSecondary)
? psav->FBBase + 0x1000000 : psav->FBBase;
}
if (psav->ApertureRegion.memory == NULL) {
#ifdef XSERVER_LIBPCIACCESS
err = pci_device_map_range(psav->PciInfo, psav->ApertureRegion.base,
psav->ApertureRegion.size,
(PCI_DEV_MAP_FLAG_WRITABLE
| PCI_DEV_MAP_FLAG_WRITE_COMBINE),
& psav->ApertureRegion.memory);
#else
psav->ApertureRegion.memory =
xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
psav->PciTag, psav->ApertureRegion.base,
psav->ApertureRegion.size);
err = (psav->ApertureRegion.memory == NULL) ? errno : 0;
#endif
if (err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Internal error: could not map aperture range (%d, %s).\n",
err, strerror(err));
return FALSE;
}
psav->ApertureMap = (psav->IsSecondary)
? psav->ApertureRegion.memory + 0x1000000
: psav->ApertureRegion.memory;
}
if (psav->MmioRegion.memory == NULL) {
#ifdef XSERVER_LIBPCIACCESS
err = pci_device_map_range(psav->PciInfo, psav->MmioRegion.base,
psav->MmioRegion.size,
(PCI_DEV_MAP_FLAG_WRITABLE),
& psav->MmioRegion.memory);
#else
psav->MmioRegion.memory =
xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
psav->PciTag, psav->MmioRegion.base,
psav->MmioRegion.size);
err = (psav->MmioRegion.memory == NULL) ? errno : 0;
#endif
if (err) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Internal error: could not map MMIO range (%d, %s).\n",
err, strerror(err));
return FALSE;
}
psav->MapBase = psav->MmioRegion.memory;
psav->BciMem = psav->MapBase + 0x10000;
SavageEnableMMIO(pScrn);
}
pScrn->memPhysBase = psav->FbRegion.base;
return TRUE;
}
static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
{
SavagePtr psav = SAVPTR(pScrn);
TRACE(("SavageUnmapMem(%x,%x)\n", psav->MapBase, psav->FBBase));
if (psav->PrimaryVidMapped) {
vgaHWUnmapMem(pScrn);
psav->PrimaryVidMapped = FALSE;
}
SavageDisableMMIO(pScrn);
if (All && (psav->MmioRegion.memory != NULL)) {
#ifdef XSERVER_LIBPCIACCESS
pci_device_unmap_range(psav->PciInfo,
psav->MmioRegion.memory,
psav->MmioRegion.size);
#else
xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBase,
SAVAGE_NEWMMIO_REGSIZE);
#endif
psav->MmioRegion.memory = NULL;
psav->MapBase = 0;
psav->BciMem = 0;
}
if (psav->FbRegion.memory != NULL) {
#ifdef XSERVER_LIBPCIACCESS
pci_device_unmap_range(psav->PciInfo,
psav->FbRegion.memory,
psav->FbRegion.size);
#else
xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->FbRegion.base,
psav->FbRegion.size);
#endif
}
if (psav->ApertureRegion.memory != NULL) {
#ifdef XSERVER_LIBPCIACCESS
pci_device_unmap_range(psav->PciInfo,
psav->ApertureRegion.memory,
psav->ApertureRegion.size);
#else
xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->ApertureRegion.base,
psav->ApertureRegion.size);
#endif
}
psav->FbRegion.memory = NULL;
psav->ApertureRegion.memory = NULL;
psav->FBBase = 0;
psav->FBStart = 0;
psav->ApertureMap = 0;
return;
}
#ifdef XF86DRI
static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
int cpp = pScrn->bitsPerPixel / 8;
int tiledBufferSize, RamNeededFor3D;
if (cpp == 2) {
tiledBufferSize = ((pScrn->virtualX+63)/64)*((pScrn->virtualY+15)/16) * 2048;
} else {
tiledBufferSize = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16) * 2048;
}
RamNeededFor3D = 4096 + /* hw cursor*/
psav->cobSize + /*COB*/
tiledBufferSize + /* front buffer */
tiledBufferSize + /* back buffer */
tiledBufferSize; /* depth buffer */
xf86DrvMsg(pScrn->scrnIndex,X_INFO,
"%d kB of Videoram needed for 3D; %d kB of Videoram available\n",
RamNeededFor3D/1024, psav->videoRambytes/1024);
if (RamNeededFor3D <= psav->videoRambytes) {
xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Sufficient Videoram available for 3D\n");
return TRUE;
} else {
xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D -- "
"Try a lower color depth or smaller desktop. "
"For integrated savages try increasing the videoram in the BIOS.\n");
return FALSE;
}
}
#endif
static void SavageInitStatus(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
switch( psav->Chipset ) {
case S3_SAVAGE3D:
case S3_SAVAGE_MX:
psav->WaitQueue = WaitQueue3D;
psav->WaitIdle = WaitIdle3D;
psav->WaitIdleEmpty = WaitIdleEmpty3D;
psav->bciUsedMask = 0x1ffff;
psav->eventStatusReg= 1;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_SUPERSAVAGE:
case S3_PROSAVAGEDDR:
case S3_TWISTER:
psav->WaitQueue = WaitQueue4;
psav->WaitIdle = WaitIdle4;
psav->WaitIdleEmpty = WaitIdleEmpty4;
psav->bciUsedMask = 0x1fffff;
psav->eventStatusReg= 1;
break;
case S3_SAVAGE2000:
psav->WaitQueue = WaitQueue2K;
psav->WaitIdle = WaitIdle2K;
psav->WaitIdleEmpty = WaitIdleEmpty2K;
psav->bciUsedMask = 0xfffff;
psav->eventStatusReg= 2;
break;
}
}
static void SavageInitShadowStatus(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
psav->ShadowStatus = psav->ConfigShadowStatus;
SavageInitStatus(pScrn);
if( psav->ShadowStatus ) {
psav->ShadowPhysical =
psav->FbRegion.base + psav->CursorKByte*1024 + 4096 - 32;
psav->ShadowVirtual = (CARD32 *)
(psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
"Shadow area physical %08lx, linear %p\n",
psav->ShadowPhysical, (void *)psav->ShadowVirtual );
psav->WaitQueue = ShadowWaitQueue;
psav->WaitIdle = ShadowWait;
psav->WaitIdleEmpty = ShadowWait;
}
if( psav->Chipset == S3_SAVAGE2000 )
psav->dwBCIWait2DIdle = 0xc0040000;
else
psav->dwBCIWait2DIdle = 0xc0020000;
}
static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen,
int argc, char **argv)
{
ScrnInfoPtr pScrn;
SavagePtr psav;
EntityInfoPtr pEnt;
int ret;
int colormapFlags;
TRACE(("SavageScreenInit()\n"));
pScrn = xf86Screens[pScreen->myNum];
psav = SAVPTR(pScrn);
pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
if (!psav->pVbe)
psav->pVbe = VBEInit(NULL, pEnt->index);
SavageEnableMMIO(pScrn);
if (!SavageMapMem(pScrn))
return FALSE;
psav->FBStart2nd = 0;
if (psav->overlayDepth) {
if ((pScrn->virtualX * pScrn->virtualY *
(DEPTH_BPP(DEPTH_2ND(pScrn))) >> 3)
> (psav->CursorKByte * 1024))
xf86DrvMsg(pScrn->scrnIndex,X_WARNING,
"Not enough memory for overlay mode: disabling\n");
else psav->FBStart2nd = psav->FBStart
+ ((pScrn->virtualX * pScrn->virtualY + 0xff) & ~0xff);
}
SavageInitShadowStatus(pScrn);
psav->ShadowCounter = 0;
SavageSave(pScrn);
vgaHWBlankScreen(pScrn, TRUE);
#ifdef XF86DRI
if (!xf86ReturnOptValBool(psav->Options, OPTION_DRI, TRUE)) {
psav->directRenderingEnabled = FALSE;
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"Direct rendering forced off\n");
} else if (psav->IsSecondary) {
psav->directRenderingEnabled = FALSE;
} else if (xf86IsEntityShared(psav->pEnt->index)) {
/* Xinerama has sync problem with DRI, disable it for now */
psav->directRenderingEnabled = FALSE;
xf86DrvMsg(scrnIndex, X_WARNING,
"Direct Rendering Disabled -- "
"Dual-head configuration is not working with "
"DRI at present.\n");
} else if (/*!psav->bTiled*/psav->bDisableTile) {
xf86DrvMsg(scrnIndex, X_WARNING,
"Direct Rendering requires a tiled framebuffer -- "
"Set Option \"DisableTile\" \"false\"\n");
} else if (psav->cobSize == 0) {
xf86DrvMsg(scrnIndex, X_WARNING,
"Direct Rendering requires the COB -- "
"Set Option \"DisableCOB\" \"false\"\n");
} else if (((psav->Chipset == S3_TWISTER)
|| (psav->Chipset == S3_PROSAVAGE)
|| (psav->Chipset == S3_SAVAGE4)
|| (psav->Chipset == S3_SAVAGE_MX)
|| (psav->Chipset == S3_SAVAGE3D)
|| (psav->Chipset == S3_SUPERSAVAGE)
|| (psav->Chipset == S3_PROSAVAGEDDR))
&& (!psav->NoAccel)
&& (SavageCheckAvailableRamFor3D(pScrn))) {
/* Setup DRI after visuals have been established */
psav->directRenderingEnabled = SAVAGEDRIScreenInit(pScreen);
/* If DRI init failed, reset shadow status. */
if (!psav->directRenderingEnabled &&
psav->ShadowStatus != psav->ConfigShadowStatus) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
SavageInitShadowStatus(pScrn);
}
/* If shadow status was enabled for DRI, hook up the shadow
* waiting functions now. */
else if (psav->ShadowStatus && !psav->ConfigShadowStatus) {
psav->WaitQueue = ShadowWaitQueue;
psav->WaitIdle = ShadowWait;
psav->WaitIdleEmpty = ShadowWait;
}
} else
psav->directRenderingEnabled = FALSE;
if(psav->directRenderingEnabled) {
xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"DRI is enabled\n");
}
else {
xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DRI isn't enabled\n");
}
#endif
if (!SavageModeInit(pScrn, pScrn->currentMode))
return FALSE;
miClearVisualTypes();
{
int visual;
visual = ((psav->FBStart2nd && pScrn->bitsPerPixel > 8)
|| pScrn->bitsPerPixel == 16) ? TrueColorMask
: miGetDefaultVisualMask(DEPTH_BPP(pScrn->depth));
if (!miSetVisualTypes(pScrn->depth, visual,
pScrn->rgbBits, pScrn->defaultVisual))
return FALSE;
if (psav->FBStart2nd) {/* we have overlay */
visual = psav->overlayDepth > 8 ? TrueColorMask :
miGetDefaultVisualMask(DEPTH_BPP(psav->overlayDepth));
if (!miSetVisualTypes(psav->overlayDepth, visual,
psav->overlayDepth > 8 ? 8 : 6,
pScrn->defaultVisual))
return FALSE;
}
}
if (!miSetPixmapDepths ())
return FALSE;
ret = SavageInternalScreenInit(scrnIndex, pScreen);
if (!ret)
return FALSE;
xf86SetBlackWhitePixels(pScreen);
{
VisualPtr visual;
visual = pScreen->visuals + pScreen->numVisuals;
while (--visual >= pScreen->visuals) {
if ((visual->class | DynamicClass) == DirectColor
&& visual->nplanes > MAX_PSEUDO_DEPTH) {
if (visual->nplanes == pScrn->depth) {
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;
} else if (visual->offsetRed > 8
|| visual->offsetGreen > 8
|| visual->offsetBlue > 8) {
/*
* mi has set these wrong. fix it here -- we cannot use pScrn
* as this is set up for the default depth 8.
*/
int tmp;
int c_s = 0;
tmp = visual->offsetBlue;
visual->offsetBlue = visual->offsetRed;
visual->offsetRed = tmp;
tmp = visual->blueMask;
visual->blueMask = visual->redMask;
visual->redMask = tmp;
switch (DEPTH_2ND(pScrn)) {
case 16:
visual->offsetRed = 11;
visual->offsetGreen = 5;
visual->offsetBlue = 0;
visual->redMask = 0xF800;
visual->greenMask = 0x7E0;
visual->blueMask = 0x1F;
break;
case 24:
visual->offsetRed = 16;
visual->offsetGreen = 8;
visual->offsetBlue = 0;
visual->redMask = 0xFF0000;
visual->greenMask = 0xFF00;
visual->blueMask = 0xFF;
c_s = 2;
break;
}
psav->overlay.redMask = visual->redMask;
psav->overlay.greenMask = visual->greenMask;
psav->overlay.blueMask = visual->blueMask;
psav->overlay.redShift = visual->offsetRed + c_s;
psav->overlay.greenShift = visual->offsetGreen + c_s;
psav->overlay.blueShift = visual->offsetBlue + c_s;
}
}
}
}
/* must be after RGB ordering fixed */
fbPictureInit (pScreen, 0, 0);
if( !psav->NoAccel ) {
SavageInitAccel(pScreen);
}
miInitializeBackingStore(pScreen);
xf86SetBackingStore(pScreen);
if( !psav->shadowFB && !psav->useEXA )
SavageDGAInit(pScreen);
miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
if (psav->hwcursor)
if (!SavageHWCursorInit(pScreen))
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"Hardware cursor initialization failed\n");
if (psav->shadowFB) {
RefreshAreaFuncPtr refreshArea = SavageRefreshArea;
if(psav->rotate) {
if (!psav->PointerMoved) {
psav->PointerMoved = pScrn->PointerMoved;
pScrn->PointerMoved = SavagePointerMoved;
}
switch(pScrn->bitsPerPixel) {
case 8: refreshArea = SavageRefreshArea8; break;
case 16: refreshArea = SavageRefreshArea16; break;
case 24: refreshArea = SavageRefreshArea24; break;
case 32: refreshArea = SavageRefreshArea32; break;
}
}
ShadowFBInit(pScreen, refreshArea);
}
if (!miCreateDefColormap(pScreen))
return FALSE;
colormapFlags = CMAP_RELOAD_ON_MODE_SWITCH
| ((psav->FBStart2nd) ? 0 : CMAP_PALETTED_TRUECOLOR);
if (psav->Chipset == S3_SAVAGE4) {
if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPaletteSavage4,
NULL, colormapFlags ))
return FALSE;
} else {
if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPalette, NULL,
colormapFlags ))
return FALSE;
}
vgaHWBlankScreen(pScrn, FALSE);
psav->CloseScreen = pScreen->CloseScreen;
pScreen->SaveScreen = SavageSaveScreen;
pScreen->CloseScreen = SavageCloseScreen;
if (xf86DPMSInit(pScreen, SavageDPMS, 0) == FALSE)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed\n");
#ifdef XF86DRI
if (psav->directRenderingEnabled) {
/* complete the DRI setup.*/
psav->directRenderingEnabled = SAVAGEDRIFinishScreenInit(pScreen);
/* If DRI initialization failed, reset shadow status and
* reinitialize 2D engine. */
if (!psav->directRenderingEnabled &&
psav->ShadowStatus != psav->ConfigShadowStatus) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
SavageInitShadowStatus(pScrn);
SavageInitialize2DEngine(pScrn);
}
}
if (psav->directRenderingEnabled) {
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
} else {
xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
}
#endif
SavagePanningCheck(pScrn, pScrn->currentMode);
#ifdef XvExtension
if( !psav->FBStart2nd && !psav->NoAccel /*&& !SavagePanningCheck(pScrn)*/ ) {
if (psav->IsSecondary)
/* Xv should work on crtc2, but I haven't gotten there yet. -- AGD */
xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv currently disabled for crtc2.\n");
else
SavageInitVideo( pScreen );
}
#endif
#ifdef XF86DRI
if ((psav->directRenderingEnabled) && (!psav->bDisableXvMC)) {
if (SAVAGEInitMC(pScreen))
xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is enabled\n");
else
xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is not enabled\n");
}
#endif
if (serverGeneration == 1)
xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
return TRUE;
}
static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen)
{
int ret = TRUE;
ScrnInfoPtr pScrn;
SavagePtr psav;
int width, height, displayWidth;
unsigned char *FBStart;
TRACE(("SavageInternalScreenInit()\n"));
pScrn = xf86Screens[pScreen->myNum];
psav = SAVPTR(pScrn);
displayWidth = pScrn->displayWidth;
if (psav->rotate) {
height = pScrn->virtualX;
width = pScrn->virtualY;
} else {
width = pScrn->virtualX;
height = pScrn->virtualY;
}
if(psav->shadowFB) {
psav->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
psav->ShadowPtr = xalloc(psav->ShadowPitch * height);
displayWidth = psav->ShadowPitch / (pScrn->bitsPerPixel >> 3);
FBStart = psav->ShadowPtr;
} else {
psav->ShadowPtr = NULL;
FBStart = psav->FBStart;
}
if (!psav->FBStart2nd) {
ret = fbScreenInit(pScreen, FBStart, width, height,
pScrn->xDpi, pScrn->yDpi,
psav->ulAperturePitch / (pScrn->bitsPerPixel >> 3), /*displayWidth,*/
pScrn->bitsPerPixel);
} else {
FbOverlayScrPrivPtr pScrPriv;
int Depth2nd = DEPTH_2ND(pScrn);
if (!fbSetupScreen (pScreen, FBStart, width, height,
pScrn->xDpi, pScrn->yDpi, displayWidth, 8))
return FALSE;
if (pScrn->depth == 8) {
ret = fbOverlayFinishScreenInit (pScreen, FBStart,
psav->FBStart2nd, width,
height,pScrn->xDpi, pScrn->yDpi,
displayWidth,displayWidth,
8, DEPTH_BPP(Depth2nd),
8, Depth2nd);
pScrPriv = fbOverlayGetScrPriv(pScreen);
pScrPriv->layer[0].key = pScrn->colorKey;
} else {
ret = fbOverlayFinishScreenInit (pScreen, psav->FBStart2nd,
FBStart,
width, height,pScrn->xDpi,
pScrn->yDpi,
displayWidth,displayWidth,
DEPTH_BPP(Depth2nd), 8,
Depth2nd, 8);
pScrPriv = fbOverlayGetScrPriv(pScreen);
pScrPriv->layer[1].key = pScrn->colorKey;
}
}
return ret;
}
static int SavageGetRefresh(DisplayModePtr mode)
{
int refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
if (mode->Flags & V_INTERLACE)
refresh *= 2.0;
if (mode->Flags & V_DBLSCAN)
refresh /= 2.0;
if (mode->VScan > 1)
refresh /= mode->VScan;
return refresh;
}
static ModeStatus SavageValidMode(int index, DisplayModePtr pMode,
Bool verbose, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[index];
SavagePtr psav = SAVPTR(pScrn);
int refresh;
TRACE(("SavageValidMode\n"));
/* We prohibit modes bigger than the LCD panel. */
/* TODO We should do this only if the panel is active. */
if( psav->TvOn )
{
if( pMode->HDisplay > psav->TVSizeX )
return MODE_VIRTUAL_X;
if( pMode->VDisplay > psav->TVSizeY )
return MODE_VIRTUAL_Y;
}
if((psav->DisplayType == MT_LCD) &&
((pMode->HDisplay > psav->PanelX) ||
(pMode->VDisplay > psav->PanelY)))
return MODE_PANEL;
if (psav->UseBIOS) {
refresh = SavageGetRefresh(pMode);
return (SavageMatchBiosMode(pScrn,pMode->HDisplay,
pMode->VDisplay,
refresh,NULL,NULL));
}
return MODE_OK;
}
static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
{
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
int width, dclk, i, j; /*, refresh; */
unsigned int m, n, r;
unsigned char tmp = 0;
SavageRegPtr new = &psav->ModeReg;
vgaRegPtr vganew = &hwp->ModeReg;
int vgaCRIndex, vgaCRReg, vgaIOBase;
int refresh;
unsigned int newmode=0, newrefresh=0;
vgaIOBase = hwp->IOBase;
vgaCRIndex = vgaIOBase + 4;
vgaCRReg = vgaIOBase + 5;
TRACE(("SavageModeInit(%dx%d, %dHz)\n",
mode->HDisplay, mode->VDisplay, mode->Clock));
#if 0
ErrorF("Clock = %d, HDisplay = %d, HSStart = %d\n",
mode->Clock, mode->HDisplay, mode->HSyncStart);
ErrorF("HSEnd = %d, HSkew = %d\n",
mode->HSyncEnd, mode->HSkew);
ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
mode->VDisplay, mode->VSyncStart, mode->VSyncEnd);
ErrorF("VTotal = %d\n",
mode->VTotal);
ErrorF("HDisplay = %d, HSStart = %d\n",
mode->CrtcHDisplay, mode->CrtcHSyncStart);
ErrorF("HSEnd = %d, HSkey = %d\n",
mode->CrtcHSyncEnd, mode->CrtcHSkew);
ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
mode->CrtcVDisplay, mode->CrtcVSyncStart, mode->CrtcVSyncEnd);
ErrorF("VTotal = %d\n",
mode->CrtcVTotal);
#endif
if (psav->IsSecondary) {
refresh = SavageGetRefresh(mode);
SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
&newmode,&newrefresh);
new->mode = newmode;
new->refresh = newrefresh;
/* do it! */
SavageWriteMode(pScrn, vganew, new, TRUE);
pScrn->currentMode = mode;
if (psav->FBStart2nd) {
SavageStreamsOn(pScrn);
SavageInitSecondaryStream(pScrn);
}
SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
return TRUE;
}
if (pScrn->bitsPerPixel == 8)
psav->HorizScaleFactor = 1;
else if (pScrn->bitsPerPixel == 16)
psav->HorizScaleFactor = 1; /* I don't think we ever want 2 */
else
psav->HorizScaleFactor = 1;
if (psav->HorizScaleFactor == 2)
if (!mode->CrtcHAdjusted) {
mode->CrtcHDisplay *= 2;
mode->CrtcHSyncStart *= 2;
mode->CrtcHSyncEnd *= 2;
mode->CrtcHBlankStart *= 2;
mode->CrtcHBlankEnd *= 2;
mode->CrtcHTotal *= 2;
mode->CrtcHSkew *= 2;
mode->CrtcHAdjusted = TRUE;
}
if (!vgaHWInit(pScrn, mode))
return FALSE;
new->mode = 0;
/* We need to set CR67 whether or not we use the BIOS. */
dclk = mode->Clock;
new->CR67 = 0x00;
switch( pScrn->depth ) {
case 8:
if( (psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000) )
new->CR67 = 0x10; /* 8bpp, 2 pixels/clock */
else
new->CR67 = 0x00; /* 8bpp, 1 pixel/clock */
break;
case 15:
if(
S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
)
new->CR67 = 0x30; /* 15bpp, 2 pixel/clock */
else
new->CR67 = 0x20; /* 15bpp, 1 pixels/clock */
break;
case 16:
if(
S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
)
new->CR67 = 0x50; /* 16bpp, 2 pixel/clock */
else
new->CR67 = 0x40; /* 16bpp, 1 pixels/clock */
break;
case 24:
if (psav->primStreamBpp == 24 )
new->CR67 = 0x70;
else
new->CR67 = 0xd0;
break;
}
if( psav->UseBIOS ) {
int refresh;
unsigned int newmode=0, newrefresh=0;
refresh = SavageGetRefresh(mode);
SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
&newmode,&newrefresh);
new->mode = newmode;
new->refresh = newrefresh;
}
if( !new->mode ) {
/*
* Either BIOS use is disabled, or we failed to find a suitable
* match. Fall back to traditional register-crunching.
*/
VGAOUT8(vgaCRIndex, 0x3a);
tmp = VGAIN8(vgaCRReg);
if (psav->pci_burst)
new->CR3A = (tmp & 0x7f) | 0x15;
else
new->CR3A = tmp | 0x95;
new->CR53 = 0x00;
new->CR31 = 0x8c;
new->CR66 = 0x89;
VGAOUT8(vgaCRIndex, 0x58);
new->CR58 = VGAIN8(vgaCRReg) & 0x80;
new->CR58 |= 0x13;
#if 0
VGAOUT8(vgaCRIndex, 0x55);
new->CR55 = VGAIN8(vgaCRReg);
if (psav->hwcursor)
new->CR55 |= 0x10;
#endif
new->SR15 = 0x03 | 0x80;
new->SR18 = 0x00;
/* enable gamma correction */
if( pScrn->depth == 24 )
new->SR1B = 0x18;
else
new->SR1B = 0x00;
/* set 8-bit CLUT */
new->SR1B |= 0x10;
new->CR43 = new->CR45 = new->CR65 = 0x00;
VGAOUT8(vgaCRIndex, 0x40);
new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
new->MMPR0 = 0x010400;
new->MMPR1 = 0x00;
new->MMPR2 = 0x0808;
new->MMPR3 = 0x08080810;
if (psav->fifo_aggressive || psav->fifo_moderate ||
psav->fifo_conservative) {
new->MMPR1 = 0x0200;
new->MMPR2 = 0x1808;
new->MMPR3 = 0x08081810;
}
if (psav->MCLK <= 0) {
new->SR10 = 255;
new->SR11 = 255;
}
psav->NeedSTREAMS = FALSE;
SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000,
&m, &n, &r);
new->SR12 = (r << 6) | (n & 0x3f);
new->SR13 = m & 0xff;
new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
if (psav->fifo_moderate) {
if (psav->primStreamBpp < 24)
new->MMPR0 -= 0x8000;
else
new->MMPR0 -= 0x4000;
} else if (psav->fifo_aggressive) {
if (psav->primStreamBpp < 24)
new->MMPR0 -= 0xc000;
else
new->MMPR0 -= 0x6000;
}
if (mode->Flags & V_INTERLACE)
new->CR42 = 0x20;
else
new->CR42 = 0x00;
new->CR34 = 0x10;
i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
((mode->CrtcHSyncStart & 0x800) >> 7);
if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
i |= 0x08;
if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
i |= 0x20;
j = (vganew->CRTC[0] + ((i & 0x01) << 8) +
vganew->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
if (j - (vganew->CRTC[4] + ((i & 0x10) << 4)) < 4) {
if (vganew->CRTC[4] + ((i & 0x10) << 4) + 4 <=
vganew->CRTC[0] + ((i & 0x01) << 8))
j = vganew->CRTC[4] + ((i & 0x10) << 4) + 4;
else
j = vganew->CRTC[0] + ((i & 0x01) << 8) + 1;
}
new->CR3B = j & 0xff;
i |= (j & 0x100) >> 2;
new->CR3C = (vganew->CRTC[0] + ((i & 0x01) << 8)) / 2 ;
new->CR5D = i;
new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) |
(((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
(((mode->CrtcVSyncStart) & 0x400) >> 8) |
(((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
new->CR91 = vganew->CRTC[19] = 0xff & width;
new->CR51 = (0x300 & width) >> 4;
new->CR90 = 0x80 | (width >> 8);
vganew->MiscOutReg |= 0x0c;
/* Set frame buffer description. */
if (psav->primStreamBpp <= 8)
new->CR50 = 0;
else if (psav->primStreamBpp <= 16)
new->CR50 = 0x10;
else
new->CR50 = 0x30;
if (pScrn->displayWidth == 640)
new->CR50 |= 0x40;
else if (pScrn->displayWidth == 800)
new->CR50 |= 0x80;
else if (pScrn->displayWidth == 1024)
new->CR50 |= 0x00;
else if (pScrn->displayWidth == 1152)
new->CR50 |= 0x01;
else if (pScrn->displayWidth == 1280)
new->CR50 |= 0xc0;
else if (pScrn->displayWidth == 1600)
new->CR50 |= 0x81;
else
new->CR50 |= 0xc1; /* Use GBD */
if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
new->CR33 = 0x00;
else
new->CR33 = 0x08;
vganew->CRTC[0x17] = 0xeb;
new->CR67 |= 1;
VGAOUT8(vgaCRIndex, 0x36);
new->CR36 = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x68);
new->CR68 = VGAIN8(vgaCRReg);
new->CR69 = 0;
VGAOUT8(vgaCRIndex, 0x6f);
new->CR6F = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRIndex, 0x86);
new->CR86 = VGAIN8(vgaCRReg) | 0x08;
VGAOUT8(vgaCRIndex, 0x88);
new->CR88 = VGAIN8(vgaCRReg) | DISABLE_BLOCK_WRITE_2D;
VGAOUT8(vgaCRIndex, 0xb0);
new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
}
pScrn->vtSema = TRUE;
/* do it! */
SavageWriteMode(pScrn, vganew, new, TRUE);
pScrn->currentMode = mode;
if (psav->FBStart2nd) {
SavageStreamsOn(pScrn);
SavageInitSecondaryStream(pScrn);
}
SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
return TRUE;
}
static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
vgaRegPtr vgaSavePtr = &hwp->SavedReg;
SavageRegPtr SavageSavePtr = &psav->SavedReg;
TRACE(("SavageCloseScreen\n"));
#ifdef XF86DRI
if (psav->directRenderingEnabled) {
SAVAGEDRICloseScreen(pScreen);
/* reset shadow values */
SavageInitShadowStatus(pScrn);
psav->directRenderingEnabled=FALSE;
}
#endif
if (psav->EXADriverPtr) {
exaDriverFini(pScreen);
psav->EXADriverPtr = NULL;
}
if( psav->AccelInfoRec ) {
XAADestroyInfoRec( psav->AccelInfoRec );
psav->AccelInfoRec = NULL;
}
if( psav->DGAModes ) {
xfree( psav->DGAModes );
psav->DGAModes = NULL;
psav->numDGAModes = 0;
}
if (pScrn->vtSema) {
if (psav->FBStart2nd)
SavageStreamsOff(pScrn);
SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
SavageResetStreams(pScrn);
vgaHWLock(hwp);
SavageUnmapMem(pScrn, 0);
}
if (psav->pVbe)
vbeFree(psav->pVbe);
psav->pVbe = NULL;
pScrn->vtSema = FALSE;
pScreen->CloseScreen = psav->CloseScreen;
return (*pScreen->CloseScreen)(scrnIndex, pScreen);
}
static Bool SavageSaveScreen(ScreenPtr pScreen, int mode)
{
ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
TRACE(("SavageSaveScreen(0x%x)\n", mode));
if( pScrn->vtSema && SAVPTR(pScrn)->hwcursor && SAVPTR(pScrn)->hwc_on )
{
if( xf86IsUnblank(mode) )
SavageShowCursor( pScrn );
else
SavageHideCursor( pScrn );
SAVPTR(pScrn)->hwc_on = TRUE; /*restore */
}
return vgaHWSaveScreen(pScreen, mode);
}
void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
SavagePtr psav = SAVPTR(pScrn);
if (psav->IsSecondary) {
SavageDoAdjustFrame(pScrn, x, y, TRUE);
} else {
SavageDoAdjustFrame(pScrn, x, y, FALSE);
}
}
void
SavageDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int crtc2)
{
SavagePtr psav = SAVPTR(pScrn);
int address=0,top=0,left=0,tile_height,tile_size;
TRACE(("SavageDoAdjustFrame(%d,%d,%x)\n", x, y, flags));
if (psav->Chipset == S3_SAVAGE2000) {
tile_height = TILEHEIGHT_2000; /* 32 */
tile_size = TILE_SIZE_BYTE_2000; /* 4096 */
} else {
tile_height = TILEHEIGHT; /* 16 */
tile_size = TILE_SIZE_BYTE; /* 2048 */
}
if (!psav->bTiled) {
left = x - x % 64;
top = y;
address = (top * psav->lDelta) + left * (pScrn->bitsPerPixel >> 3);
address = (address >> 5) << 5;
} else {
top = y - y % tile_height;
if (pScrn->bitsPerPixel == 16) {
left = x - x % TILEWIDTH_16BPP;
address = top * psav->lDelta + left * tile_size / TILEWIDTH_16BPP;
} else if (pScrn->bitsPerPixel == 32) {
left = x - x % TILEWIDTH_32BPP;
address = top * psav->lDelta + left * tile_size / TILEWIDTH_32BPP;
}
}
address += pScrn->fbOffset;
if (psav->Chipset == S3_SAVAGE_MX) {
if (!crtc2) {
OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);/* IGA1 */
} else {
OUTREG32(PRI_STREAM2_FBUF_ADDR0, address & 0xFFFFFFFC);/* IGA2 */
OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFFC);
}
} else if (psav->Chipset == S3_SUPERSAVAGE) {
if (!crtc2) {
/* IGA1 */
OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
} else {
/* IGA2 */
OUTREG32(PRI_STREAM2_FBUF_ADDR0, ((address & 0xFFFFFFF8) | 0x80000000));
OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFF8);
}
} else if (psav->Chipset == S3_SAVAGE2000) {
/* certain Y values seems to cause havoc, not sure why */
OUTREG32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
OUTREG32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
} else {
OUTREG32(PRI_STREAM_FBUF_ADDR0,address | 0xFFFFFFFC);
OUTREG32(PRI_STREAM_FBUF_ADDR1,address | 0x80000000);
}
return;
}
Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
SavagePtr psav = SAVPTR(pScrn);
Bool success;
TRACE(("SavageSwitchMode\n"));
if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
SavageStreamsOff(xf86Screens[scrnIndex]);
success = SavageModeInit(xf86Screens[scrnIndex], mode);
/* switching mode on primary will reset secondary. it needs to be reset as well*/
if (psav->IsPrimary) {
DevUnion* pPriv;
SavageEntPtr pSavEnt;
pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
gSavageEntityIndex);
pSavEnt = pPriv->ptr;
SavageModeInit(pSavEnt->pSecondaryScrn, pSavEnt->pSecondaryScrn->currentMode);
}
SavagePanningCheck(pScrn, mode);
return success;
}
void SavageEnableMMIO(ScrnInfoPtr pScrn)
{
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
int vgaCRIndex, vgaCRReg;
unsigned char val;
TRACE(("SavageEnableMMIO\n"));
vgaHWSetStdFuncs(hwp);
vgaHWSetMmioFuncs(hwp, psav->MapBase, 0x8000);
val = VGAIN8(0x3c3);
VGAOUT8(0x3c3, val | 0x01);
val = VGAIN8(VGA_MISC_OUT_R);
VGAOUT8(VGA_MISC_OUT_W, val | 0x01);
vgaCRIndex = psav->vgaIOBase + 4;
vgaCRReg = psav->vgaIOBase + 5;
if( psav->Chipset >= S3_SAVAGE4 )
{
VGAOUT8(vgaCRIndex, 0x40);
val = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, val | 1);
}
return;
}
void SavageDisableMMIO(ScrnInfoPtr pScrn)
{
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
int vgaCRIndex, vgaCRReg;
unsigned char val;
TRACE(("SavageDisableMMIO\n"));
vgaCRIndex = psav->vgaIOBase + 4;
vgaCRReg = psav->vgaIOBase + 5;
if( psav->Chipset >= S3_SAVAGE4 )
{
VGAOUT8(vgaCRIndex, 0x40);
val = VGAIN8(vgaCRReg);
VGAOUT8(vgaCRReg, val | 1);
}
vgaHWSetStdFuncs(hwp);
return;
}
void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
LOCO *colors, VisualPtr pVisual)
{
SavagePtr psav = SAVPTR(pScrn);
int i, index;
int updateKey = -1;
unsigned char byte = 0;
/* choose CLUT */
if (psav->IsPrimary) {
/* enable CLUT 1 */
VGAOUT8(0x3c4, 0x21);
byte = VGAIN8(0x3c5);
VGAOUT8(0x3c5, (byte & ~0x01));
/* select CLUT 1 */
VGAOUT8(0x3c4, 0x47);
byte = VGAIN8(0x3c5);
VGAOUT8(0x3c5, (byte & ~0x03) | 0x01); /* CLUT 1 */
} else if (psav->IsSecondary) {
/* enable CLUT 2 */
VGAOUT8(0x3c4, 0x21);
byte = VGAIN8(0x3c5);
VGAOUT8(0x3c5, (byte & ~0x10));
/* select CLUT 2 */
VGAOUT8(0x3c4, 0x47);
byte = VGAIN8(0x3c5);
VGAOUT8(0x3c5, (byte & ~0x03) | 0x02); /* CLUT 2 */
}
for (i=0; i<numColors; i++) {
index = indicies[i];
if (index == pScrn->colorKey) updateKey = index;
VGAOUT8(0x3c8, index);
VGAOUT8(0x3c9, colors[index].red);
VGAOUT8(0x3c9, colors[index].green);
VGAOUT8(0x3c9, colors[index].blue);
}
/* restore saved CLUT index value */
if (psav->IsPrimary || psav->IsSecondary) {
VGAOUT8(0x3c4, 0x47);
VGAOUT8(0x3c5, byte);
}
if (updateKey != -1)
SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
colors[updateKey].blue);
}
#define Shift(v,d) ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))
static void
SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b)
{
ScreenPtr pScreen;
SavagePtr psav = SAVPTR(pScrn);
FbOverlayScrPrivPtr pScrOvlPriv;
CARD32 key;
int ul = 0, ol = 1;
if (pScrn->depth != 8) {
ul = 1;
ol = 0;
}
if (!(pScreen = pScrn->pScreen)
|| !(pScrOvlPriv = fbOverlayGetScrPriv(pScreen)))
return;
key = ((Shift(r,psav->overlay.redShift) & psav->overlay.redMask)
| (Shift(g,psav->overlay.greenShift) & psav->overlay.greenMask)
| (Shift(b,psav->overlay.blueShift) & psav->overlay.blueMask));
if (pScrOvlPriv->layer[ol].key != key) {
pScrOvlPriv->layer[ol].key = key;
(*pScrOvlPriv->PaintKey) (&pScrOvlPriv->layer[ol].u.run.pixmap->drawable,
&pScrOvlPriv->layer[ul].u.run.region,
pScrOvlPriv->layer[ol].key, ol);
}
}
#if 0
#define inStatus1() (hwp->readST01( hwp ))
#endif
void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
LOCO *colors, VisualPtr pVisual)
{
SavagePtr psav = SAVPTR(pScrn);
int i, index;
int updateKey = -1;
VerticalRetraceWait();
for (i=0; i<numColors; i++) {
if (!(inStatus1()) & 0x08)
VerticalRetraceWait();
index = indicies[i];
VGAOUT8(0x3c8, index);
VGAOUT8(0x3c9, colors[index].red);
VGAOUT8(0x3c9, colors[index].green);
VGAOUT8(0x3c9, colors[index].blue);
if (index == pScrn->colorKey) updateKey = index;
}
if (updateKey != -1)
SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
colors[updateKey].blue);
}
static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
int min_n2, int max_n2, long freq_min,
long freq_max, unsigned int *mdiv,
unsigned int *ndiv, unsigned int *r)
{
double ffreq, ffreq_min, ffreq_max;
double div, diff, best_diff;
unsigned int m;
unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
ffreq = freq / 1000.0 / BASE_FREQ;
ffreq_max = freq_max / 1000.0 / BASE_FREQ;
ffreq_min = freq_min / 1000.0 / BASE_FREQ;
if (ffreq < ffreq_min / (1 << max_n2)) {
ErrorF("invalid frequency %1.3f Mhz\n",
ffreq*BASE_FREQ);
ffreq = ffreq_min / (1 << max_n2);
}
if (ffreq > ffreq_max / (1 << min_n2)) {
ErrorF("invalid frequency %1.3f Mhz\n",
ffreq*BASE_FREQ);
ffreq = ffreq_max / (1 << min_n2);
}
/* work out suitable timings */
best_diff = ffreq;
for (n2=min_n2; n2<=max_n2; n2++) {
for (n1=min_n1+2; n1<=max_n1+2; n1++) {
m = (int)(ffreq * n1 * (1 << n2) + 0.5);
if (m < min_m+2 || m > 127+2)
continue;
div = (double)(m) / (double)(n1);
if ((div >= ffreq_min) &&
(div <= ffreq_max)) {
diff = ffreq - div / (1 << n2);
if (diff < 0.0)
diff = -diff;
if (diff < best_diff) {
best_diff = diff;
best_m = m;
best_n1 = n1;
best_n2 = n2;
}
}
}
}
*ndiv = best_n1 - 2;
*r = best_n2;
*mdiv = best_m - 2;
}
void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file)
{
unsigned char cr66;
int r, success = 0;
CARD32 fifo_control = 0, miu_control = 0;
CARD32 streams_timeout = 0, misc_timeout = 0;
vgaHWPtr hwp = VGAHWPTR(pScrn);
SavagePtr psav = SAVPTR(pScrn);
int vgaCRIndex, vgaCRReg, vgaIOBase;
TRACE(("SavageGEReset(%d,%s)\n", line, file));
vgaIOBase = hwp->IOBase;
vgaCRIndex = vgaIOBase + 4;
vgaCRReg = vgaIOBase + 5;
if (from_timeout) {
if (psav->GEResetCnt++ < 10 || xf86GetVerbosity() > 1)
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"SavageGEReset called from %s line %d\n", file, line);
} else
psav->WaitIdleEmpty(psav);
if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
fifo_control = INREG(FIFO_CONTROL_REG);
miu_control = INREG(MIU_CONTROL_REG);
streams_timeout = INREG(STREAMS_TIMEOUT_REG);
misc_timeout = INREG(MISC_TIMEOUT_REG);
}
VGAOUT8(vgaCRIndex, 0x66);
cr66 = VGAIN8(vgaCRReg);
usleep(10000);
for (r=1; r<10; r++) {
VGAOUT8(vgaCRReg, cr66 | 0x02);
usleep(10000);
VGAOUT8(vgaCRReg, cr66 & ~0x02);
usleep(10000);
if (!from_timeout)
psav->WaitIdleEmpty(psav);
OUTREG(DEST_SRC_STR, psav->Bpl << 16 | psav->Bpl);
usleep(10000);
switch(psav->Chipset) {
case S3_SAVAGE3D:
case S3_SAVAGE_MX:
success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
break;
case S3_SAVAGE4:
case S3_PROSAVAGE:
case S3_PROSAVAGEDDR:
case S3_TWISTER:
case S3_SUPERSAVAGE:
success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
break;
case S3_SAVAGE2000:
success = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
break;
}
if(!success) {
usleep(10000);
xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
"restarting S3 graphics engine reset %2d ...\n", r);
}
else
break;
}
/* At this point, the FIFO is empty and the engine is idle. */
if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
OUTREG(FIFO_CONTROL_REG, fifo_control);
OUTREG(MIU_CONTROL_REG, miu_control);
OUTREG(STREAMS_TIMEOUT_REG, streams_timeout);
OUTREG(MISC_TIMEOUT_REG, misc_timeout);
}
OUTREG(SRC_BASE, 0);
OUTREG(DEST_BASE, 0);
OUTREG(CLIP_L_R, ((0) << 16) | pScrn->displayWidth);
OUTREG(CLIP_T_B, ((0) << 16) | psav->ScissB);
OUTREG(MONO_PAT_0, ~0);
OUTREG(MONO_PAT_1, ~0);
SavageSetGBD(pScrn);
}
/* This function is used to debug, it prints out the contents of s3 regs */
void
SavagePrintRegs(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
unsigned char i;
int vgaCRIndex = 0x3d4;
int vgaCRReg = 0x3d5;
ErrorF( "SR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
for( i = 0; i < 0x70; i++ ) {
if( !(i % 16) )
ErrorF( "\nSR%xx ", i >> 4 );
VGAOUT8( 0x3c4, i );
ErrorF( " %02x", VGAIN8(0x3c5) );
}
ErrorF( "\n\nCR x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
for( i = 0; i < 0xB7; i++ ) {
if( !(i % 16) )
ErrorF( "\nCR%xx ", i >> 4 );
VGAOUT8( vgaCRIndex, i );
ErrorF( " %02x", VGAIN8(vgaCRReg) );
}
ErrorF("\n\n");
}
static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
{
SavagePtr psav = SAVPTR(pScrn);
unsigned char sr8 = 0x00, srd = 0x00;
TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
if (psav->DisplayType == MT_CRT) {
VGAOUT8(0x3c4, 0x08);
sr8 = VGAIN8(0x3c5);
sr8 |= 0x06;
VGAOUT8(0x3c5, sr8);
VGAOUT8(0x3c4, 0x0d);
srd = VGAIN8(0x3c5);
srd &= 0x03;
switch (mode) {
case DPMSModeOn:
break;
case DPMSModeStandby:
srd |= 0x10;
break;
case DPMSModeSuspend:
srd |= 0x40;
break;
case DPMSModeOff:
srd |= 0x50;
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
break;
}
VGAOUT8(0x3c4, 0x0d);
VGAOUT8(0x3c5, srd);
}
if (psav->DisplayType == MT_LCD || psav->DisplayType == MT_DFP) {
if (S3_MOBILE_TWISTER_SERIES(psav->Chipset) && psav->UseBIOS) {
SavageSetPanelEnabled(psav, (mode == DPMSModeOn));
} else {
switch (mode) {
case DPMSModeOn:
VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
VGAOUT8(0x3c5, VGAIN8(0x3c5) | 0x10);
break;
case DPMSModeStandby:
case DPMSModeSuspend:
case DPMSModeOff:
VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10);
break;
default:
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
break;
}
}
}
return;
}
static void
SavageProbeDDC(ScrnInfoPtr pScrn, int index)
{
vbeInfoPtr pVbe;
if (xf86LoadSubModule(pScrn, "vbe")) {
xf86LoaderReqSymLists(vbeSymbols, NULL);
pVbe = VBEInit(NULL, index);
ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
vbeFree(pVbe);
}
}
static unsigned int
SavageDDC1Read(ScrnInfoPtr pScrn)
{
register unsigned char tmp;
SavagePtr psav = SAVPTR(pScrn);
UnLockExtRegs();
VerticalRetraceWait();
InI2CREG(tmp,psav->I2CPort);
return ((unsigned int) (tmp & 0x08));
}
static Bool
SavageDDC1(int scrnIndex)
{
ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
SavagePtr psav = SAVPTR(pScrn);
unsigned char byte;
xf86MonPtr pMon;
UnLockExtRegs();
/* initialize chipset */
InI2CREG(byte,psav->I2CPort);
OutI2CREG(byte | 0x12,psav->I2CPort);
pMon = xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),SavageDDC1Read);
if (!pMon)
return FALSE;
xf86PrintEDID(pMon);
if (!psav->IgnoreEDID)
xf86SetDDCproperties(pScrn,pMon);
/* undo initialization */
OutI2CREG(byte,psav->I2CPort);
return TRUE;
}
static void
SavageGetTvMaxSize(SavagePtr psav)
{
if( psav->PAL ) {
psav->TVSizeX = 800;
psav->TVSizeY = 600;
}
else {
psav->TVSizeX = 640;
psav->TVSizeY = 480;
}
}
static Bool
SavagePanningCheck(ScrnInfoPtr pScrn, DisplayModePtr pMode)
{
SavagePtr psav = SAVPTR(pScrn);
psav->iResX = pMode->CrtcHDisplay;
psav->iResY = pMode->CrtcVDisplay;
if ((psav->iResX < psav->PanelX || psav->iResY < psav->PanelY))
psav->FPExpansion = TRUE;
else
psav->FPExpansion = FALSE;
if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
return TRUE;
else
return FALSE;
}
static void
SavageResetStreams(ScrnInfoPtr pScrn)
{
SavagePtr psav = SAVPTR(pScrn);
unsigned char cr67;
unsigned char cr69;
/* disable streams */
switch (psav->Chipset) {
case S3_SAVAGE_MX:
case S3_SUPERSAVAGE:
OUTREG32(PRI_STREAM_STRIDE,0);
OUTREG32(PRI_STREAM2_STRIDE, 0);
OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
OUTREG8(CRT_ADDRESS_REG, 0x67);
cr67 = INREG8(CRT_DATA_REG);
cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
OUTREG8(CRT_DATA_REG, cr67);
break;
case S3_SAVAGE3D:
case S3_SAVAGE4:
case S3_TWISTER:
case S3_PROSAVAGE:
case S3_PROSAVAGEDDR:
OUTREG32(PRI_STREAM_STRIDE,0);
OUTREG32(PRI_STREAM_FBUF_ADDR0,0);
OUTREG32(PRI_STREAM_FBUF_ADDR1,0);
OUTREG8(CRT_ADDRESS_REG, 0x67);
cr67 = INREG8(CRT_DATA_REG);
cr67 &= ~0x0c; /* CR67[2] = 1 : enable stream 1 */
OUTREG8(CRT_DATA_REG, cr67);
OUTREG8(CRT_ADDRESS_REG, 0x69);
cr69 = INREG8(CRT_DATA_REG);
cr69 &= ~0x80; /* CR69[0] = 1 : Mem-mapped regs */
OUTREG8(CRT_DATA_REG, cr69);
break;
case S3_SAVAGE2000:
OUTREG32(PRI_STREAM_STRIDE,0);
OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
OUTREG8(CRT_ADDRESS_REG, 0x67);
cr67 = INREG8(CRT_DATA_REG);
cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
OUTREG8(CRT_DATA_REG, cr67);
break;
default:
break;
}
}