summaryrefslogtreecommitdiff
path: root/src/savage_driver.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 16:48:55 +0000
commitbe3817e94d5c31cd15aa4785cb5b0bdefc45141c (patch)
tree1c89ec3834e348b290ffa7a7c5ddb11958ed5360 /src/savage_driver.c
Initial revisionXORG-STABLE
Diffstat (limited to 'src/savage_driver.c')
-rw-r--r--src/savage_driver.c3282
1 files changed, 3282 insertions, 0 deletions
diff --git a/src/savage_driver.c b/src/savage_driver.c
new file mode 100644
index 0000000..cdfe256
--- /dev/null
+++ b/src/savage_driver.c
@@ -0,0 +1,3282 @@
+/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/savage/savage_driver.c,v 1.34 2003/02/25 04:08:21 dawes Exp $ */
+/*
+ * vim: sw=4 ts=8 ai ic:
+ *
+ * XFree86 4.0 S3 Savage driver
+ *
+ * Tim Roberts <timr@probo.com>
+ * Ani Joshi <ajoshi@unixbox.com>
+ *
+ * TODO: add credits for the 3.3.x authors...
+ *
+ */
+
+
+#include "xf86RAC.h"
+#include "shadowfb.h"
+
+#include "globals.h"
+#define DPMS_SERVER
+#include "extensions/dpms.h"
+
+#ifdef XvExtension
+#include "xf86xv.h"
+#endif
+
+#include "savage_driver.h"
+#include "savage_bci.h"
+
+
+
+
+/*
+ * prototypes
+ */
+static void SavageEnableMMIO(ScrnInfoPtr pScrn);
+static void SavageDisableMMIO(ScrnInfoPtr pScrn);
+
+static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid);
+static void SavageIdentify(int flags);
+static Bool SavageProbe(DriverPtr drv, int flags);
+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 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 SavageMapMMIO(ScrnInfoPtr pScrn);
+static Bool SavageMapFB(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 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);
+
+extern ScrnInfoPtr gpScrn;
+
+#define iabs(a) ((int)(a)>0?(a):(-(a)))
+
+#define DRIVER_NAME "savage"
+#define DRIVER_VERSION "1.1.26"
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 1
+#define PATCHLEVEL 26
+#define SAVAGE_VERSION ((VERSION_MAJOR << 24) | \
+ (VERSION_MINOR << 16) | \
+ PATCHLEVEL)
+
+
+/*#define TRACEON*/
+#ifdef TRACEON
+#define TRACE(prms) ErrorF prms
+#else
+#define TRACE(prms)
+#endif
+
+DriverRec SAVAGE =
+{
+ SAVAGE_VERSION,
+ DRIVER_NAME,
+ SavageIdentify,
+ SavageProbe,
+ SavageAvailableOptions,
+ NULL,
+ 0
+};
+
+
+/* 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, "ProSavage PN133" },
+ { PCI_CHIP_S3TWISTER_K, "ProSavage 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_SUPERSAVAGE, "SuperSavage" },
+ { -1, NULL }
+};
+
+/* 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_PROSAVAGE, PCI_CHIP_S3TWISTER_P, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_S3TWISTER_K, RES_SHARED_VGA },
+ { S3_PROSAVAGE, PCI_CHIP_PROSAVAGE_DDR, RES_SHARED_VGA },
+ { S3_PROSAVAGE, 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 }
+};
+
+typedef enum {
+ OPTION_PCI_BURST
+ ,OPTION_PCI_RETRY
+ ,OPTION_NOACCEL
+ ,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
+} SavageOpts;
+
+
+static const OptionInfoRec SavageOptions[] =
+{
+ { OPTION_NOACCEL, "NoAccel", OPTV_BOOLEAN, {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 },
+ { -1, NULL, OPTV_NONE, {0}, FALSE }
+};
+
+
+static const char *vgaHWSymbols[] = {
+ "vgaHWBlankScreen",
+ "vgaHWCopyReg",
+ "vgaHWGetHWRec",
+ "vgaHWGetIOBase",
+ "vgaHWGetIndex",
+ "vgaHWInit",
+ "vgaHWLock",
+ "vgaHWProtect",
+ "vgaHWRestore",
+ "vgaHWSave",
+ "vgaHWSaveScreen",
+ "vgaHWSetMmioFuncs",
+ "vgaHWSetStdFuncs",
+ "vgaHWUnmapMem",
+ "vgaHWddc1SetSpeed",
+#if 0
+ "vgaHWFreeHWRec",
+ "vgaHWMapMem",
+ "vgaHWUnlock",
+#endif
+ NULL
+};
+
+static const char *ramdacSymbols[] = {
+ "xf86CreateCursorInfoRec",
+#if 0
+ "xf86DestroyCursorInfoRec",
+#endif
+ "xf86InitCursor",
+ NULL
+};
+
+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",
+ NULL
+};
+
+static const char *xaaSymbols[] = {
+ "XAACopyROP",
+ "XAACopyROP_PM",
+ "XAACreateInfoRec",
+ "XAADestroyInfoRec",
+ "XAAFillSolidRects",
+ "XAAHelpPatternROP",
+ "XAAHelpSolidROP",
+ "XAAInit",
+ "XAAScreenIndex",
+ NULL
+};
+
+static const char *shadowSymbols[] = {
+ "ShadowFBInit",
+ NULL
+};
+
+static const char *int10Symbols[] = {
+ "xf86ExecX86int10",
+#if 0
+ "xf86FreeInt10",
+#endif
+ "xf86InitInt10",
+ "xf86Int10AllocPages",
+ "xf86Int10FreePages",
+ "xf86int10Addr",
+ NULL
+};
+
+static const char *fbSymbols[] = {
+ "fbPictureInit",
+ "fbScreenInit",
+ NULL
+};
+
+#ifdef XFree86LOADER
+
+static MODULESETUPPROTO(SavageSetup);
+
+static XF86ModuleVersionInfo SavageVersRec = {
+ "savage",
+ MODULEVENDORSTRING,
+ MODINFOSTRING1,
+ MODINFOSTRING2,
+ XF86_VERSION_CURRENT,
+ VERSION_MAJOR, VERSION_MINOR, PATCHLEVEL,
+ ABI_CLASS_VIDEODRV,
+ ABI_VIDEODRV_VERSION,
+ MOD_CLASS_VIDEODRV,
+ {0, 0, 0, 0}
+};
+
+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, 0);
+ LoaderRefSymLists(vgaHWSymbols, fbSymbols, ramdacSymbols,
+ xaaSymbols, shadowSymbols, vbeSymbols, vbeOptSymbols,
+ int10Symbols, i2cSymbols, ddcSymbols, NULL);
+ return (pointer) 1;
+ } else {
+ if (errmaj)
+ *errmaj = LDR_ONCEONLY;
+ return NULL;
+ }
+}
+
+#endif /* XFree86LOADER */
+
+
+/*
+ * 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 = %08x...\n", 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) & 0x7fff;
+ BCI_SEND( psav->dwBCIWait2DIdle );
+ BCI_SEND( 0x98000000 + psav->ShadowCounter );
+
+ while(
+ (psav->ShadowVirtual[1] & 0x7fff) != psav->ShadowCounter &&
+ (loop++ < MAXLOOP)
+ )
+ ;
+
+ return loop >= MAXLOOP;
+}
+
+static Bool
+ShadowWait1( SavagePtr psav, int v )
+{
+ return ShadowWait( psav );
+}
+
+
+/* Wait until "v" queue entries are free */
+
+static int
+WaitQueue3D( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ else
+ {
+ loop &= STATUS_WORD0;
+ while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
+ ;
+ }
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitQueue4( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ if( !psav->NoPCIRetry )
+ return 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ else
+ while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP))
+ ;
+ return loop >= MAXLOOP;
+}
+
+static int
+WaitQueue2K( SavagePtr psav, int v )
+{
+ int loop = 0;
+ int slots = MAXFIFO - v;
+
+ if( !psav->NoPCIRetry )
+ return 0;
+ mem_barrier();
+ if( psav->ShadowVirtual )
+ {
+ psav->WaitQueue = ShadowWait1;
+ return ShadowWait(psav);
+ }
+ 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);
+ }
+ while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) )
+ ;
+ 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);
+ }
+ while( (!(ALT_STATUS_WORD0 & 0x00800000)) && (loop++ < MAXLOOP) )
+ ;
+ 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;
+ xfree(pScrn->driverPrivate);
+ pScrn->driverPrivate = NULL;
+ SavageUnmapMem(pScrn, 1);
+}
+
+
+static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid)
+{
+ return SavageOptions;
+}
+
+
+static void SavageIdentify(int flags)
+{
+ xf86PrintChipsets("SAVAGE",
+ "driver (version " DRIVER_VERSION ") for S3 Savage chipsets",
+ SavageChips);
+}
+
+
+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)
+ 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++) {
+ ScrnInfoPtr pScrn = xf86AllocateScreen(drv, 0);
+
+ pScrn->driverVersion = (int)DRIVER_VERSION;
+ pScrn->driverName = 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;
+ xf86ConfigActivePciEntity(pScrn, usedChips[i], SavagePciChipsets,
+ NULL, NULL, NULL, NULL, NULL);
+ }
+
+ 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;
+}
+
+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;
+ pointer ddc;
+
+ 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, 8, 8, 8, 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/*6*/;
+
+ 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_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");
+ }
+
+ if ((s = xf86GetOptValString(psav->Options, OPTION_ROTATE))) {
+ if(!xf86NameCmp(s, "CW")) {
+ /* accel is disabled below for shadowFB */
+ psav->shadowFB = TRUE;
+ psav->rotate = 1;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
+ "Rotating screen clockwise - acceleration disabled\n");
+ } else if(!xf86NameCmp(s, "CCW")) {
+ psav->shadowFB = TRUE;
+ psav->rotate = -1;
+ xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Rotating screen"
+ "counter clockwise - acceleration 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 (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 enabled\n" );
+
+
+ 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" );
+
+ /* Add more options here. */
+
+ 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, "int10")) {
+ xf86LoaderReqSymLists(int10Symbols, NULL);
+ psav->pInt10 = xf86InitInt10(pEnt->index);
+ }
+
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ xf86LoaderReqSymLists(vbeSymbols, NULL);
+ psav->pVbe = VBEInit(psav->pInt10, pEnt->index);
+ }
+
+
+ psav->PciInfo = xf86GetPciInfoForEntity(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;
+ psav->Chipset = xf86StringToToken(SavageChipsets, pScrn->chipset);
+ from = X_CONFIG;
+ } else if (pEnt->device->chipID >= 0) {
+ psav->ChipId = pEnt->device->chipID;
+ psav->Chipset = LookupChipID(SavagePciChipsets, psav->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 = psav->PciInfo->chipType;
+ psav->Chipset = LookupChipID(SavagePciChipsets, psav->ChipId);
+ 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 = psav->PciInfo->chipRev;
+
+ if (pEnt->device->videoRam != 0)
+ pScrn->videoRam = pEnt->device->videoRam;
+
+ xfree(pEnt);
+
+ /* maybe throw in some more sanity checks here */
+
+ xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
+
+ psav->PciTag = pciTag(psav->PciInfo->bus, psav->PciInfo->device,
+ psav->PciInfo->func);
+
+
+ if (!SavageMapMMIO(pScrn)) {
+ vbeFree(psav->pVbe);
+ 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);
+ 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 unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
+ static unsigned char RamSavage4[] = { 2, 4, 8, 12, 16, 32, 64, 32 };
+ static unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
+ static 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:
+ 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);
+ }
+
+ 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->CursorKByte = pScrn->videoRam - 4;
+ psav->cobIndex = 0;
+ psav->cobSize = 0;
+ psav->cobOffset = psav->videoRambytes;
+ }
+ else if( (S3_SAVAGE4_SERIES(psav->Chipset)) ||
+ (S3_SUPERSAVAGE == psav->Chipset) ) {
+ /*
+ * The Savage4 and ProSavage have COB coherency bugs which render
+ * the buffer useless. COB seems to make the SuperSavage slower.
+ * We disable it.
+ */
+ psav->CursorKByte = pScrn->videoRam - 4;
+ psav->cobIndex = 2;
+ psav->cobSize = 0x8000 << psav->cobIndex;
+ psav->cobOffset = psav->videoRambytes;
+ }
+ else
+ {
+ /* We use 128kB for the COB on all other chips. */
+
+ psav->cobSize = 1 << 17;
+ if (psav->Chipset == S3_SUPERSAVAGE) {
+ psav->cobIndex = 2;
+ }
+ else {
+ psav->cobIndex = 7;
+ }
+ psav->cobOffset = psav->videoRambytes - psav->cobSize;
+ }
+
+ /*
+ * We place the cursor in high memory, just before the command overflow
+ * buffer. The cursor must be aligned on a 4k boundary.
+ */
+
+ psav->CursorKByte = (psav->cobOffset >> 10) - 4;
+
+ /* 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. */
+
+ switch( psav->Chipset ) {
+ case S3_SAVAGE3D:
+ case S3_SAVAGE_MX:
+ psav->WaitQueue = WaitQueue3D;
+ psav->WaitIdle = WaitIdle3D;
+ psav->WaitIdleEmpty = WaitIdleEmpty3D;
+ break;
+
+ case S3_SAVAGE4:
+ case S3_PROSAVAGE:
+ case S3_SUPERSAVAGE:
+ psav->WaitQueue = WaitQueue4;
+ psav->WaitIdle = WaitIdle4;
+ psav->WaitIdleEmpty = WaitIdleEmpty4;
+ break;
+
+ case S3_SAVAGE2000:
+ psav->WaitQueue = WaitQueue2K;
+ psav->WaitIdle = WaitIdle2K;
+ psav->WaitIdleEmpty = WaitIdleEmpty2K;
+ break;
+ }
+
+ /* Do the DDC dance. */
+
+ if( psav->Chipset != S3_PROSAVAGE ) {
+ ddc = xf86LoadSubModule(pScrn, "ddc");
+ if (ddc) {
+#if 0
+ xf86MonPtr pMon = NULL;
+#endif
+
+ xf86LoaderReqSymLists(ddcSymbols, NULL);
+#if 0
+/*
+ * On many machines, the attempt to read DDC information via VBE puts the
+ * BIOS access into a state which prevents me from reading mode information.
+ * This is a complete mystery to me.
+ */
+ if ((psav->pVbe)
+ && ((pMon = xf86PrintEDID(vbeDoEDID(psav->pVbe, ddc))) != NULL))
+ xf86SetDDCproperties(pScrn,pMon);
+ else
+#endif
+ if (!SavageDDC1(pScrn->scrnIndex)) {
+ if ( xf86LoadSubModule(pScrn, "i2c") ) {
+ xf86LoaderReqSymLists(i2cSymbols,NULL);
+ if (SavageI2CInit(pScrn)) {
+ unsigned char tmp;
+
+ InI2CREG(psav,tmp);
+ OutI2CREG(psav,tmp | 0x13);
+ xf86SetDDCproperties(pScrn,xf86PrintEDID(
+ xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C)));
+ OutI2CREG(psav,tmp);
+ }
+ }
+ }
+ }
+ }
+
+ /* Savage ramdac speeds */
+ pScrn->numClocks = 4;
+ pScrn->clock[0] = 250000;
+ pScrn->clock[1] = 250000;
+ pScrn->clock[2] = 220000;
+ pScrn->clock[3] = 220000;
+
+ if (psav->dacSpeedBpp <= 0) {
+ if (pScrn->bitsPerPixel > 24)
+ psav->dacSpeedBpp = pScrn->clock[3];
+ else if (pScrn->bitsPerPixel >= 24)
+ psav->dacSpeedBpp = pScrn->clock[2];
+ else if ((pScrn->bitsPerPixel > 8) && (pScrn->bitsPerPixel < 24))
+ psav->dacSpeedBpp = pScrn->clock[1];
+ else if (pScrn->bitsPerPixel <= 8)
+ psav->dacSpeedBpp = pScrn->clock[0];
+ }
+
+ /* Set ramdac limits */
+ psav->maxClock = psav->dacSpeedBpp;
+
+ /* 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);
+
+ psav->minClock = 10000;
+
+ 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( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) && !psav->CrtOnly )
+ {
+ unsigned char cr6b = hwp->readCrtc( hwp, 0x6b );
+
+ int panelX = (hwp->readSeq(hwp, 0x61) +
+ ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
+ int panelY = hwp->readSeq(hwp, 0x69) +
+ ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
+
+ char * sTechnology = "Unknown";
+
+ /* 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.
+ */
+
+ enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
+ ActiveCRT = 0x01,
+ ActiveLCD = 0x02,
+ ActiveTV = 0x04,
+ ActiveCRT2 = 0x20,
+ ActiveDUO = 0x80
+ };
+
+ 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;
+
+ 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 );
+ }
+ }
+ }
+
+ clockRanges = xnfcalloc(sizeof(ClockRange),1);
+ clockRanges->next = NULL;
+ clockRanges->minClock = psav->minClock;
+ 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);
+ 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);
+ return FALSE;
+ }
+
+ 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, pScrn->bitsPerPixel );
+
+ 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");
+ }
+ }
+ }
+
+ 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);
+ return FALSE;
+ }
+
+ xf86LoaderReqSymLists(fbSymbols, NULL);
+
+ if( !psav->NoAccel ) {
+ if( !xf86LoadSubModule(pScrn, "xaa") ) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(xaaSymbols, NULL );
+ }
+
+ if (psav->hwcursor) {
+ if (!xf86LoadSubModule(pScrn, "ramdac")) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(ramdacSymbols, NULL);
+ }
+
+ if (psav->shadowFB) {
+ if (!xf86LoadSubModule(pScrn, "shadowfb")) {
+ SavageFreeRec(pScrn);
+ vbeFree(psav->pVbe);
+ return FALSE;
+ }
+ xf86LoaderReqSymLists(shadowSymbols, NULL);
+ }
+ vbeFree(psav->pVbe);
+
+ return TRUE;
+}
+
+
+static Bool SavageEnterVT(int scrnIndex, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ TRACE(("SavageEnterVT(%d)\n", flags));
+
+ gpScrn = pScrn;
+ SavageEnableMMIO(pScrn);
+ SavageSave(pScrn);
+ return SavageModeInit(pScrn, pScrn->currentMode);
+}
+
+
+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;
+
+ TRACE(("SavageLeaveVT(%d)\n", flags));
+ gpScrn = pScrn;
+ SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
+ 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 regsters. */
+
+ if( S3_SAVAGE_MOBILE_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, cr67;
+ 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));
+
+ 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);
+
+ /* Set the color mode. */
+
+ VGAOUT8(vgaCRIndex, 0x67);
+ VGAOUT8(vgaCRReg, restore->CR67);
+
+ /* Enable gamma correction. */
+
+ VGAOUT8(0x3c4, 0x1b);
+ if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive )
+ VGAOUT8(0x3c5, 0x28 );
+ else
+ VGAOUT8(0x3c5, 0x00 );
+
+ /* 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(pScrn->bitsPerPixel == 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( pScrn->bitsPerPixel == 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 * (pScrn->bitsPerPixel / 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;
+ }
+
+ SavageInitialize2DEngine(pScrn);
+ SavageSetGBD(pScrn);
+
+ VGAOUT16(vgaCRIndex, 0x0140);
+
+ SavageSetGBD(pScrn);
+
+ 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->pInt10 ) {
+ SavageSetTextMode( psav );
+ }
+
+ VGAOUT8(vgaCRIndex, 0x67);
+ cr67 = VGAIN8(vgaCRReg);
+ VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c); /* no STREAMS yet */
+
+ /* 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 regsters. */
+ if( S3_SAVAGE_MOBILE_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 */
+
+ /* 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);
+ 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 & ~0x28);
+ 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(psav);
+ 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(psav);
+ 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 )
+ SavageSetGBD(pScrn);
+
+ vgaHWProtect(pScrn, FALSE);
+
+ return;
+}
+
+
+static Bool SavageMapMMIO(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav;
+
+ TRACE(("SavageMapMMIO()\n"));
+
+ psav = SAVPTR(pScrn);
+
+ if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
+ psav->MmioBase = psav->PciInfo->memBase[0] + SAVAGE_NEWMMIO_REGBASE_S3;
+ psav->FrameBufferBase = psav->PciInfo->memBase[0];
+ }
+ else {
+ psav->MmioBase = psav->PciInfo->memBase[0] + SAVAGE_NEWMMIO_REGBASE_S4;
+ psav->FrameBufferBase = psav->PciInfo->memBase[1];
+ }
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "mapping MMIO @ 0x%x with size 0x%x\n",
+ psav->MmioBase, SAVAGE_NEWMMIO_REGSIZE);
+
+ psav->MapBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO, psav->PciTag,
+ psav->MmioBase,
+ SAVAGE_NEWMMIO_REGSIZE);
+#if 0
+ psav->MapBaseDense = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO_32BIT,
+ psav->PciTag,
+ psav->PciInfo->memBase[0],
+ 0x8000);
+#endif
+ if (!psav->MapBase) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal error: cound not map registers\n");
+ return FALSE;
+ }
+
+ psav->BciMem = psav->MapBase + 0x10000;
+
+ SavageEnableMMIO(pScrn);
+
+ return TRUE;
+}
+
+
+
+static Bool SavageMapFB(ScrnInfoPtr pScrn)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+
+ TRACE(("SavageMapFB()\n"));
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "mapping framebuffer @ 0x%x with size 0x%x\n",
+ psav->FrameBufferBase, psav->videoRambytes);
+
+ if (psav->videoRambytes) {
+ psav->FBBase = xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
+ psav->PciTag, psav->FrameBufferBase,
+ psav->videoRambytes);
+ if (!psav->FBBase) {
+ xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
+ "Internal error: could not map framebuffer\n");
+ return FALSE;
+ }
+ psav->FBStart = psav->FBBase;
+ }
+ pScrn->memPhysBase = psav->PciInfo->memBase[0];
+ pScrn->fbOffset = 0;
+
+ return TRUE;
+}
+
+
+static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
+{
+ SavagePtr psav;
+
+ 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->MapBase) {
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBase,
+ SAVAGE_NEWMMIO_REGSIZE);
+ psav->MapBase = 0;
+ }
+
+ if (psav->FBBase) {
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->FBBase,
+ psav->videoRambytes);
+ psav->FBBase = 0;
+ }
+
+#if 0
+ xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBaseDense,
+ 0x8000);
+#endif
+
+ return;
+}
+
+
+static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen,
+ int argc, char **argv)
+{
+ ScrnInfoPtr pScrn;
+ SavagePtr psav;
+ EntityInfoPtr pEnt;
+ int ret;
+
+ TRACE(("SavageScreenInit()\n"));
+
+ pScrn = xf86Screens[pScreen->myNum];
+ psav = SAVPTR(pScrn);
+
+ pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
+ psav->pVbe = VBEInit(NULL, pEnt->index);
+
+ SavageEnableMMIO(pScrn);
+
+ if (!SavageMapFB(pScrn))
+ return FALSE;
+
+ if( psav->ShadowStatus ) {
+ psav->ShadowPhysical =
+ psav->FrameBufferBase + psav->CursorKByte*1024 + 4096 - 32;
+
+ psav->ShadowVirtual = (CARD32 *)
+ (psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
+
+ xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
+ "Shadow area physical %08x, linear %08x\n",
+ psav->ShadowPhysical, psav->ShadowVirtual );
+
+ psav->WaitQueue = ShadowWait1;
+ psav->WaitIdle = ShadowWait;
+ psav->WaitIdleEmpty = ShadowWait;
+
+ if( psav->Chipset == S3_SAVAGE2000 )
+ psav->dwBCIWait2DIdle = 0xc0040000;
+ else
+ psav->dwBCIWait2DIdle = 0xc0020000;
+ }
+ psav->ShadowCounter = 0;
+
+ SavageSave(pScrn);
+
+ vgaHWBlankScreen(pScrn, TRUE);
+
+ if (!SavageModeInit(pScrn, pScrn->currentMode))
+ return FALSE;
+
+ miClearVisualTypes();
+
+ if (pScrn->bitsPerPixel == 16) {
+ if (!miSetVisualTypes(pScrn->depth, TrueColorMask,
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths ())
+ return FALSE;
+ } else {
+ if (!miSetVisualTypes(pScrn->depth, miGetDefaultVisualMask(pScrn->depth),
+ pScrn->rgbBits, pScrn->defaultVisual))
+ return FALSE;
+ if (!miSetPixmapDepths ())
+ return FALSE;
+ }
+
+ ret = SavageInternalScreenInit(scrnIndex, pScreen);
+ if (!ret)
+ return FALSE;
+
+ xf86SetBlackWhitePixels(pScreen);
+
+ if (pScrn->bitsPerPixel > 8) {
+ VisualPtr visual;
+
+ visual = pScreen->visuals + pScreen->numVisuals;
+ while (--visual >= pScreen->visuals) {
+ if ((visual->class | DynamicClass) == DirectColor) {
+ visual->offsetRed = pScrn->offset.red;
+ visual->offsetGreen = pScrn->offset.green;
+ visual->offsetBlue = pScrn->offset.blue;
+ visual->redMask = pScrn->mask.red;
+ visual->greenMask = pScrn->mask.green;
+ visual->blueMask = pScrn->mask.blue;
+ }
+ }
+ }
+
+ /* must be after RGB ordering fixed */
+ fbPictureInit (pScreen, 0, 0);
+
+ if( !psav->NoAccel ) {
+ SavageInitAccel(pScreen);
+ }
+
+ miInitializeBackingStore(pScreen);
+ xf86SetBackingStore(pScreen);
+
+ if( !psav->shadowFB )
+ 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;
+
+ if (psav->Chipset == S3_SAVAGE4) {
+ if (!xf86HandleColormaps(pScreen, 256, 6, SavageLoadPaletteSavage4,
+ NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH
+ | CMAP_PALETTED_TRUECOLOR
+ ))
+ return FALSE;
+ } else {
+ if (!xf86HandleColormaps(pScreen, 256, 6, SavageLoadPalette, NULL,
+ CMAP_RELOAD_ON_MODE_SWITCH
+ | CMAP_PALETTED_TRUECOLOR
+ ))
+ 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 XvExtension
+ if( !psav->NoAccel && !SavagePanningCheck(pScrn) )
+ SavageInitVideo( pScreen );
+#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;
+ }
+
+ ret = fbScreenInit(pScreen, FBStart, width, height,
+ pScrn->xDpi, pScrn->yDpi,
+ displayWidth,
+ pScrn->bitsPerPixel);
+ return ret;
+}
+
+
+static ModeStatus SavageValidMode(int index, DisplayModePtr pMode,
+ Bool verbose, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[index];
+ SavagePtr psav = SAVPTR(pScrn);
+
+ 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->CrtOnly &&
+ psav->PanelX &&
+ (
+ (pMode->HDisplay > psav->PanelX) ||
+ (pMode->VDisplay > psav->PanelY)
+ )
+ )
+ return MODE_PANEL;
+
+ 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;
+
+ 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 (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->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 (pScrn->bitsPerPixel == 24 )
+ new->CR67 = 0x70;
+ else
+ new->CR67 = 0xd0;
+ break;
+ }
+
+ if( psav->UseBIOS ) {
+ int refresh;
+ SavageModeEntryPtr pmt;
+
+ /* Scan through our BIOS list to locate the closest valid mode. */
+
+ /* If we ever break 4GHz clocks on video boards, we'll need to
+ * change this.
+ */
+
+ refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
+
+#ifdef EXTENDED_DEBUG
+ ErrorF( "Desired refresh rate = %dHz\n", refresh );
+#endif
+
+ for( i = 0, pmt = psav->ModeTable->Modes;
+ i < psav->ModeTable->NumModes;
+ i++, pmt++ )
+ {
+ if( (pmt->Width == mode->HDisplay) &&
+ (pmt->Height == mode->VDisplay) )
+ {
+ int jDelta = 99;
+ int jBest = 0;
+
+ /* We have an acceptable mode. Find a refresh rate. */
+
+ new->mode = pmt->VesaMode;
+ for( j = 0; j < pmt->RefreshCount; j++ )
+ {
+ if( pmt->RefreshRate[j] == refresh )
+ {
+ /* Exact match. */
+ jBest = j;
+ break;
+ }
+ else if( iabs(pmt->RefreshRate[j] - refresh) < jDelta )
+ {
+ jDelta = iabs(pmt->RefreshRate[j] - refresh);
+ jBest = j;
+ }
+ }
+
+ new->refresh = pmt->RefreshRate[jBest];
+ break;
+ }
+ }
+
+ if( new->mode ) {
+ /* Success: we found a match in the BIOS. */
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "Chose mode %x at %dHz.\n", new->mode, new->refresh );
+ }
+ else {
+ xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
+ "No suitable BIOS mode found for %dx%d %dMHz.\n",
+ mode->HDisplay, mode->VDisplay, mode->Clock/1000 );
+ }
+ }
+
+ 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;
+
+/* VGAOUT8(0x3c4, 0x1b);
+ new->SR1B = VGAIN8(0x3c5);
+ if( pScrn->depth == 24 )
+ new->SR1B |= 0x28;
+*/
+ if( pScrn->depth == 24 )
+ new->SR1B = 0x28;
+ else
+ new->SR1B = 0x00;
+
+
+ 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 (pScrn->bitsPerPixel < 24)
+ new->MMPR0 -= 0x8000;
+ else
+ new->MMPR0 -= 0x4000;
+ } else if (psav->fifo_aggressive) {
+ if (pScrn->bitsPerPixel < 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 * (pScrn->bitsPerPixel / 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 (pScrn->bitsPerPixel <= 8)
+ new->CR50 = 0;
+ else if (pScrn->bitsPerPixel <= 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, 0x88);
+ new->CR86 = VGAIN8(vgaCRReg) | 0x08;
+ VGAOUT8(vgaCRIndex, 0xb0);
+ new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
+ }
+
+ pScrn->vtSema = TRUE;
+
+ /* do it! */
+ SavageWriteMode(pScrn, vganew, new, TRUE);
+ 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"));
+
+ if (psav->pVbe)
+ vbeFree(psav->pVbe);
+ psav->pVbe = 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) {
+ SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
+ vgaHWLock(hwp);
+ SavageUnmapMem(pScrn, 0);
+ }
+
+ 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;
+ }
+
+ return vgaHWSaveScreen(pScreen, mode);
+}
+
+
+void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ SavagePtr psav = SAVPTR(pScrn);
+ int Base;
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+
+ TRACE(("SavageAdjustFrame(%d,%d,%x)\n", x, y, flags));
+
+ if (psav->ShowCache && y)
+ y += pScrn->virtualY - 1;
+
+ Base = ((y * pScrn->displayWidth + (x&~1)) *
+ (pScrn->bitsPerPixel / 8)) >> 2;
+ /* now program the start address registers */
+ VGAOUT16(vgaCRIndex, (Base & 0x00ff00) | 0x0c);
+ VGAOUT16(vgaCRIndex, ((Base & 0x00ff) << 8) | 0x0d);
+ VGAOUT8(vgaCRIndex, 0x69);
+ VGAOUT8(vgaCRReg, (Base & 0x7f0000) >> 16);
+
+ return;
+}
+
+
+Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
+{
+ TRACE(("SavageSwitchMode\n"));
+ return SavageModeInit(xf86Screens[scrnIndex], mode);
+}
+
+
+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;
+
+ for (i=0; i<numColors; i++) {
+ index = indicies[i];
+ VGAOUT8(0x3c8, index);
+ VGAOUT8(0x3c9, colors[index].red);
+ VGAOUT8(0x3c9, colors[index].green);
+ VGAOUT8(0x3c9, colors[index].blue);
+ }
+}
+
+#define inStatus1() (hwp->readST01( hwp ))
+
+void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
+ LOCO *colors, VisualPtr pVisual)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ int i, index;
+
+ vgaHWPtr hwp = VGAHWPTR(pScrn);
+ int vgaCRIndex, vgaCRReg, vgaIOBase;
+ vgaIOBase = hwp->IOBase;
+ vgaCRIndex = vgaIOBase + 4;
+ vgaCRReg = vgaIOBase + 5;
+ VerticalRetraceWait(psav);
+
+ for (i=0; i<numColors; i++) {
+ if (!(inStatus1()) & 0x08)
+ VerticalRetraceWait(psav);
+ index = indicies[i];
+ VGAOUT8(0x3c8, index);
+ VGAOUT8(0x3c9, colors[index].red);
+ VGAOUT8(0x3c9, colors[index].green);
+ VGAOUT8(0x3c9, colors[index].blue);
+ }
+}
+
+
+
+static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
+
+ /* Make sure linear addressing is enabled after the BIOS call. */
+ /* Note that we must use an I/O port to do this. */
+ 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_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));
+
+ 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);
+
+ return;
+}
+
+
+static unsigned int
+SavageDDC1Read(ScrnInfoPtr pScrn)
+{
+ register vgaHWPtr hwp = VGAHWPTR(pScrn);
+ register unsigned char tmp;
+ SavagePtr psav = SAVPTR(pScrn);
+
+ VerticalRetraceWait(psav);
+
+ InI2CREG(psav,tmp);
+ while (hwp->readST01(hwp)&0x8) {};
+ while (!(hwp->readST01(hwp)&0x8)) {};
+
+ return ((unsigned int) (tmp & 0x08));
+}
+
+static Bool
+SavageDDC1(int scrnIndex)
+{
+ ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
+ SavagePtr psav = SAVPTR(pScrn);
+ unsigned char tmp;
+ Bool success = FALSE;
+ xf86MonPtr pMon;
+
+ /* initialize chipset */
+ InI2CREG(psav,tmp);
+ OutI2CREG(psav,tmp | 0x12);
+
+ if ((pMon = xf86PrintEDID(
+ xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeed,SavageDDC1Read))) != NULL)
+ success = TRUE;
+ xf86SetDDCproperties(pScrn,pMon);
+
+ /* undo initialization */
+ OutI2CREG(psav,tmp);
+ return success;
+}
+
+
+static void
+SavageProbeDDC(ScrnInfoPtr pScrn, int index)
+{
+ vbeInfoPtr pVbe;
+ if (xf86LoadSubModule(pScrn, "vbe")) {
+ pVbe = VBEInit(NULL,index);
+ ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
+ vbeFree(pVbe);
+ }
+}
+
+
+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)
+{
+ SavagePtr psav = SAVPTR(pScrn);
+ DisplayModePtr pMode;
+
+ pMode = pScrn->currentMode;
+ psav->iResX = pMode->CrtcHDisplay;
+ psav->iResY = pMode->CrtcVDisplay;
+ if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
+ return TRUE;
+ else
+ return FALSE;
+}
+
+