savage_driver.c revision ab47cfaa
1/*
2 * Copyright (C) 1994-2000 The XFree86 Project, Inc.  All Rights Reserved.
3 * Copyright (c) 2003-2006, X.Org Foundation
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 * COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 *
23 * Except as contained in this notice, the name of the copyright holder(s)
24 * and author(s) shall not be used in advertising or otherwise to promote
25 * the sale, use or other dealings in this Software without prior written
26 * authorization from the copyright holder(s) and author(s).
27 */
28
29/**
30 * \file savage_driver.c
31 *
32 * \author Tim Roberts <timr@probo.com>
33 * \author Ani Joshi <ajoshi@unixbox.com>
34 *
35 * \todo Add credits for the 3.3.x authors.
36 */
37
38#ifdef HAVE_CONFIG_H
39#include "config.h"
40#endif
41
42#include "xf86RAC.h"
43#include "shadowfb.h"
44
45#include "globals.h"
46#define DPMS_SERVER
47#include <X11/extensions/dpms.h>
48
49#include "xf86xv.h"
50
51#include "savage_driver.h"
52#include "savage_regs.h"
53#include "savage_bci.h"
54#include "savage_streams.h"
55
56#define TRANSPARENCY_KEY 0xff;
57
58#ifdef XF86DRI
59#define _XF86DRI_SERVER_
60#include "savage_dri.h"
61#include "savage_sarea.h"
62#endif
63
64
65/*
66 * prototypes
67 */
68static void SavageEnableMMIO(ScrnInfoPtr pScrn);
69static void SavageDisableMMIO(ScrnInfoPtr pScrn);
70
71static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid);
72static void SavageIdentify(int flags);
73static Bool SavageProbe(DriverPtr drv, int flags);
74static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags);
75
76static Bool SavageEnterVT(int scrnIndex, int flags);
77static void SavageLeaveVT(int scrnIndex, int flags);
78static void SavageSave(ScrnInfoPtr pScrn);
79static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr, SavageRegPtr, Bool);
80
81static void SavageInitStatus(ScrnInfoPtr pScrn);
82static void SavageInitShadowStatus(ScrnInfoPtr pScrn);
83
84static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen, int argc,
85			     char **argv);
86static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen);
87static ModeStatus SavageValidMode(int index, DisplayModePtr mode,
88				  Bool verbose, int flags);
89
90void SavageDGAInit(ScreenPtr);
91static Bool SavageMapMem(ScrnInfoPtr pScrn);
92static void SavageUnmapMem(ScrnInfoPtr pScrn, int All);
93static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode);
94static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen);
95static Bool SavageSaveScreen(ScreenPtr pScreen, int mode);
96static void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors,
97			      int *indicies, LOCO *colors,
98			      VisualPtr pVisual);
99static void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors,
100			      int *indicies, LOCO *colors,
101			      VisualPtr pVisual);
102static void SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b);
103static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
104			   int min_n2, int max_n2, long freq_min,
105			   long freq_max, unsigned int *mdiv,
106			   unsigned int *ndiv, unsigned int *r);
107void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file);
108void SavagePrintRegs(ScrnInfoPtr pScrn);
109static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags);
110static Bool SavageDDC1(int scrnIndex);
111static unsigned int SavageDDC1Read(ScrnInfoPtr pScrn);
112static void SavageProbeDDC(ScrnInfoPtr pScrn, int index);
113static void SavageGetTvMaxSize(SavagePtr psav);
114static Bool SavagePanningCheck(ScrnInfoPtr pScrn);
115#ifdef XF86DRI
116static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn);
117#endif
118static void SavageResetStreams(ScrnInfoPtr pScrn);
119
120extern ScrnInfoPtr gpScrn;
121
122#define iabs(a)	((int)(a)>0?(a):(-(a)))
123
124/*#define TRACEON*/
125#ifdef TRACEON
126#define TRACE(prms)	ErrorF prms
127#else
128#define TRACE(prms)
129#endif
130
131int gSavageEntityIndex = -1;
132
133_X_EXPORT DriverRec SAVAGE =
134{
135    SAVAGE_VERSION,
136    SAVAGE_DRIVER_NAME,
137    SavageIdentify,
138    SavageProbe,
139    SavageAvailableOptions,
140    NULL,
141    0,
142    NULL
143};
144
145
146/* Supported chipsets */
147
148static SymTabRec SavageChips[] = {
149    { PCI_CHIP_SAVAGE4,		"Savage4" },
150    { PCI_CHIP_SAVAGE3D,	"Savage3D" },
151    { PCI_CHIP_SAVAGE3D_MV,	"Savage3D-MV" },
152    { PCI_CHIP_SAVAGE2000,	"Savage2000" },
153    { PCI_CHIP_SAVAGE_MX_MV,	"Savage/MX-MV" },
154    { PCI_CHIP_SAVAGE_MX,	"Savage/MX" },
155    { PCI_CHIP_SAVAGE_IX_MV,	"Savage/IX-MV" },
156    { PCI_CHIP_SAVAGE_IX,	"Savage/IX" },
157    { PCI_CHIP_PROSAVAGE_PM,	"ProSavage PM133" },
158    { PCI_CHIP_PROSAVAGE_KM,	"ProSavage KM133" },
159    { PCI_CHIP_S3TWISTER_P,	"Twister PN133" },
160    { PCI_CHIP_S3TWISTER_K,	"Twister KN133" },
161    { PCI_CHIP_SUPSAV_MX128,	"SuperSavage/MX 128" },
162    { PCI_CHIP_SUPSAV_MX64,	"SuperSavage/MX 64" },
163    { PCI_CHIP_SUPSAV_MX64C,	"SuperSavage/MX 64C" },
164    { PCI_CHIP_SUPSAV_IX128SDR,	"SuperSavage/IX 128" },
165    { PCI_CHIP_SUPSAV_IX128DDR,	"SuperSavage/IX 128" },
166    { PCI_CHIP_SUPSAV_IX64SDR,	"SuperSavage/IX 64" },
167    { PCI_CHIP_SUPSAV_IX64DDR,	"SuperSavage/IX 64" },
168    { PCI_CHIP_SUPSAV_IXCSDR,	"SuperSavage/IXC 64" },
169    { PCI_CHIP_SUPSAV_IXCDDR,	"SuperSavage/IXC 64" },
170    { PCI_CHIP_PROSAVAGE_DDR,	"ProSavage DDR" },
171    { PCI_CHIP_PROSAVAGE_DDRK,	"ProSavage DDR-K" },
172    { -1,			NULL }
173};
174
175static SymTabRec SavageChipsets[] = {
176    { S3_SAVAGE3D,	"Savage3D" },
177    { S3_SAVAGE4,	"Savage4" },
178    { S3_SAVAGE2000,	"Savage2000" },
179    { S3_SAVAGE_MX,	"MobileSavage" },
180    { S3_PROSAVAGE,	"ProSavage" },
181    { S3_TWISTER,       "Twister"},
182    { S3_PROSAVAGEDDR,  "ProSavageDDR"},
183    { S3_SUPERSAVAGE,   "SuperSavage" },
184    { -1,		NULL }
185};
186
187/* This table maps a PCI device ID to a chipset family identifier. */
188
189static PciChipsets SavagePciChipsets[] = {
190    { S3_SAVAGE3D,	PCI_CHIP_SAVAGE3D,	RES_SHARED_VGA },
191    { S3_SAVAGE3D,	PCI_CHIP_SAVAGE3D_MV, 	RES_SHARED_VGA },
192    { S3_SAVAGE4,	PCI_CHIP_SAVAGE4,	RES_SHARED_VGA },
193    { S3_SAVAGE2000,	PCI_CHIP_SAVAGE2000,	RES_SHARED_VGA },
194    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_MX_MV,	RES_SHARED_VGA },
195    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_MX,	RES_SHARED_VGA },
196    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_IX_MV,	RES_SHARED_VGA },
197    { S3_SAVAGE_MX,	PCI_CHIP_SAVAGE_IX,	RES_SHARED_VGA },
198    { S3_PROSAVAGE,	PCI_CHIP_PROSAVAGE_PM,	RES_SHARED_VGA },
199    { S3_PROSAVAGE,	PCI_CHIP_PROSAVAGE_KM,	RES_SHARED_VGA },
200    { S3_TWISTER,	PCI_CHIP_S3TWISTER_P,	RES_SHARED_VGA },
201    { S3_TWISTER,	PCI_CHIP_S3TWISTER_K,	RES_SHARED_VGA },
202    { S3_PROSAVAGEDDR,	PCI_CHIP_PROSAVAGE_DDR,	RES_SHARED_VGA },
203    { S3_PROSAVAGEDDR,	PCI_CHIP_PROSAVAGE_DDRK,	RES_SHARED_VGA },
204    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX128,	RES_SHARED_VGA },
205    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX64,	RES_SHARED_VGA },
206    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_MX64C,	RES_SHARED_VGA },
207    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX128SDR,	RES_SHARED_VGA },
208    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX128DDR,	RES_SHARED_VGA },
209    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX64SDR,	RES_SHARED_VGA },
210    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IX64DDR,	RES_SHARED_VGA },
211    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IXCSDR,	RES_SHARED_VGA },
212    { S3_SUPERSAVAGE,	PCI_CHIP_SUPSAV_IXCDDR,	RES_SHARED_VGA },
213    { -1,		-1,			RES_UNDEFINED }
214};
215
216typedef enum {
217     OPTION_PCI_BURST
218    ,OPTION_PCI_RETRY
219    ,OPTION_NOACCEL
220    ,OPTION_ACCELMETHOD
221    ,OPTION_LCD_CENTER
222    ,OPTION_LCDCLOCK
223    ,OPTION_MCLK
224    ,OPTION_REFCLK
225    ,OPTION_SHOWCACHE
226    ,OPTION_SWCURSOR
227    ,OPTION_HWCURSOR
228    ,OPTION_SHADOW_FB
229    ,OPTION_ROTATE
230    ,OPTION_USEBIOS
231    ,OPTION_SHADOW_STATUS
232    ,OPTION_CRT_ONLY
233    ,OPTION_TV_ON
234    ,OPTION_TV_PAL
235    ,OPTION_FORCE_INIT
236    ,OPTION_OVERLAY
237    ,OPTION_T_KEY
238    ,OPTION_DISABLE_XVMC
239    ,OPTION_DISABLE_TILE
240    ,OPTION_DISABLE_COB
241    ,OPTION_BCI_FOR_XV
242    ,OPTION_DVI
243    ,OPTION_BUS_TYPE
244    ,OPTION_DMA_TYPE
245    ,OPTION_DMA_MODE
246    ,OPTION_AGP_MODE
247    ,OPTION_AGP_SIZE
248    ,OPTION_DRI
249} SavageOpts;
250
251
252static const OptionInfoRec SavageOptions[] =
253{
254    { OPTION_NOACCEL,	"NoAccel",	OPTV_BOOLEAN, {0}, FALSE },
255    { OPTION_ACCELMETHOD, "AccelMethod", OPTV_STRING,	{0}, FALSE },
256    { OPTION_HWCURSOR,	"HWCursor",	OPTV_BOOLEAN, {0}, FALSE },
257    { OPTION_SWCURSOR,	"SWCursor",	OPTV_BOOLEAN, {0}, FALSE },
258    { OPTION_SHADOW_FB,	"ShadowFB",	OPTV_BOOLEAN, {0}, FALSE },
259    { OPTION_ROTATE,	"Rotate",	OPTV_ANYSTR, {0}, FALSE },
260    { OPTION_USEBIOS,	"UseBIOS",	OPTV_BOOLEAN, {0}, FALSE },
261    { OPTION_LCDCLOCK,	"LCDClock",	OPTV_FREQ,    {0}, FALSE },
262    { OPTION_SHADOW_STATUS, "ShadowStatus", OPTV_BOOLEAN, {0}, FALSE },
263    { OPTION_CRT_ONLY,  "CrtOnly",      OPTV_BOOLEAN, {0}, FALSE },
264    { OPTION_TV_ON,     "TvOn",         OPTV_BOOLEAN, {0}, FALSE },
265    { OPTION_TV_PAL,    "PAL",          OPTV_BOOLEAN, {0}, FALSE },
266    { OPTION_FORCE_INIT,"ForceInit",    OPTV_BOOLEAN, {0}, FALSE },
267    { OPTION_OVERLAY,	"Overlay",	OPTV_ANYSTR, {0}, FALSE },
268    { OPTION_T_KEY,	"TransparencyKey",	OPTV_ANYSTR, {0}, FALSE },
269    { OPTION_FORCE_INIT,   "ForceInit",   OPTV_BOOLEAN, {0}, FALSE },
270    { OPTION_DISABLE_XVMC, "DisableXVMC", OPTV_BOOLEAN, {0}, FALSE },
271    { OPTION_DISABLE_TILE, "DisableTile", OPTV_BOOLEAN, {0}, FALSE },
272    { OPTION_DISABLE_COB,  "DisableCOB",  OPTV_BOOLEAN, {0}, FALSE },
273    { OPTION_BCI_FOR_XV,   "BCIforXv",    OPTV_BOOLEAN, {0}, FALSE },
274    { OPTION_DVI,          "DVI",       OPTV_BOOLEAN, {0}, FALSE },
275#ifdef XF86DRI
276    { OPTION_BUS_TYPE,	"BusType",	OPTV_ANYSTR,  {0}, FALSE },
277    { OPTION_DMA_TYPE,	"DmaType",	OPTV_ANYSTR,  {0}, FALSE },
278    { OPTION_DMA_MODE,  "DmaMode",	OPTV_ANYSTR,  {0}, FALSE },
279    { OPTION_AGP_MODE,	"AGPMode",	OPTV_INTEGER, {0}, FALSE },
280    { OPTION_AGP_SIZE,	"AGPSize",	OPTV_INTEGER, {0}, FALSE },
281    { OPTION_DRI,       "DRI",          OPTV_BOOLEAN, {0}, TRUE },
282#endif
283    { -1,		NULL,		OPTV_NONE,    {0}, FALSE }
284};
285
286
287static const char *vgaHWSymbols[] = {
288    "vgaHWBlankScreen",
289    "vgaHWCopyReg",
290    "vgaHWGetHWRec",
291    "vgaHWGetIOBase",
292    "vgaHWGetIndex",
293    "vgaHWInit",
294    "vgaHWLock",
295    "vgaHWProtect",
296    "vgaHWRestore",
297    "vgaHWSave",
298    "vgaHWSaveScreen",
299    "vgaHWSetMmioFuncs",
300    "vgaHWSetStdFuncs",
301    "vgaHWUnmapMem",
302    "vgaHWddc1SetSpeedWeak",
303#if 0
304    "vgaHWFreeHWRec",
305    "vgaHWMapMem",
306    "vgaHWUnlock",
307#endif
308    NULL
309};
310
311#ifdef XF86DRI
312static const char *drmSymbols[] = {
313    "drmAvailable",
314    "drmAddBufs",
315    "drmAddMap",
316    "drmCtlInstHandler",
317    "drmGetInterruptFromBusID",
318    "drmFreeVersion",
319    "drmGetVersion",
320    "drmMap",
321    "drmUnmap",
322    "drmMapBufs",
323    "drmUnmapBufs",
324    "drmAgpAcquire",
325    "drmAgpRelease",
326    "drmAgpEnable",
327    "drmAgpAlloc",
328    "drmAgpFree",
329    "drmAgpBind",
330    "drmAgpUnbind",
331    "drmAgpGetMode",
332    "drmAgpBase",
333    "drmAgpSize",
334    "drmAgpVendorId",
335    "drmAgpDeviceId",
336    "drmMGAInitDMA",
337    "drmMGACleanupDMA",
338    "drmMGAFlushDMA",
339    "drmMGAEngineReset",
340    NULL
341};
342
343static const char *driSymbols[] = {
344    "DRIGetDrawableIndex",
345    "DRIFinishScreenInit",
346    "DRIDestroyInfoRec",
347    "DRICloseScreen",
348    "DRIDestroyInfoRec",
349    "DRIScreenInit",
350    "DRIDestroyInfoRec",
351    "DRICreateInfoRec",
352    "DRILock",
353    "DRIUnlock",
354    "DRIGetSAREAPrivate",
355    "DRIGetContext",
356    "DRIQueryVersion",
357    "DRIAdjustFrame",
358    "DRIOpenFullScreen",
359    "DRICloseFullScreen",
360    "GlxSetVisualConfigs",
361    NULL
362};
363#endif
364
365
366static const char *ramdacSymbols[] = {
367    "xf86CreateCursorInfoRec",
368#if 0
369    "xf86DestroyCursorInfoRec",
370#endif
371    "xf86InitCursor",
372    NULL
373};
374
375static const char *int10Symbols[] = {
376    "xf86ExecX86int10",
377    "xf86Int10AllocPages",
378    "xf86int10Addr",
379    "xf86Int10FreePages"
380};
381
382static const char *vbeSymbols[] = {
383    "VBEInit",
384    "vbeDoEDID",
385#if 0
386    "vbeFree",
387#endif
388    NULL
389};
390
391static const char *vbeOptSymbols[] = {
392    "vbeModeInit",
393    "VBESetVBEMode",
394    "VBEGetVBEInfo",
395    "VBEFreeVBEInfo",
396    NULL
397};
398
399static const char *ddcSymbols[] = {
400    "xf86DoEDID_DDC1",
401    "xf86DoEDID_DDC2",
402    "xf86PrintEDID",
403    "xf86SetDDCproperties",
404    NULL
405};
406
407static const char *i2cSymbols[] = {
408    "xf86CreateI2CBusRec",
409    "xf86I2CBusInit",
410    "xf86CreateI2CDevRec",
411    "xf86I2CDevInit",
412    "xf86I2CWriteByte",
413    "xf86I2CWriteBytes",
414    "xf86I2CReadByte",
415    "xf86I2CReadBytes",
416    "xf86I2CWriteRead",
417    "xf86DestroyI2CDevRec",
418    NULL
419};
420
421static const char *xaaSymbols[] = {
422    "XAAGetCopyROP",
423    "XAAGetCopyROP_PM",
424    "XAACreateInfoRec",
425    "XAADestroyInfoRec",
426    "XAAFillSolidRects",
427    "XAAHelpPatternROP",
428    "XAAHelpSolidROP",
429    "XAAInit",
430    "XAAScreenIndex",
431    NULL
432};
433
434static const char *exaSymbols[] = {
435    "exaDriverAlloc",
436    "exaDriverInit",
437    "exaDriverFini",
438    "exaOffscreenAlloc",
439    "exaOffscreenFree",
440    "exaGetPixmapOffset",
441    "exaGetPixmapPitch",
442    "exaGetPixmapSize",
443    NULL
444};
445
446static const char *shadowSymbols[] = {
447    "ShadowFBInit",
448    NULL
449};
450
451static const char *fbSymbols[] = {
452    "fbPictureInit",
453    "fbScreenInit",
454    NULL
455};
456
457#ifdef XFree86LOADER
458
459static MODULESETUPPROTO(SavageSetup);
460
461static XF86ModuleVersionInfo SavageVersRec = {
462    "savage",
463    MODULEVENDORSTRING,
464    MODINFOSTRING1,
465    MODINFOSTRING2,
466    XORG_VERSION_CURRENT,
467    SAVAGE_VERSION_MAJOR, SAVAGE_VERSION_MINOR, SAVAGE_PATCHLEVEL,
468    ABI_CLASS_VIDEODRV,
469    ABI_VIDEODRV_VERSION,
470    MOD_CLASS_VIDEODRV,
471    {0, 0, 0, 0}
472};
473
474_X_EXPORT XF86ModuleData savageModuleData = {
475    &SavageVersRec,
476    SavageSetup,
477    NULL
478};
479
480static pointer SavageSetup(pointer module, pointer opts, int *errmaj,
481			   int *errmin)
482{
483    static Bool setupDone = FALSE;
484
485    if (!setupDone) {
486	setupDone = TRUE;
487	xf86AddDriver(&SAVAGE, module, 1);
488	LoaderRefSymLists(vgaHWSymbols, fbSymbols, ramdacSymbols,
489			  xaaSymbols,
490			  exaSymbols,
491			  shadowSymbols, vbeSymbols, vbeOptSymbols,
492#ifdef XF86DRI
493                          drmSymbols, driSymbols,
494#endif
495			  int10Symbols, i2cSymbols, ddcSymbols, NULL);
496	return (pointer) 1;
497    } else {
498	if (errmaj)
499	    *errmaj = LDR_ONCEONLY;
500	return NULL;
501    }
502}
503
504#endif /* XFree86LOADER */
505
506static SavageEntPtr SavageEntPriv(ScrnInfoPtr pScrn)
507{
508    DevUnion     *pPriv;
509    SavagePtr  psav   = SAVPTR(pScrn);
510    pPriv = xf86GetEntityPrivate(psav->pEnt->index,
511                                 gSavageEntityIndex);
512    return pPriv->ptr;
513}
514
515
516/*
517 * I'd rather have these wait macros be inline, but S3 has made it
518 * darned near impossible.  The bit fields are in a different place in
519 * all three families, the status register has a different address in the
520 * three families, and even the idle vs busy sense flipped in the Sav2K.
521 */
522
523static void
524ResetBCI2K( SavagePtr psav )
525{
526    CARD32 cob = INREG( 0x48c18 );
527    /* if BCI is enabled and BCI is busy... */
528
529    if(
530	(cob & 0x00000008) &&
531	! (ALT_STATUS_WORD0 & 0x00200000)
532    )
533    {
534	ErrorF( "Resetting BCI, stat = %08lx...\n",
535		(unsigned long) ALT_STATUS_WORD0);
536	/* Turn off BCI */
537	OUTREG( 0x48c18, cob & ~8 );
538	usleep(10000);
539	/* Turn it back on */
540	OUTREG( 0x48c18, cob );
541	usleep(10000);
542    }
543}
544
545static Bool
546ShadowWait( SavagePtr psav )
547{
548    BCI_GET_PTR;
549    int loop = 0;
550
551    if( !psav->NoPCIRetry )
552	return 0;
553
554    psav->ShadowCounter = (psav->ShadowCounter + 1) & 0xffff;
555    if (psav->ShadowCounter == 0)
556	psav->ShadowCounter++; /* 0 is reserved for the BIOS
557				  to avoid confusion in the DRM */
558    BCI_SEND( psav->dwBCIWait2DIdle );
559    BCI_SEND( 0x98000000 + psav->ShadowCounter );
560
561    while(
562	(int)(psav->ShadowVirtual[psav->eventStatusReg] & 0xffff) !=
563	psav->ShadowCounter && (loop++ < MAXLOOP)
564    )
565	;
566
567    return loop >= MAXLOOP;
568}
569
570static Bool
571ShadowWaitQueue( SavagePtr psav, int v )
572{
573    int loop = 0;
574    CARD32 slots = MAXFIFO - v;
575
576    if (slots >= psav->bciThresholdHi)
577	slots = psav->bciThresholdHi;
578    else
579	return ShadowWait( psav );
580
581    /* Savage 2000 reports only entries filled in the COB, not the on-chip
582     * queue. Also it reports in qword units instead of dwords. */
583    if (psav->Chipset == S3_SAVAGE2000)
584	slots = (slots - 32) / 4;
585
586    while( ((psav->ShadowVirtual[0] & psav->bciUsedMask) >= slots) && (loop++ < MAXLOOP))
587	;
588
589    return loop >= MAXLOOP;
590}
591
592/* Wait until "v" queue entries are free */
593
594static int
595WaitQueue3D( SavagePtr psav, int v )
596{
597    int loop = 0;
598    CARD32 slots = MAXFIFO - v;
599
600    mem_barrier();
601    if( psav->ShadowVirtual )
602    {
603	psav->WaitQueue = ShadowWaitQueue;
604	return ShadowWaitQueue(psav, v);
605    }
606    else
607    {
608	loop &= STATUS_WORD0;
609	while( ((STATUS_WORD0 & 0x0000ffff) > slots) && (loop++ < MAXLOOP))
610	    ;
611    }
612    return loop >= MAXLOOP;
613}
614
615static int
616WaitQueue4( SavagePtr psav, int v )
617{
618    int loop = 0;
619    CARD32 slots = MAXFIFO - v;
620
621    if( !psav->NoPCIRetry )
622	return 0;
623    mem_barrier();
624    if( psav->ShadowVirtual )
625    {
626	psav->WaitQueue = ShadowWaitQueue;
627	return ShadowWaitQueue(psav, v);
628    }
629    else
630	while( ((ALT_STATUS_WORD0 & 0x001fffff) > slots) && (loop++ < MAXLOOP));
631    return loop >= MAXLOOP;
632}
633
634static int
635WaitQueue2K( SavagePtr psav, int v )
636{
637    int loop = 0;
638    CARD32 slots = (MAXFIFO - v) / 4;
639
640    if( !psav->NoPCIRetry )
641	return 0;
642    mem_barrier();
643    if( psav->ShadowVirtual )
644    {
645	psav->WaitQueue = ShadowWaitQueue;
646	return ShadowWaitQueue(psav, v);
647    }
648    else
649	while( ((ALT_STATUS_WORD0 & 0x000fffff) > slots) && (loop++ < MAXLOOP))
650	    ;
651    if( loop >= MAXLOOP )
652	ResetBCI2K(psav);
653    return loop >= MAXLOOP;
654}
655
656/* Wait until GP is idle and queue is empty */
657
658static int
659WaitIdleEmpty3D(SavagePtr psav)
660{
661    int loop = 0;
662    mem_barrier();
663    if( psav->ShadowVirtual )
664    {
665	psav->WaitIdleEmpty = ShadowWait;
666	return ShadowWait(psav);
667    }
668    loop &= STATUS_WORD0;
669    while( ((STATUS_WORD0 & 0x0008ffff) != 0x80000) && (loop++ < MAXLOOP) );
670    return loop >= MAXLOOP;
671}
672
673static int
674WaitIdleEmpty4(SavagePtr psav)
675{
676    int loop = 0;
677    mem_barrier();
678    if( psav->ShadowVirtual )
679    {
680	psav->WaitIdleEmpty = ShadowWait;
681	return ShadowWait(psav);
682    }
683	/* which is right?*/
684    /*while( ((ALT_STATUS_WORD0 & 0x00a1ffff) != 0x00a00000) && (loop++ < MAXLOOP) );*/ /* tim */
685    while (((ALT_STATUS_WORD0 & 0x00e1ffff) != 0x00e00000) && (loop++ < MAXLOOP)); /* S3 */
686    return loop >= MAXLOOP;
687}
688
689static int
690WaitIdleEmpty2K(SavagePtr psav)
691{
692    int loop = 0;
693    mem_barrier();
694    if( psav->ShadowVirtual )
695    {
696	psav->WaitIdleEmpty = ShadowWait;
697	return ShadowWait(psav);
698    }
699    loop &= ALT_STATUS_WORD0;
700    while( ((ALT_STATUS_WORD0 & 0x009fffff) != 0) && (loop++ < MAXLOOP) );
701    if( loop >= MAXLOOP )
702	ResetBCI2K(psav);
703    return loop >= MAXLOOP;
704}
705
706/* Wait until GP is idle */
707
708static int
709WaitIdle3D(SavagePtr psav)
710{
711    int loop = 0;
712    mem_barrier();
713    if( psav->ShadowVirtual )
714    {
715	psav->WaitIdle = ShadowWait;
716	return ShadowWait(psav);
717    }
718    while( (!(STATUS_WORD0 & 0x00080000)) && (loop++ < MAXLOOP) );
719    return loop >= MAXLOOP;
720}
721
722static int
723WaitIdle4(SavagePtr psav)
724{
725    int loop = 0;
726    mem_barrier();
727    if( psav->ShadowVirtual )
728    {
729	psav->WaitIdle = ShadowWait;
730	return ShadowWait(psav);
731    }
732	/* which is right?*/
733    /*while( (!(ALT_STATUS_WORD0 & 0x00800000)) && (loop++ < MAXLOOP) );*/ /* tim */
734    while (((ALT_STATUS_WORD0 & 0x00E00000)!=0x00E00000) && (loop++ < MAXLOOP)); /* S3 */
735    return loop >= MAXLOOP;
736}
737
738static int
739WaitIdle2K(SavagePtr psav)
740{
741    int loop = 0;
742    mem_barrier();
743    if( psav->ShadowVirtual )
744    {
745	psav->WaitIdle = ShadowWait;
746	return ShadowWait(psav);
747    }
748    loop &= ALT_STATUS_WORD0;
749    while( (ALT_STATUS_WORD0 & 0x00900000) && (loop++ < MAXLOOP) );
750    return loop >= MAXLOOP;
751}
752
753
754static Bool SavageGetRec(ScrnInfoPtr pScrn)
755{
756    if (pScrn->driverPrivate)
757	return TRUE;
758
759    pScrn->driverPrivate = xnfcalloc(sizeof(SavageRec), 1);
760    return TRUE;
761}
762
763
764static void SavageFreeRec(ScrnInfoPtr pScrn)
765{
766    TRACE(( "SavageFreeRec(%x)\n", pScrn->driverPrivate ));
767    if (!pScrn->driverPrivate)
768	return;
769    SavageUnmapMem(pScrn, 1);
770    xfree(pScrn->driverPrivate);
771    pScrn->driverPrivate = NULL;
772}
773
774
775static const OptionInfoRec * SavageAvailableOptions(int chipid, int busid)
776{
777    return SavageOptions;
778}
779
780
781static void SavageIdentify(int flags)
782{
783    xf86PrintChipsets("SAVAGE",
784		      "driver (version " SAVAGE_DRIVER_VERSION ") for S3 Savage chipsets",
785		      SavageChips);
786}
787
788
789static Bool SavageProbe(DriverPtr drv, int flags)
790{
791    int i;
792    GDevPtr *devSections = NULL;
793    int *usedChips;
794    int numDevSections;
795    int numUsed;
796    Bool foundScreen = FALSE;
797
798    /* sanity checks */
799    if ((numDevSections = xf86MatchDevice("savage", &devSections)) <= 0)
800	return FALSE;
801    if (xf86GetPciVideoInfo() == NULL) {
802        if (devSections)
803	    xfree(devSections);
804        return FALSE;
805    }
806
807    numUsed = xf86MatchPciInstances("SAVAGE", PCI_VENDOR_S3,
808				    SavageChipsets, SavagePciChipsets,
809				    devSections, numDevSections, drv,
810				    &usedChips);
811    if (devSections)
812	xfree(devSections);
813    devSections = NULL;
814    if (numUsed <= 0)
815	return FALSE;
816
817    if (flags & PROBE_DETECT)
818	foundScreen = TRUE;
819    else
820	for (i=0; i<numUsed; i++) {
821            EntityInfoPtr pEnt = xf86GetEntityInfo(usedChips[i]);;
822            ScrnInfoPtr pScrn = xf86ConfigPciEntity(NULL, 0, usedChips[i],
823						    NULL, RES_SHARED_VGA,
824						    NULL, NULL, NULL, NULL);
825
826            if (pScrn != NULL) {
827 	        pScrn->driverVersion = SAVAGE_VERSION;
828	        pScrn->driverName = SAVAGE_DRIVER_NAME;
829	        pScrn->name = "SAVAGE";
830	        pScrn->Probe = SavageProbe;
831	        pScrn->PreInit = SavagePreInit;
832	        pScrn->ScreenInit = SavageScreenInit;
833	        pScrn->SwitchMode = SavageSwitchMode;
834	        pScrn->AdjustFrame = SavageAdjustFrame;
835	        pScrn->EnterVT = SavageEnterVT;
836	        pScrn->LeaveVT = SavageLeaveVT;
837	        pScrn->FreeScreen = NULL;
838	        pScrn->ValidMode = SavageValidMode;
839	        foundScreen = TRUE;
840	    }
841
842            pEnt = xf86GetEntityInfo(usedChips[i]);
843
844            /* MX, IX, SuperSavage cards support Dual-Head, mark the entity as sharable*/
845            if(pEnt->chipset == S3_SAVAGE_MX || pEnt->chipset == S3_SUPERSAVAGE)
846            {
847		DevUnion   *pPriv;
848		SavageEntPtr pSavageEnt;
849
850		xf86SetEntitySharable(usedChips[i]);
851
852		if (gSavageEntityIndex == -1)
853		    gSavageEntityIndex = xf86AllocateEntityPrivateIndex();
854
855		pPriv = xf86GetEntityPrivate(pEnt->index,
856					     gSavageEntityIndex);
857
858		if (!pPriv->ptr) {
859		    int j;
860		    int instance = xf86GetNumEntityInstances(pEnt->index);
861
862		    for (j = 0; j < instance; j++)
863			xf86SetEntityInstanceForScreen(pScrn, pEnt->index, j);
864
865		    pPriv->ptr = xnfcalloc(sizeof(SavageEntRec), 1);
866		    pSavageEnt = pPriv->ptr;
867		    pSavageEnt->HasSecondary = FALSE;
868		} else {
869		    pSavageEnt = pPriv->ptr;
870		    pSavageEnt->HasSecondary = TRUE;
871		}
872	    }
873	    xfree(pEnt);
874	}
875
876
877    xfree(usedChips);
878    return foundScreen;
879}
880
881static int LookupChipID( PciChipsets* pset, int ChipID )
882{
883    /* Is there a function to do this for me? */
884    while( pset->numChipset >= 0 )
885    {
886        if( pset->PCIid == ChipID )
887	    return pset->numChipset;
888	pset++;
889    }
890
891    return -1;
892}
893
894static void SavageDoDDC(ScrnInfoPtr pScrn)
895{
896    SavagePtr psav= SAVPTR(pScrn);
897    pointer ddc;
898
899    /* Do the DDC dance. */ /* S3/VIA's DDC code */
900    ddc = xf86LoadSubModule(pScrn, "ddc");
901    if (ddc) {
902        xf86LoaderReqSymLists(ddcSymbols, NULL);
903        switch( psav->Chipset ) {
904            case S3_SAVAGE3D:
905            case S3_SAVAGE_MX:
906            case S3_SUPERSAVAGE:
907	    case S3_SAVAGE2000:
908		psav->DDCPort = 0xAA;
909                psav->I2CPort = 0xA0;
910                break;
911
912            case S3_SAVAGE4:
913            case S3_PROSAVAGE:
914            case S3_TWISTER:
915            case S3_PROSAVAGEDDR:
916                psav->DDCPort = 0xB1;
917                psav->I2CPort = 0xA0;
918                break;
919        }
920
921        if (!SavageDDC1(pScrn->scrnIndex)) {
922            /* DDC1 failed,switch to DDC2 */
923            if (xf86LoadSubModule(pScrn, "i2c")) {
924                xf86LoaderReqSymLists(i2cSymbols,NULL);
925                if (SavageI2CInit(pScrn)) {
926                    unsigned char tmp;
927
928                    InI2CREG(tmp,psav->DDCPort);
929                    OutI2CREG(tmp | 0x13,psav->DDCPort);
930                    xf86SetDDCproperties(pScrn,xf86PrintEDID(
931                                             xf86DoEDID_DDC2(pScrn->scrnIndex,psav->I2C)));
932                    OutI2CREG(tmp,psav->DDCPort);
933                }
934            }
935        }
936    }
937}
938
939/* Copied from ddc/Property.c via nv */
940static DisplayModePtr
941SavageModesAdd(DisplayModePtr Modes, DisplayModePtr Additions)
942{
943    if (!Modes) {
944        if (Additions)
945            return Additions;
946        else
947            return NULL;
948    }
949
950    if (Additions) {
951        DisplayModePtr Mode = Modes;
952
953        while (Mode->next)
954            Mode = Mode->next;
955
956        Mode->next = Additions;
957        Additions->prev = Mode;
958    }
959
960    return Modes;
961}
962
963/* borrowed from nv */
964static void
965SavageAddPanelMode(ScrnInfoPtr pScrn)
966{
967    SavagePtr psav= SAVPTR(pScrn);
968    DisplayModePtr  Mode  = NULL;
969
970    Mode = xf86CVTMode(psav->PanelX, psav->PanelY, 60.00, TRUE, FALSE);
971    Mode->type = M_T_DRIVER | M_T_PREFERRED;
972    pScrn->monitor->Modes = SavageModesAdd(pScrn->monitor->Modes, Mode);
973
974    if ((pScrn->monitor->nHsync == 0) &&
975        (pScrn->monitor->nVrefresh == 0)) {
976	if (!Mode->HSync)
977	    Mode->HSync = ((float) Mode->Clock ) / ((float) Mode->HTotal);
978	if (!Mode->VRefresh)
979	    Mode->VRefresh = (1000.0 * ((float) Mode->Clock)) /
980		((float) (Mode->HTotal * Mode->VTotal));
981
982	if (Mode->HSync < pScrn->monitor->hsync[0].lo)
983	    pScrn->monitor->hsync[0].lo = Mode->HSync;
984	if (Mode->HSync > pScrn->monitor->hsync[0].hi)
985	    pScrn->monitor->hsync[0].hi = Mode->HSync;
986	if (Mode->VRefresh < pScrn->monitor->vrefresh[0].lo)
987	    pScrn->monitor->vrefresh[0].lo = Mode->VRefresh;
988	if (Mode->VRefresh > pScrn->monitor->vrefresh[0].hi)
989	    pScrn->monitor->vrefresh[0].hi = Mode->VRefresh;
990
991	pScrn->monitor->nHsync = 1;
992	pScrn->monitor->nVrefresh = 1;
993    }
994}
995
996static void SavageGetPanelInfo(ScrnInfoPtr pScrn)
997{
998    SavagePtr psav= SAVPTR(pScrn);
999    vgaHWPtr hwp;
1000    unsigned char cr6b;
1001    int panelX, panelY;
1002    char * sTechnology = "Unknown";
1003    enum ACTIVE_DISPLAYS { /* These are the bits in CR6B */
1004	ActiveCRT = 0x01,
1005	ActiveLCD = 0x02,
1006	ActiveTV = 0x04,
1007	ActiveCRT2 = 0x20,
1008	ActiveDUO = 0x80
1009    };
1010
1011    hwp = VGAHWPTR(pScrn);
1012
1013    /* Check LCD panel information */
1014
1015    cr6b = hwp->readCrtc( hwp, 0x6b );
1016
1017    panelX = (hwp->readSeq(hwp, 0x61) +
1018	    ((hwp->readSeq(hwp, 0x66) & 0x02) << 7) + 1) * 8;
1019    panelY = hwp->readSeq(hwp, 0x69) +
1020	    ((hwp->readSeq(hwp, 0x6e) & 0x70) << 4) + 1;
1021
1022
1023	/* OK, I admit it.  I don't know how to limit the max dot clock
1024	 * for LCD panels of various sizes.  I thought I copied the formula
1025	 * from the BIOS, but many users have informed me of my folly.
1026	 *
1027	 * Instead, I'll abandon any attempt to automatically limit the
1028	 * clock, and add an LCDClock option to XF86Config.  Some day,
1029	 * I should come back to this.
1030	 */
1031
1032
1033    if( (hwp->readSeq( hwp, 0x39 ) & 0x03) == 0 )
1034    {
1035	sTechnology = "TFT";
1036    }
1037    else if( (hwp->readSeq( hwp, 0x30 ) & 0x01) == 0 )
1038    {
1039	sTechnology = "DSTN";
1040    }
1041    else
1042    {
1043	sTechnology = "STN";
1044    }
1045
1046    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1047		   "%dx%d %s LCD panel detected %s\n",
1048		   panelX, panelY, sTechnology,
1049		   cr6b & ActiveLCD ? "and active" : "but not active");
1050
1051    if( cr6b & ActiveLCD ) {
1052	    /* If the LCD is active and panel expansion is enabled, */
1053	    /* we probably want to kill the HW cursor. */
1054
1055	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1056		       "- Limiting video mode to %dx%d\n",
1057		       panelX, panelY );
1058
1059	psav->PanelX = panelX;
1060	psav->PanelY = panelY;
1061
1062	if( psav->LCDClock > 0.0 )
1063	{
1064	    psav->maxClock = psav->LCDClock * 1000.0;
1065	    xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1066			    "- Limiting dot clock to %1.2f MHz\n",
1067			    psav->LCDClock );
1068	}
1069    } else {
1070        psav->DisplayType = MT_CRT;
1071    }
1072}
1073
1074
1075static Bool SavagePreInit(ScrnInfoPtr pScrn, int flags)
1076{
1077    EntityInfoPtr pEnt;
1078    SavagePtr psav;
1079    MessageType from = X_DEFAULT;
1080    int i;
1081    ClockRangePtr clockRanges;
1082    char *s = NULL;
1083    unsigned char config1, m, n, n1, n2, sr8, cr66 = 0, tmp;
1084    int mclk;
1085    vgaHWPtr hwp;
1086    int vgaCRIndex, vgaCRReg;
1087    Bool dvi;
1088
1089    TRACE(("SavagePreInit(%d)\n", flags));
1090
1091    gpScrn = pScrn;
1092
1093    if (flags & PROBE_DETECT) {
1094	SavageProbeDDC( pScrn, xf86GetEntityInfo(pScrn->entityList[0])->index );
1095	return TRUE;
1096    }
1097
1098    if (!xf86LoadSubModule(pScrn, "vgahw"))
1099	return FALSE;
1100
1101    xf86LoaderReqSymLists(vgaHWSymbols, NULL);
1102    if (!vgaHWGetHWRec(pScrn))
1103	return FALSE;
1104
1105#if 0
1106    /* Here we can alter the number of registers saved and restored by the
1107     * standard vgaHWSave and Restore routines.
1108     */
1109    vgaHWSetRegCounts( pScrn, VGA_NUM_CRTC, VGA_NUM_SEQ, VGA_NUM_GFX, VGA_NUM_ATTR );
1110#endif
1111
1112    pScrn->monitor = pScrn->confScreen->monitor;
1113
1114    /*
1115     * We support depths of 8, 15, 16 and 24.
1116     * We support bpp of 8, 16, and 32.
1117     */
1118
1119    if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1120	return FALSE;
1121    else {
1122        int requiredBpp;
1123	int altBpp = 0;
1124
1125	switch (pScrn->depth) {
1126	case 8:
1127	case 16:
1128	    requiredBpp = pScrn->depth;
1129	    break;
1130	case 15:
1131	    requiredBpp = 16;
1132	    break;
1133	case 24:
1134	    requiredBpp = 32;
1135	    altBpp = 24;
1136	    break;
1137
1138	default:
1139	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1140		       "Given depth (%d) is not supported by this driver\n",
1141			pScrn->depth);
1142	    return FALSE;
1143	}
1144
1145	if(
1146	    (pScrn->bitsPerPixel != requiredBpp) &&
1147	    (pScrn->bitsPerPixel != altBpp)
1148	) {
1149	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1150		       "Depth %d must specify %d bpp; %d was given\n",
1151		       pScrn->depth, requiredBpp, pScrn->bitsPerPixel );
1152	    return FALSE;
1153	}
1154    }
1155
1156    xf86PrintDepthBpp(pScrn);
1157
1158    if (pScrn->depth > 8) {
1159	rgb zeros = {0, 0, 0};
1160
1161	if (!xf86SetWeight(pScrn, zeros, zeros))
1162	    return FALSE;
1163	else {
1164	    /* TODO check weight returned is supported */
1165	    ;
1166	}
1167    }
1168
1169    if (!xf86SetDefaultVisual(pScrn, -1)) {
1170	return FALSE;
1171    } else {
1172	/* We don't currently support DirectColor at 16bpp */
1173	if (pScrn->bitsPerPixel == 16 && pScrn->defaultVisual != TrueColor) {
1174	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Given default visual"
1175		       " (%s) is not supported at depth %d\n",
1176		       xf86GetVisualName(pScrn->defaultVisual), pScrn->depth);
1177	    return FALSE;
1178	}
1179    }
1180
1181    pScrn->progClock = TRUE;
1182
1183    if (!SavageGetRec(pScrn))
1184	return FALSE;
1185    psav = SAVPTR(pScrn);
1186
1187    hwp = VGAHWPTR(pScrn);
1188    vgaHWGetIOBase(hwp);
1189    psav->vgaIOBase = hwp->IOBase;
1190
1191    xf86CollectOptions(pScrn, NULL);
1192
1193    if (pScrn->depth == 8)
1194	pScrn->rgbBits = 8;
1195
1196    if (!(psav->Options = xalloc(sizeof(SavageOptions))))
1197	return FALSE;
1198    memcpy(psav->Options, SavageOptions, sizeof(SavageOptions));
1199    xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, psav->Options);
1200
1201    xf86GetOptValBool(psav->Options, OPTION_PCI_BURST, &psav->pci_burst);
1202
1203    if (psav->pci_burst) {
1204	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1205		   "Option: pci_burst - PCI burst read enabled\n");
1206    }
1207
1208    psav->NoPCIRetry = 1;		/* default */
1209    if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_RETRY, FALSE)) {
1210	if (xf86ReturnOptValBool(psav->Options, OPTION_PCI_BURST, FALSE)) {
1211	    psav->NoPCIRetry = 0;
1212	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: pci_retry\n");
1213	} else
1214	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"pci_retry\" option requires \"pci_burst\"\n");
1215    }
1216
1217    xf86GetOptValBool( psav->Options, OPTION_SHADOW_FB, &psav->shadowFB );
1218    if (psav->shadowFB) {
1219	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Option: shadow FB enabled\n");
1220    }
1221
1222    psav->primStreamBpp = pScrn->bitsPerPixel;
1223
1224    if ((s = xf86GetOptValString(psav->Options, OPTION_ROTATE))) {
1225	if(!xf86NameCmp(s, "CW")) {
1226	    /* accel is disabled below for shadowFB */
1227             /* RandR is disabled when the Rotate option is used (does
1228              * not work well together and scrambles the screen) */
1229
1230	    psav->shadowFB = TRUE;
1231	    psav->rotate = 1;
1232            xf86DisableRandR();
1233	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1234		       "Rotating screen clockwise"
1235                       "- acceleration and RandR disabled\n");
1236	} else if(!xf86NameCmp(s, "CCW")) {
1237	    psav->shadowFB = TRUE;
1238	    psav->rotate = -1;
1239            xf86DisableRandR();
1240            xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1241                   "Rotating screen counter clockwise"
1242                   " - acceleration and RandR disabled\n");
1243
1244	} else {
1245	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "\"%s\" is not a valid"
1246		       "value for Option \"Rotate\"\n", s);
1247	    xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1248		       "Valid options are \"CW\" or \"CCW\"\n");
1249	}
1250    }
1251
1252    if (xf86GetOptValBool(psav->Options, OPTION_NOACCEL, &psav->NoAccel))
1253	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1254		    "Option: NoAccel - Acceleration Disabled\n");
1255
1256    if (psav->shadowFB && !psav->NoAccel) {
1257	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1258		   "HW acceleration not supported with \"shadowFB\".\n");
1259	psav->NoAccel = TRUE;
1260    }
1261
1262    if(!psav->NoAccel) {
1263        from = X_DEFAULT;
1264	char *strptr;
1265        if((strptr = (char *)xf86GetOptValString(psav->Options, OPTION_ACCELMETHOD))) {
1266	    if(!xf86NameCmp(strptr,"XAA")) {
1267	        from = X_CONFIG;
1268	        psav->useEXA = FALSE;
1269	    } else if(!xf86NameCmp(strptr,"EXA")) {
1270	       from = X_CONFIG;
1271	       psav->useEXA = TRUE;
1272	    }
1273       }
1274       xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
1275		psav->useEXA ? "EXA" : "XAA");
1276    }
1277
1278    if ((s = xf86GetOptValString(psav->Options, OPTION_OVERLAY))) {
1279
1280	if (psav->shadowFB) {
1281	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1282		       "Option \"Overlay\" not supported with shadowFB\n");
1283	} else {
1284	    if (pScrn->depth == 8) {
1285		if (!*s || !xf86NameCmp(s, "24")) {
1286		    psav->overlayDepth = 24;
1287		    psav->NoAccel = TRUE; /* Preliminary */
1288		    pScrn->colorKey = TRANSPARENCY_KEY;
1289		    pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1290		} else if (!xf86NameCmp(s, "16")) {
1291		    psav->overlayDepth = 16;
1292		    psav->NoAccel = TRUE; /* Preliminary */
1293		    pScrn->colorKey = TRANSPARENCY_KEY;
1294		    pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1295		} else {
1296		    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
1297			       "\"%s\" Ingnoring\n",s);
1298		}
1299	    } else if (pScrn->depth != 15) {
1300		psav->overlayDepth = 8;
1301		psav->NoAccel = TRUE; /* Preliminary */
1302		pScrn->colorKey = TRANSPARENCY_KEY;
1303		pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1304		if (*s && (xf86NameCmp(s, "8")))
1305		    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
1306			       "\"%s\" for depth %i overlay depth must be 8\n",
1307			       s,pScrn->depth);
1308	    } else {
1309		 xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Overlay not "
1310			       "supported for depth 15\n");
1311	    }
1312	    if (psav->overlayDepth) {
1313		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"%i/%i Overlay enabled\n",
1314			   pScrn->depth,psav->overlayDepth);
1315		psav->primStreamBpp = 8;
1316	    }
1317	}
1318    }
1319
1320    if (pScrn->bitsPerPixel == 24 && !psav->NoAccel) {
1321	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1322		   "HW acceleration not possible with depth 32 and bpp 24.\n");
1323	psav->NoAccel = TRUE;
1324    }
1325
1326    /*
1327     * The SWCursor setting takes priority over HWCursor.  The default
1328     * if neither is specified is HW, unless ShadowFB is specified,
1329     * then SW.
1330     */
1331
1332    from = X_DEFAULT;
1333    psav->hwcursor = psav->shadowFB ? FALSE : TRUE;
1334    if (xf86GetOptValBool(psav->Options, OPTION_HWCURSOR, &psav->hwcursor))
1335	from = X_CONFIG;
1336    if (xf86ReturnOptValBool(psav->Options, OPTION_SWCURSOR, FALSE)) {
1337	psav->hwcursor = FALSE;
1338	from = X_CONFIG;
1339    }
1340    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
1341        psav->hwcursor ? "HW" : "SW");
1342
1343    from = X_DEFAULT;
1344    psav->UseBIOS = TRUE;
1345    if (xf86GetOptValBool(psav->Options, OPTION_USEBIOS, &psav->UseBIOS) )
1346	from = X_CONFIG;
1347    xf86DrvMsg(pScrn->scrnIndex, from, "%ssing video BIOS to set modes\n",
1348        psav->UseBIOS ? "U" : "Not u" );
1349
1350    psav->LCDClock = 0.0;
1351    if( xf86GetOptValFreq( psav->Options, OPTION_LCDCLOCK, OPTUNITS_MHZ, &psav->LCDClock ) )
1352	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1353		    "Option: LCDClock %1.2f MHz\n", psav->LCDClock );
1354
1355    if( xf86GetOptValBool( psav->Options, OPTION_SHADOW_STATUS, &psav->ShadowStatus)) {
1356	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1357		    "Option: ShadowStatus %sabled\n", psav->ShadowStatus ? "en" : "dis" );
1358	psav->ForceShadowStatus = TRUE;
1359    } else
1360	psav->ForceShadowStatus = FALSE;
1361    /* If ShadowStatus is off it will be automatically enabled for DRI.
1362     * If DRI initialization fails fall back to ConfigShadowStatus. */
1363    psav->ConfigShadowStatus = psav->ShadowStatus;
1364
1365    if( xf86GetOptValBool( psav->Options, OPTION_CRT_ONLY, &psav->CrtOnly))
1366	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1367		    "Option: CrtOnly enabled\n" );
1368
1369    if( xf86GetOptValBool( psav->Options, OPTION_TV_ON, &psav->TvOn)) {
1370        psav->PAL = FALSE;
1371        SavageGetTvMaxSize(psav);
1372    }
1373
1374    if( xf86GetOptValBool( psav->Options, OPTION_TV_PAL, &psav->PAL)) {
1375        SavageGetTvMaxSize(psav);
1376	psav->TvOn = TRUE;
1377    }
1378
1379    if( psav->TvOn )
1380	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1381		    "TV enabled in %s format\n",
1382		    psav->PAL ? "PAL" : "NTSC" );
1383
1384    psav->ForceInit = 0;
1385    if( xf86GetOptValBool( psav->Options, OPTION_FORCE_INIT, &psav->ForceInit))
1386	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1387		    "Option: ForceInit enabled\n" );
1388
1389    if (pScrn->numEntities > 1) {
1390	SavageFreeRec(pScrn);
1391	return FALSE;
1392    }
1393
1394    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
1395    if (pEnt->resources) {
1396	xfree(pEnt);
1397	SavageFreeRec(pScrn);
1398	return FALSE;
1399    }
1400    psav->EntityIndex = pEnt->index;
1401
1402    if (xf86LoadSubModule(pScrn, "vbe")) {
1403	xf86LoaderReqSymLists(vbeSymbols, NULL);
1404	psav->pVbe = VBEInit(NULL, pEnt->index);
1405    }
1406
1407    psav->PciInfo = xf86GetPciInfoForEntity(pEnt->index);
1408    xf86RegisterResources(pEnt->index, NULL, ResNone);
1409    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
1410    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
1411
1412    from = X_DEFAULT;
1413    if (pEnt->device->chipset && *pEnt->device->chipset) {
1414	pScrn->chipset = pEnt->device->chipset;
1415	psav->ChipId = pEnt->device->chipID;
1416	psav->Chipset = xf86StringToToken(SavageChipsets, pScrn->chipset);
1417	from = X_CONFIG;
1418    } else if (pEnt->device->chipID >= 0) {
1419	psav->ChipId = pEnt->device->chipID;
1420	psav->Chipset = LookupChipID(SavagePciChipsets, psav->ChipId);
1421	pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
1422						   psav->Chipset);
1423	from = X_CONFIG;
1424	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
1425		   pEnt->device->chipID);
1426    } else {
1427	from = X_PROBED;
1428	psav->ChipId = psav->PciInfo->chipType;
1429	psav->Chipset = LookupChipID(SavagePciChipsets, psav->ChipId);
1430	pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
1431						   psav->Chipset);
1432    }
1433
1434    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chip: id %04x, \"%s\"\n",
1435	       psav->ChipId, xf86TokenToString( SavageChips, psav->ChipId ) );
1436
1437    if (pEnt->device->chipRev >= 0) {
1438	psav->ChipRev = pEnt->device->chipRev;
1439	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
1440		   psav->ChipRev);
1441    } else
1442	psav->ChipRev = psav->PciInfo->chipRev;
1443
1444    xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
1445
1446    if (pEnt->device->videoRam != 0)
1447    	pScrn->videoRam = pEnt->device->videoRam;
1448
1449    xfree(pEnt);
1450
1451    psav->PciTag = pciTag(psav->PciInfo->bus, psav->PciInfo->device,
1452			  psav->PciInfo->func);
1453
1454
1455    /* Set AGP Mode from config */
1456    /* We support 1X 2X and 4X  */
1457#ifdef XF86DRI
1458				/* AGP/PCI (FK: copied from radeon_driver.c) */
1459    /* Proper autodetection of an AGP capable device requires examining
1460     * PCI config registers to determine if the device implements extended
1461     * PCI capabilities, and then walking the capability list as indicated
1462     * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP
1463     * capability is present.  The procedure is outlined as follows:
1464     *
1465     * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device
1466     *    to determine wether or not this device implements any extended
1467     *    capabilities.  If this bit is zero, then the device is a PCI 2.1
1468     *    or earlier device and is not AGP capable, and we can conclude it
1469     *    to be a PCI device.
1470     *
1471     * 2) If bit 4 of the status register is set, then the device implements
1472     *    extended capabilities.  There is an 8 bit wide capabilities pointer
1473     *    register located at offset 0x34 in PCI config space which points to
1474     *    the first capability in a linked list of extended capabilities that
1475     *    this device implements.  The lower two bits of this register are
1476     *    reserved and MBZ so must be masked out.
1477     *
1478     * 3) The extended capabilities list is formed by one or more extended
1479     *    capabilities structures which are aligned on DWORD boundaries.
1480     *    The first byte of the structure is the capability ID (CAP_ID)
1481     *    indicating what extended capability this structure refers to.  The
1482     *    second byte of the structure is an offset from the beginning of
1483     *    PCI config space pointing to the next capability in the linked
1484     *    list (NEXT_PTR) or NULL (0x00) at the end of the list.  The lower
1485     *    two bits of this pointer are reserved and MBZ.  By examining the
1486     *    CAP_ID of each capability and walking through the list, we will
1487     *    either find the AGP_CAP_ID (0x02) indicating this device is an
1488     *    AGP device, or we'll reach the end of the list, indicating it is
1489     *    a PCI device.
1490     *
1491     * Mike A. Harris <mharris@redhat.com>
1492     *
1493     * References:
1494     *	- PCI Local Bus Specification Revision 2.2, Chapter 6
1495     *	- AGP Interface Specification Revision 2.0, Section 6.1.5
1496     */
1497
1498    psav->IsPCI = TRUE;
1499
1500    if (pciReadLong(psav->PciTag, PCI_CMD_STAT_REG) & SAVAGE_CAP_LIST) {
1501	CARD32 cap_ptr, cap_id;
1502
1503	cap_ptr = pciReadLong(psav->PciTag,
1504			      SAVAGE_CAPABILITIES_PTR_PCI_CONFIG)
1505	    & SAVAGE_CAP_PTR_MASK;
1506
1507	while(cap_ptr != SAVAGE_CAP_ID_NULL) {
1508	    cap_id = pciReadLong(psav->PciTag, cap_ptr);
1509	    if ((cap_id & 0xff) == SAVAGE_CAP_ID_AGP) {
1510		psav->IsPCI = FALSE;
1511		break;
1512	    }
1513	    cap_ptr = (cap_id >> 8) & SAVAGE_CAP_PTR_MASK;
1514	}
1515    }
1516
1517    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%s card detected\n",
1518	       (psav->IsPCI) ? "PCI" : "AGP");
1519
1520    if ((s = xf86GetOptValString(psav->Options, OPTION_BUS_TYPE))) {
1521	if (strcmp(s, "AGP") == 0) {
1522	    if (psav->IsPCI) {
1523		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1524			   "BusType AGP not available on PCI card\n");
1525	    } else {
1526		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to AGP\n");
1527	    }
1528	} else if (strcmp(s, "PCI") == 0) {
1529	    psav->IsPCI = TRUE;
1530	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to PCI\n");
1531	} else {
1532	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1533		       "Invalid BusType option, using %s DMA\n",
1534		       psav->IsPCI ? "PCI" : "AGP");
1535	}
1536    }
1537
1538    psav->AgpDMA = !psav->IsPCI;
1539    if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_TYPE))) {
1540	if (strcmp(s, "AGP") == 0) {
1541	    if (psav->IsPCI) {
1542		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1543			   "AGP DMA not available on PCI card, using PCI DMA\n");
1544	    } else {
1545		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using AGP DMA\n");
1546	    }
1547	} else if (strcmp(s, "PCI") == 0) {
1548	    psav->AgpDMA = FALSE;
1549	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using PCI DMA\n");
1550	} else {
1551	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1552		       "Invalid DmaType option, using %s DMA\n",
1553		       psav->AgpDMA ? "AGP" : "PCI");
1554	}
1555    } else {
1556	xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
1557		   "Using %s DMA\n", psav->AgpDMA ? "AGP" : "PCI");
1558    }
1559
1560    psav->CommandDMA = TRUE;
1561    psav->VertexDMA = TRUE;
1562    from = X_DEFAULT;
1563    if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_MODE))) {
1564	from = X_CONFIG;
1565	if (strcmp(s, "Command") == 0)
1566	    psav->VertexDMA = FALSE;
1567	else if (strcmp(s, "Vertex") == 0)
1568	    psav->CommandDMA = FALSE;
1569	else if (strcmp(s, "None") == 0)
1570	    psav->VertexDMA = psav->CommandDMA = FALSE;
1571	else if (strcmp(s, "Any") != 0) {
1572	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid DmaMode option\n");
1573	    from = X_DEFAULT;
1574	}
1575    }
1576    if (psav->CommandDMA && S3_SAVAGE3D_SERIES(psav->Chipset)) {
1577	xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
1578		   "Savage3D/MX/IX does not support command DMA.\n");
1579	psav->CommandDMA = FALSE;
1580    }
1581    if ((psav->CommandDMA || psav->VertexDMA) &&
1582	psav->Chipset == S3_SUPERSAVAGE) {
1583	xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
1584		   "DMA is not supported on SuperSavages.\n");
1585	psav->CommandDMA = psav->VertexDMA = FALSE;
1586    }
1587    if (psav->CommandDMA && psav->VertexDMA)
1588	xf86DrvMsg(pScrn->scrnIndex, from,
1589		   "Will try command and vertex DMA mode\n");
1590    else if (psav->CommandDMA && !psav->VertexDMA)
1591	xf86DrvMsg(pScrn->scrnIndex, from,
1592		   "Will try only command DMA mode\n");
1593    else if (!psav->CommandDMA && psav->VertexDMA)
1594	xf86DrvMsg(pScrn->scrnIndex, from,
1595		   "Will try only vertex DMA mode\n");
1596    else
1597	xf86DrvMsg(pScrn->scrnIndex, from,
1598		   "DMA disabled\n");
1599
1600    if (!psav->IsPCI) {
1601	from = X_DEFAULT;
1602	psav->agpMode = SAVAGE_DEFAULT_AGP_MODE;
1603	/*psav->agpMode = SAVAGE_MAX_AGP_MODE;*/
1604	psav->agpSize = 16;
1605
1606	if (xf86GetOptValInteger(psav->Options,
1607				 OPTION_AGP_MODE, &(psav->agpMode))) {
1608	    if (psav->agpMode < 1) {
1609		psav->agpMode = 1;
1610	    }
1611	    if (psav->agpMode > SAVAGE_MAX_AGP_MODE) {
1612		psav->agpMode = SAVAGE_MAX_AGP_MODE;
1613	    }
1614	    if ((psav->agpMode > 2) &&
1615		(psav->Chipset == S3_SAVAGE3D ||
1616		 psav->Chipset == S3_SAVAGE_MX))
1617		psav->agpMode = 2; /* old savages only support 2x */
1618	    from = X_CONFIG;
1619	}
1620
1621	xf86DrvMsg(pScrn->scrnIndex, from, "Using AGP %dx mode\n",
1622		   psav->agpMode);
1623
1624	from = X_DEFAULT;
1625	if (xf86GetOptValInteger(psav->Options,
1626				 OPTION_AGP_SIZE, (int *)&(psav->agpSize))) {
1627	    switch (psav->agpSize) {
1628	    case 4:
1629	    case 8:
1630	    case 16:
1631	    case 32:
1632	    case 64:
1633	    case 128:
1634	    case 256:
1635		from = X_CONFIG;
1636		break;
1637	    default:
1638		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1639			   "Illegal AGP size: %d MB, defaulting to 16 MB\n", psav->agpSize);
1640		psav->agpSize = 16;
1641	    }
1642	}
1643
1644	xf86DrvMsg(pScrn->scrnIndex, from,
1645		   "Using %d MB AGP aperture\n", psav->agpSize);
1646    } else {
1647	psav->agpMode = 0;
1648	psav->agpSize = 0;
1649    }
1650
1651#endif
1652
1653    /* we can use Option "DisableTile TRUE" to disable tile mode */
1654    psav->bDisableTile = FALSE;
1655    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_TILE,&psav->bDisableTile)) {
1656        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1657                   "Option: %s Tile Mode and Program it \n",(psav->bDisableTile?"Disable":"Enable"));
1658    }
1659
1660#ifdef XF86DRI
1661    /* disabled by default...doesn't seem to work */
1662    psav->bDisableXvMC = TRUE; /* if you want to free up more mem for DRI,etc. */
1663    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_XVMC, &psav->bDisableXvMC)) {
1664        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1665                   "Option: %s Hardware XvMC support\n",(psav->bDisableXvMC?"Disable":"Enable"));
1666    }
1667#endif
1668
1669    psav->disableCOB = FALSE; /* if you are having problems on savage4+ */
1670    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_COB, &psav->disableCOB)) {
1671        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1672                   "Option: %s the COB\n",(psav->disableCOB?"Disable":"Enable"));
1673    }
1674    if (psav->Chipset == S3_PROSAVAGE ||
1675	psav->Chipset == S3_TWISTER   ||
1676	psav->Chipset == S3_PROSAVAGEDDR)
1677	psav->BCIforXv = TRUE;
1678    else
1679    	psav->BCIforXv = FALSE; /* use the BCI for Xv */
1680    if (xf86GetOptValBool(psav->Options, OPTION_BCI_FOR_XV, &psav->BCIforXv)) {
1681        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1682                   "Option: %s use of the BCI for Xv\n",(psav->BCIforXv?"Enable":"Disable"));
1683    }
1684    psav->dvi = FALSE;
1685    if (xf86GetOptValBool(psav->Options, OPTION_DVI, &psav->dvi)) {
1686        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1687                   "%s DVI port support (Savage4 only)\n",(psav->dvi?"Force":"Disable"));
1688    }
1689
1690    /* Add more options here. */
1691
1692
1693    psav               = SAVPTR(pScrn);
1694    psav->IsSecondary  = FALSE;
1695    psav->IsPrimary    = FALSE;
1696    psav->pEnt         = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1697
1698    if (xf86IsEntityShared(psav->pEnt->index)) {
1699	if (xf86IsPrimInitDone(psav->pEnt->index)) {
1700
1701	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
1702
1703	    psav->IsSecondary = TRUE;
1704	    pSavageEnt->pSecondaryScrn = pScrn;
1705	    psav->TvOn = pSavageEnt->TvOn;
1706	} else {
1707	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
1708
1709	    xf86SetPrimInitDone(psav->pEnt->index);
1710
1711	    psav->IsPrimary = TRUE;
1712	    pSavageEnt->pPrimaryScrn        = pScrn;
1713	    pSavageEnt->TvOn = psav->TvOn;
1714	}
1715    }
1716
1717    switch(psav->Chipset) {
1718	case S3_SAVAGE_MX:
1719	case S3_SUPERSAVAGE:
1720	    psav->HasCRTC2 = TRUE;
1721	    break;
1722        default:
1723            psav->HasCRTC2 = FALSE;
1724    }
1725
1726    if ((psav->IsSecondary || psav->IsPrimary) && !psav->UseBIOS) {
1727	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "BIOS currently required for Dualhead mode setting.\n");
1728	return FALSE;
1729    }
1730
1731    if (psav->IsSecondary &&
1732	(pScrn->bitsPerPixel > 16) &&
1733	!psav->NoAccel &&
1734	(psav->Chipset == S3_SAVAGE_MX)) {
1735	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No acceleration in Dualhead mode at depth 24\n");
1736	return FALSE;
1737    }
1738
1739    /* maybe throw in some more sanity checks here */
1740
1741    if (!SavageMapMem(pScrn)) {
1742	SavageFreeRec(pScrn);
1743        vbeFree(psav->pVbe);
1744	psav->pVbe = NULL;
1745	return FALSE;
1746    }
1747
1748    vgaCRIndex = psav->vgaIOBase + 4;
1749    vgaCRReg = psav->vgaIOBase + 5;
1750
1751    xf86EnableIO();
1752    /* unprotect CRTC[0-7] */
1753    VGAOUT8(vgaCRIndex, 0x11);
1754    tmp = VGAIN8(vgaCRReg);
1755    VGAOUT8(vgaCRReg, tmp & 0x7f);
1756
1757    /* unlock extended regs */
1758    VGAOUT16(vgaCRIndex, 0x4838);
1759    VGAOUT16(vgaCRIndex, 0xa039);
1760    VGAOUT16(0x3c4, 0x0608);
1761
1762    VGAOUT8(vgaCRIndex, 0x40);
1763    tmp = VGAIN8(vgaCRReg);
1764    VGAOUT8(vgaCRReg, tmp & ~0x01);
1765
1766    /* unlock sys regs */
1767    VGAOUT8(vgaCRIndex, 0x38);
1768    VGAOUT8(vgaCRReg, 0x48);
1769
1770    {
1771	Gamma zeros = {0.0, 0.0, 0.0};
1772
1773	if (!xf86SetGamma(pScrn, zeros)) {
1774	    vbeFree(psav->pVbe);
1775	    psav->pVbe = NULL;
1776	    SavageFreeRec(pScrn);
1777	    return FALSE;
1778	}
1779    }
1780
1781    /* Unlock system registers. */
1782    VGAOUT16(vgaCRIndex, 0x4838);
1783
1784    /* Next go on to detect amount of installed ram */
1785
1786    VGAOUT8(vgaCRIndex, 0x36);            /* for register CR36 (CONFG_REG1), */
1787    config1 = VGAIN8(vgaCRReg);           /* get amount of vram installed */
1788
1789    /* Compute the amount of video memory and offscreen memory. */
1790
1791    if (!pScrn->videoRam) {
1792	static const unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
1793	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
1794	static const unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
1795	static const unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
1796
1797	switch( psav->Chipset ) {
1798	case S3_SAVAGE3D:
1799	    pScrn->videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
1800	    break;
1801
1802	case S3_SAVAGE4:
1803	    /*
1804	     * The Savage4 has one ugly special case to consider.  On
1805	     * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
1806	     * when it really means 8MB.  Why do it the same when you
1807	     * can do it different...
1808	     */
1809	    VGAOUT8(vgaCRIndex, 0x68);	/* memory control 1 */
1810	    if( (VGAIN8(vgaCRReg) & 0xC0) == (0x01 << 6) )
1811		RamSavage4[1] = 8;
1812
1813	    /*FALLTHROUGH*/
1814
1815	case S3_SAVAGE2000:
1816	    pScrn->videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
1817	    break;
1818
1819	case S3_SAVAGE_MX:
1820	case S3_SUPERSAVAGE:
1821	    pScrn->videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
1822	    break;
1823
1824	case S3_PROSAVAGE:
1825	case S3_PROSAVAGEDDR:
1826	case S3_TWISTER:
1827	    pScrn->videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
1828	    break;
1829
1830	default:
1831	    /* How did we get here? */
1832	    pScrn->videoRam = 0;
1833	    break;
1834	}
1835
1836	psav->videoRambytes = pScrn->videoRam * 1024;
1837
1838	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1839		"probed videoram:  %dk\n",
1840		pScrn->videoRam);
1841    } else {
1842	psav->videoRambytes = pScrn->videoRam * 1024;
1843
1844	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1845	       "videoram =  %dk\n",
1846		pScrn->videoRam);
1847    }
1848
1849    /* Get video RAM */
1850    if( !pScrn->videoRam && psav->pVbe )
1851    {
1852        /* If VBE is available, ask it about onboard memory. */
1853
1854	VbeInfoBlock* vib;
1855
1856	vib = VBEGetVBEInfo( psav->pVbe );
1857	pScrn->videoRam = vib->TotalMemory * 64;
1858	VBEFreeVBEInfo( vib );
1859
1860	/* VBE often cuts 64k off of the RAM total. */
1861
1862	if( pScrn->videoRam & 64 )
1863	    pScrn->videoRam += 64;
1864
1865	psav->videoRambytes = pScrn->videoRam * 1024;
1866    }
1867
1868
1869    /*
1870     * If we're running with acceleration, compute the command overflow
1871     * buffer location.  The command overflow buffer must END at a
1872     * 4MB boundary; for all practical purposes, that means the very
1873     * end of the frame buffer.
1874     */
1875    if (psav->NoAccel) {
1876        psav->cobIndex = 0;
1877        psav->cobSize = 0;
1878    }
1879    else if( ((S3_SAVAGE4_SERIES(psav->Chipset)) ||
1880             (S3_SUPERSAVAGE == psav->Chipset)) && psav->disableCOB ) {
1881        /*
1882         * The Savage4 and ProSavage have COB coherency bugs which render
1883         * the buffer useless.
1884         */
1885	/*
1886        psav->cobIndex = 2;
1887        psav->cobSize = 0x8000 << psav->cobIndex;
1888	*/
1889        psav->cobIndex = 0;
1890        psav->cobSize = 0;
1891	psav->bciThresholdHi = 32;
1892	psav->bciThresholdLo = 0;
1893    } else {
1894        /* We use 128kB for the COB on all other chips. */
1895        psav->cobSize = 0x20000;
1896	if (S3_SAVAGE3D_SERIES(psav->Chipset) ||
1897	    psav->Chipset == S3_SAVAGE2000) {
1898	    psav->cobIndex = 7; /* rev.A savage4 apparently also uses 7 */
1899	} else {
1900	    psav->cobIndex = 2;
1901	}
1902	/* max command size: 2560 entries */
1903	psav->bciThresholdHi = psav->cobSize/4 + 32 - 2560;
1904	psav->bciThresholdLo = psav->bciThresholdHi - 2560;
1905    }
1906
1907    /* align cob to 128k */
1908    psav->cobOffset = (psav->videoRambytes - psav->cobSize) & ~0x1ffff;
1909
1910    /* The cursor must be aligned on a 4k boundary. */
1911    psav->CursorKByte = (psav->cobOffset >> 10) - 4;
1912    psav->endfb = (psav->CursorKByte << 10) - 1;
1913
1914    if (psav->IsPrimary) {
1915        pScrn->videoRam /= 2;
1916	psav->videoRambytes = pScrn->videoRam * 1024;
1917	psav->CursorKByte = (psav->videoRambytes >> 10) - 4;
1918	psav->endfb = (psav->CursorKByte << 10) - 1;
1919	psav->videoRambytes *= 2;
1920	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1921		"Using %dk of videoram for primary head\n",
1922		pScrn->videoRam);
1923    }
1924
1925    if(psav->IsSecondary)
1926    {
1927        pScrn->videoRam /= 2;
1928	/*psav->videoRambytes = pScrn->videoRam * 1024;*/
1929	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1930		"Using %dk of videoram for secondary head\n",
1931		pScrn->videoRam);
1932    }
1933
1934    pScrn->fbOffset = (psav->IsSecondary)
1935      ? pScrn->videoRam * 1024 : 0;
1936
1937    /* reset graphics engine to avoid memory corruption */
1938    VGAOUT8(vgaCRIndex, 0x66);
1939    cr66 = VGAIN8(vgaCRReg);
1940    VGAOUT8(vgaCRReg, cr66 | 0x02);
1941    usleep(10000);
1942
1943    VGAOUT8(vgaCRIndex, 0x66);
1944    VGAOUT8(vgaCRReg, cr66 & ~0x02);	/* clear reset flag */
1945    usleep(10000);
1946
1947    /* Set status word positions based on chip type. */
1948    SavageInitStatus(pScrn);
1949
1950    /* check for DVI/flat panel */
1951    dvi = FALSE;
1952    if (psav->Chipset == S3_SAVAGE4) {
1953	unsigned char sr30 = 0x00;
1954	VGAOUT8(0x3c4, 0x30);
1955	/* clear bit 1 */
1956	VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x02);
1957    	sr30 = VGAIN8(0x3c5);
1958    	if (sr30 & 0x02 /*0x04 */) {
1959            dvi = TRUE;
1960	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Digital Flat Panel Detected\n");
1961	}
1962    }
1963
1964    if( (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
1965	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) && !psav->CrtOnly ) {
1966	psav->DisplayType = MT_LCD;
1967    } else if (dvi || ((psav->Chipset == S3_SAVAGE4) && psav->dvi)) {
1968	psav->DisplayType = MT_DFP;
1969    } else {
1970	psav->DisplayType = MT_CRT;
1971    }
1972
1973    if (psav->IsSecondary)
1974	psav->DisplayType = MT_CRT;
1975
1976    /* Do the DDC dance. */
1977    SavageDoDDC(pScrn);
1978
1979    /* set up ramdac max clock - might be altered by SavageGetPanelInfo */
1980    if (pScrn->bitsPerPixel >= 24)
1981        psav->maxClock = 220000;
1982    else
1983        psav->maxClock = 250000;
1984
1985    /* detect current mclk */
1986    VGAOUT8(0x3c4, 0x08);
1987    sr8 = VGAIN8(0x3c5);
1988    VGAOUT8(0x3c5, 0x06);
1989    VGAOUT8(0x3c4, 0x10);
1990    n = VGAIN8(0x3c5);
1991    VGAOUT8(0x3c4, 0x11);
1992    m = VGAIN8(0x3c5);
1993    VGAOUT8(0x3c4, 0x08);
1994    VGAOUT8(0x3c5, sr8);
1995    m &= 0x7f;
1996    n1 = n & 0x1f;
1997    n2 = (n >> 5) & 0x03;
1998    mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
1999    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
2000	       mclk / 1000.0);
2001
2002    pScrn->maxHValue = 2048 << 3;	/* 11 bits of h_total 8-pixel units */
2003    pScrn->maxVValue = 2048;		/* 11 bits of v_total */
2004    pScrn->virtualX = pScrn->display->virtualX;
2005    pScrn->virtualY = pScrn->display->virtualY;
2006
2007    /* Check LCD panel information */
2008
2009    if(psav->DisplayType == MT_LCD)
2010    {
2011	SavageGetPanelInfo(pScrn);
2012	SavageAddPanelMode(pScrn);
2013    }
2014
2015#if 0
2016    if (psav->CrtOnly && !psav->UseBIOS) {
2017	VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
2018	VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10); /* disable FP */
2019        if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) /*||
2020	    S3_MOBILE_TWISTER_SERIES(psav->Chipset)*/) { /* not sure this works on mobile prosavage */
2021		VGAOUT8(0x3c4, 0x31);
2022		VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x04); /* make sure crtc1 is crt source */
2023    	}
2024    }
2025#endif
2026
2027    if( psav->UseBIOS )
2028    {
2029	/* Go probe the BIOS for all the modes and refreshes at this depth. */
2030
2031	if( psav->ModeTable )
2032	{
2033	    SavageFreeBIOSModeTable( psav, &psav->ModeTable );
2034	}
2035
2036	psav->ModeTable = SavageGetBIOSModeTable( psav, psav->primStreamBpp );
2037
2038	if( !psav->ModeTable || !psav->ModeTable->NumModes ) {
2039	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2040		       "Failed to fetch any BIOS modes.  Disabling BIOS.\n");
2041	    psav->UseBIOS = FALSE;
2042	}
2043	else
2044	/*if( xf86Verbose )*/
2045	{
2046	    SavageModeEntryPtr pmt;
2047
2048	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2049		       "Found %d modes at this depth:\n",
2050		       psav->ModeTable->NumModes);
2051
2052	    for(
2053		i = 0, pmt = psav->ModeTable->Modes;
2054		i < psav->ModeTable->NumModes;
2055		i++, pmt++ )
2056	    {
2057		int j;
2058		ErrorF( "    [%03x] %d x %d",
2059			pmt->VesaMode, pmt->Width, pmt->Height );
2060		for( j = 0; j < pmt->RefreshCount; j++ )
2061		{
2062		    ErrorF( ", %dHz", pmt->RefreshRate[j] );
2063		}
2064		ErrorF( "\n");
2065	    }
2066	}
2067    }
2068
2069    clockRanges = xnfalloc(sizeof(ClockRange));
2070    clockRanges->next = NULL;
2071    clockRanges->minClock = 10000;
2072    clockRanges->maxClock = psav->maxClock;
2073    clockRanges->clockIndex = -1;
2074    clockRanges->interlaceAllowed = TRUE;
2075    clockRanges->doubleScanAllowed = TRUE;
2076    clockRanges->ClockDivFactor = 1.0;
2077    clockRanges->ClockMulFactor = 1.0;
2078
2079    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
2080			  pScrn->display->modes, clockRanges, NULL,
2081			  256, 2048, 16 * pScrn->bitsPerPixel,
2082			  128, 2048,
2083			  pScrn->virtualX, pScrn->virtualY,
2084			  psav->videoRambytes, LOOKUP_BEST_REFRESH);
2085
2086    if (i == -1) {
2087	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
2088	SavageFreeRec(pScrn);
2089	vbeFree(psav->pVbe);
2090	psav->pVbe = NULL;
2091	return FALSE;
2092    }
2093
2094    xf86PruneDriverModes(pScrn);
2095
2096    if (i == 0 || pScrn->modes == NULL) {
2097	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
2098	SavageFreeRec(pScrn);
2099	vbeFree(psav->pVbe);
2100	psav->pVbe = NULL;
2101	return FALSE;
2102    }
2103
2104    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
2105    pScrn->currentMode = pScrn->modes;
2106    xf86PrintModes(pScrn);
2107    xf86SetDpi(pScrn, 0, 0);
2108
2109    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
2110	SavageFreeRec(pScrn);
2111	vbeFree(psav->pVbe);
2112	psav->pVbe = NULL;
2113	return FALSE;
2114    }
2115
2116    xf86LoaderReqSymLists(fbSymbols, NULL);
2117
2118    if( !psav->NoAccel ) {
2119
2120        char *modName = NULL;
2121        const char **symNames = NULL;
2122
2123	if (psav->useEXA) {
2124	    modName = "exa";
2125	    symNames = exaSymbols;
2126	    XF86ModReqInfo req;
2127	    int errmaj, errmin;
2128	    memset(&req, 0, sizeof(req));
2129	    req.majorversion = 2;
2130	    req.minorversion = 0;
2131
2132	    if( !LoadSubModule(pScrn->module, modName,
2133		NULL, NULL, NULL, &req, &errmaj, &errmin) ) {
2134		LoaderErrorMsg(NULL, modName, errmaj, errmin);
2135	    	SavageFreeRec(pScrn);
2136	    	vbeFree(psav->pVbe);
2137	    	psav->pVbe = NULL;
2138	    	return FALSE;
2139	    }
2140	} else {
2141	    modName = "xaa";
2142	    symNames = xaaSymbols;
2143	    if( !xf86LoadSubModule(pScrn, modName) ) {
2144	    	SavageFreeRec(pScrn);
2145	    	vbeFree(psav->pVbe);
2146	    	psav->pVbe = NULL;
2147	    	return FALSE;
2148	    }
2149	}
2150
2151	xf86LoaderReqSymLists(symNames, NULL );
2152
2153    }
2154
2155    if (psav->hwcursor) {
2156	if (!xf86LoadSubModule(pScrn, "ramdac")) {
2157	    SavageFreeRec(pScrn);
2158	    vbeFree(psav->pVbe);
2159	    psav->pVbe = NULL;
2160	    return FALSE;
2161	}
2162	xf86LoaderReqSymLists(ramdacSymbols, NULL);
2163    }
2164
2165    if (psav->shadowFB) {
2166	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
2167	    SavageFreeRec(pScrn);
2168	    vbeFree(psav->pVbe);
2169	    psav->pVbe = NULL;
2170	    return FALSE;
2171	}
2172	xf86LoaderReqSymLists(shadowSymbols, NULL);
2173    }
2174    vbeFree(psav->pVbe);
2175
2176    psav->pVbe = NULL;
2177
2178    return TRUE;
2179}
2180
2181
2182static Bool SavageEnterVT(int scrnIndex, int flags)
2183{
2184    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2185#ifdef XF86DRI
2186    SavagePtr psav= SAVPTR(pScrn);
2187    ScreenPtr pScreen;
2188    SAVAGESAREAPrivPtr pSAREAPriv;
2189#endif
2190
2191    TRACE(("SavageEnterVT(%d)\n", flags));
2192
2193    gpScrn = pScrn;
2194    SavageEnableMMIO(pScrn);
2195
2196#ifdef XF86DRI
2197    if (psav->directRenderingEnabled) {
2198        pScreen = screenInfo.screens[scrnIndex];
2199	pSAREAPriv = (SAVAGESAREAPrivPtr)DRIGetSAREAPrivate(pScreen);
2200	/* Assume that 3D state was clobbered, invalidate it by
2201	 * changing ctxOwner in the sarea. */
2202	pSAREAPriv->ctxOwner = DRIGetContext(pScreen);
2203        DRIUnlock(pScreen);
2204        psav->LockHeld = 0;
2205    }
2206#endif
2207    if (!SAVPTR(pScrn)->IsSecondary)
2208    	SavageSave(pScrn);
2209    if(SavageModeInit(pScrn, pScrn->currentMode)) {
2210	/* some BIOSes seem to enable HW cursor on PM resume */
2211	if (!SAVPTR(pScrn)->hwc_on)
2212	    SavageHideCursor( pScrn );
2213	return TRUE;
2214    }
2215
2216    return FALSE;
2217}
2218
2219
2220static void SavageLeaveVT(int scrnIndex, int flags)
2221{
2222    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
2223    vgaHWPtr hwp = VGAHWPTR(pScrn);
2224    SavagePtr psav = SAVPTR(pScrn);
2225    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2226    SavageRegPtr SavageSavePtr = &psav->SavedReg;
2227#ifdef XF86DRI
2228    ScreenPtr pScreen;
2229#endif
2230
2231    TRACE(("SavageLeaveVT(%d)\n", flags));
2232    gpScrn = pScrn;
2233
2234#ifdef XF86DRI
2235    if (psav->directRenderingEnabled) {
2236        pScreen = screenInfo.screens[scrnIndex];
2237        DRILock(pScreen, 0);
2238        psav->LockHeld = 1;
2239    }
2240#endif
2241    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
2242        SavageStreamsOff(pScrn);
2243    SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
2244    SavageResetStreams(pScrn);
2245    SavageDisableMMIO(pScrn);
2246
2247}
2248
2249
2250static void SavageSave(ScrnInfoPtr pScrn)
2251{
2252    unsigned char cr3a, cr53, cr66;
2253    vgaHWPtr hwp = VGAHWPTR(pScrn);
2254    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2255    SavagePtr psav = SAVPTR(pScrn);
2256    SavageRegPtr save = &psav->SavedReg;
2257    unsigned short vgaCRReg = psav->vgaIOBase + 5;
2258    unsigned short vgaCRIndex = psav->vgaIOBase + 4;
2259
2260    TRACE(("SavageSave()\n"));
2261
2262    VGAOUT16(vgaCRIndex, 0x4838);
2263    VGAOUT16(vgaCRIndex, 0xa039);
2264    VGAOUT16(0x3c4, 0x0608);
2265
2266    VGAOUT8(vgaCRIndex, 0x66);
2267    cr66 = VGAIN8(vgaCRReg);
2268    VGAOUT8(vgaCRReg, cr66 | 0x80);
2269    VGAOUT8(vgaCRIndex, 0x3a);
2270    cr3a = VGAIN8(vgaCRReg);
2271    VGAOUT8(vgaCRReg, cr3a | 0x80);
2272    VGAOUT8(vgaCRIndex, 0x53);
2273    cr53 = VGAIN8(vgaCRReg);
2274    VGAOUT8(vgaCRReg, cr53 & 0x7f);
2275
2276    if (xf86IsPrimaryPci(psav->PciInfo))
2277	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
2278    else
2279	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
2280
2281    VGAOUT8(vgaCRIndex, 0x66);
2282    VGAOUT8(vgaCRReg, cr66);
2283    VGAOUT8(vgaCRIndex, 0x3a);
2284    VGAOUT8(vgaCRReg, cr3a);
2285
2286    VGAOUT8(vgaCRIndex, 0x66);
2287    VGAOUT8(vgaCRReg, cr66);
2288    VGAOUT8(vgaCRIndex, 0x3a);
2289    VGAOUT8(vgaCRReg, cr3a);
2290
2291    /* unlock extended seq regs */
2292    VGAOUT8(0x3c4, 0x08);
2293    save->SR08 = VGAIN8(0x3c5);
2294    VGAOUT8(0x3c5, 0x06);
2295
2296    /* now save all the extended regs we need */
2297    VGAOUT8(vgaCRIndex, 0x31);
2298    save->CR31 = VGAIN8(vgaCRReg);
2299    VGAOUT8(vgaCRIndex, 0x32);
2300    save->CR32 = VGAIN8(vgaCRReg);
2301    VGAOUT8(vgaCRIndex, 0x34);
2302    save->CR34 = VGAIN8(vgaCRReg);
2303    VGAOUT8(vgaCRIndex, 0x36);
2304    save->CR36 = VGAIN8(vgaCRReg);
2305    VGAOUT8(vgaCRIndex, 0x3a);
2306    save->CR3A = VGAIN8(vgaCRReg);
2307    VGAOUT8(vgaCRIndex, 0x40);
2308    save->CR40 = VGAIN8(vgaCRReg);
2309    VGAOUT8(vgaCRIndex, 0x42);
2310    save->CR42 = VGAIN8(vgaCRReg);
2311    VGAOUT8(vgaCRIndex, 0x45);
2312    save->CR45 = VGAIN8(vgaCRReg);
2313    VGAOUT8(vgaCRIndex, 0x50);
2314    save->CR50 = VGAIN8(vgaCRReg);
2315    VGAOUT8(vgaCRIndex, 0x51);
2316    save->CR51 = VGAIN8(vgaCRReg);
2317    VGAOUT8(vgaCRIndex, 0x53);
2318    save->CR53 = VGAIN8(vgaCRReg);
2319    VGAOUT8(vgaCRIndex, 0x58);
2320    save->CR58 = VGAIN8(vgaCRReg);
2321    VGAOUT8(vgaCRIndex, 0x60);
2322    save->CR60 = VGAIN8(vgaCRReg);
2323    VGAOUT8(vgaCRIndex, 0x66);
2324    save->CR66 = VGAIN8(vgaCRReg);
2325    VGAOUT8(vgaCRIndex, 0x67);
2326    save->CR67 = VGAIN8(vgaCRReg);
2327    VGAOUT8(vgaCRIndex, 0x68);
2328    save->CR68 = VGAIN8(vgaCRReg);
2329    VGAOUT8(vgaCRIndex, 0x69);
2330    save->CR69 = VGAIN8(vgaCRReg);
2331    VGAOUT8(vgaCRIndex, 0x6f);
2332    save->CR6F = VGAIN8(vgaCRReg);
2333
2334    VGAOUT8(vgaCRIndex, 0x33);
2335    save->CR33 = VGAIN8(vgaCRReg);
2336    VGAOUT8(vgaCRIndex, 0x86);
2337    save->CR86 = VGAIN8(vgaCRReg);
2338    VGAOUT8(vgaCRIndex, 0x88);
2339    save->CR88 = VGAIN8(vgaCRReg);
2340    VGAOUT8(vgaCRIndex, 0x90);
2341    save->CR90 = VGAIN8(vgaCRReg);
2342    VGAOUT8(vgaCRIndex, 0x91);
2343    save->CR91 = VGAIN8(vgaCRReg);
2344    VGAOUT8(vgaCRIndex, 0xb0);
2345    save->CRB0 = VGAIN8(vgaCRReg) | 0x80;
2346
2347    /* extended mode timing regs */
2348    VGAOUT8(vgaCRIndex, 0x3b);
2349    save->CR3B = VGAIN8(vgaCRReg);
2350    VGAOUT8(vgaCRIndex, 0x3c);
2351    save->CR3C = VGAIN8(vgaCRReg);
2352    VGAOUT8(vgaCRIndex, 0x43);
2353    save->CR43 = VGAIN8(vgaCRReg);
2354    VGAOUT8(vgaCRIndex, 0x5d);
2355    save->CR5D = VGAIN8(vgaCRReg);
2356    VGAOUT8(vgaCRIndex, 0x5e);
2357    save->CR5E = VGAIN8(vgaCRReg);
2358    VGAOUT8(vgaCRIndex, 0x65);
2359    save->CR65 = VGAIN8(vgaCRReg);
2360
2361    /* save seq extended regs for DCLK PLL programming */
2362    VGAOUT8(0x3c4, 0x0e);
2363    save->SR0E = VGAIN8(0x3c5);
2364    VGAOUT8(0x3c4, 0x0f);
2365    save->SR0F = VGAIN8(0x3c5);
2366    VGAOUT8(0x3c4, 0x10);
2367    save->SR10 = VGAIN8(0x3c5);
2368    VGAOUT8(0x3c4, 0x11);
2369    save->SR11 = VGAIN8(0x3c5);
2370    VGAOUT8(0x3c4, 0x12);
2371    save->SR12 = VGAIN8(0x3c5);
2372    VGAOUT8(0x3c4, 0x13);
2373    save->SR13 = VGAIN8(0x3c5);
2374    VGAOUT8(0x3c4, 0x29);
2375    save->SR29 = VGAIN8(0x3c5);
2376
2377    VGAOUT8(0x3c4, 0x15);
2378    save->SR15 = VGAIN8(0x3c5);
2379    VGAOUT8(0x3c4, 0x30);
2380    save->SR30 = VGAIN8(0x3c5);
2381    VGAOUT8(0x3c4, 0x18);
2382    save->SR18 = VGAIN8(0x3c5);
2383    VGAOUT8(0x3c4, 0x1b);
2384    save->SR1B = VGAIN8(0x3c5);
2385
2386    /* Save flat panel expansion registers. */
2387
2388    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2389	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2390	int i;
2391	for( i = 0; i < 8; i++ ) {
2392	    VGAOUT8(0x3c4, 0x54+i);
2393	    save->SR54[i] = VGAIN8(0x3c5);
2394	}
2395    }
2396
2397    VGAOUT8(vgaCRIndex, 0x66);
2398    cr66 = VGAIN8(vgaCRReg);
2399    VGAOUT8(vgaCRReg, cr66 | 0x80);
2400    VGAOUT8(vgaCRIndex, 0x3a);
2401    cr3a = VGAIN8(vgaCRReg);
2402    VGAOUT8(vgaCRReg, cr3a | 0x80);
2403
2404    /* now save MIU regs */
2405    if( ! S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
2406	save->MMPR0 = INREG(FIFO_CONTROL_REG);
2407	save->MMPR1 = INREG(MIU_CONTROL_REG);
2408	save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
2409	save->MMPR3 = INREG(MISC_TIMEOUT_REG);
2410    }
2411
2412    VGAOUT8(vgaCRIndex, 0x3a);
2413    VGAOUT8(vgaCRReg, cr3a);
2414    VGAOUT8(vgaCRIndex, 0x66);
2415    VGAOUT8(vgaCRReg, cr66);
2416
2417    if (!psav->ModeStructInit) {
2418	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
2419	memcpy(&psav->ModeReg, save, sizeof(SavageRegRec));
2420	psav->ModeStructInit = TRUE;
2421    }
2422
2423#if 0
2424    if (xf86GetVerbosity() > 1)
2425	SavagePrintRegs(pScrn);
2426#endif
2427
2428    return;
2429}
2430
2431
2432static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
2433			    SavageRegPtr restore, Bool Entering)
2434{
2435    unsigned char tmp, cr3a, cr66;
2436    vgaHWPtr hwp = VGAHWPTR(pScrn);
2437    SavagePtr psav = SAVPTR(pScrn);
2438    int vgaCRIndex, vgaCRReg, vgaIOBase;
2439
2440
2441    vgaIOBase = hwp->IOBase;
2442    vgaCRIndex = vgaIOBase + 4;
2443    vgaCRReg = vgaIOBase + 5;
2444
2445    TRACE(("SavageWriteMode(%x)\n", restore->mode));
2446
2447#ifdef XF86DRI
2448    if (psav->directRenderingEnabled) {
2449        DRILock(screenInfo.screens[pScrn->scrnIndex], 0);
2450        psav->LockHeld = 1;
2451    }
2452#endif
2453
2454    if (psav->IsSecondary) {
2455	/* Set up the mode.  Don't clear video RAM. */
2456	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2457	SavageSetGBD(pScrn);
2458	return;
2459    }
2460
2461    if( Entering &&
2462	(!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
2463    )
2464	SavageInitialize2DEngine(pScrn);
2465
2466    /*
2467     * If we figured out a VESA mode number for this timing, just use
2468     * the S3 BIOS to do the switching, with a few additional tweaks.
2469     */
2470
2471    if( psav->UseBIOS && restore->mode > 0x13 )
2472    {
2473	int width;
2474	unsigned short cr6d;
2475	unsigned short cr79 = 0;
2476
2477	/* Set up the mode.  Don't clear video RAM. */
2478	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2479
2480	/* Restore the DAC. */
2481	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
2482
2483	/* Unlock the extended registers. */
2484
2485#if 0
2486	/* Which way is better? */
2487	hwp->writeCrtc( hwp, 0x38, 0x48 );
2488	hwp->writeCrtc( hwp, 0x39, 0xa0 );
2489	hwp->writeSeq( hwp, 0x08, 0x06 );
2490#endif
2491
2492	VGAOUT16(vgaCRIndex, 0x4838);
2493	VGAOUT16(vgaCRIndex, 0xA039);
2494	VGAOUT16(0x3c4, 0x0608);
2495
2496	/* Enable linear addressing. */
2497
2498	VGAOUT16(vgaCRIndex, 0x1358);
2499
2500	/* Disable old MMIO. */
2501
2502	VGAOUT8(vgaCRIndex, 0x53);
2503	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & ~0x10);
2504
2505	/* Disable HW cursor */
2506
2507	VGAOUT16(vgaCRIndex, 0x0045);
2508
2509	/* Set the color mode. */
2510
2511	VGAOUT8(vgaCRIndex, 0x67);
2512	VGAOUT8(vgaCRReg, restore->CR67);
2513
2514	/* Enable gamma correction, set CLUT to 8 bit */
2515
2516	VGAOUT8(0x3c4, 0x1b);
2517	if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive
2518	    && ! psav->FBStart2nd )
2519		VGAOUT8(0x3c5, 0x18 );
2520	else
2521		VGAOUT8(0x3c5, 0x10 );
2522
2523	/* We may need TV/panel fixups here.  See s3bios.c line 2904. */
2524
2525	/* Set FIFO fetch delay. */
2526	VGAOUT8(vgaCRIndex, 0x85);
2527	VGAOUT8(vgaCRReg, (VGAIN8(vgaCRReg) & 0xf8) | 0x03);
2528
2529	/* Patch CR79.  These values are magical. */
2530
2531	if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2532	{
2533	    VGAOUT8(vgaCRIndex, 0x6d);
2534	    cr6d = VGAIN8(vgaCRReg);
2535
2536	    cr79 = 0x04;
2537
2538	    if( pScrn->displayWidth >= 1024 )
2539	    {
2540		if(psav->primStreamBpp == 32 )
2541		{
2542		    if( restore->refresh >= 130 )
2543			cr79 = 0x03;
2544		    else if( pScrn->displayWidth >= 1280 )
2545			cr79 = 0x02;
2546		    else if(
2547			(pScrn->displayWidth == 1024) &&
2548			(restore->refresh >= 75)
2549		    )
2550		    {
2551			if( cr6d && LCD_ACTIVE )
2552			    cr79 = 0x05;
2553			else
2554			    cr79 = 0x08;
2555		    }
2556		}
2557		else if( psav->primStreamBpp == 16)
2558		{
2559
2560/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
2561 * screen artifacts with that value.  Let's keep it low for now.
2562 *		if( restore->refresh >= 130 )
2563 *		    cr79 = 0x13;
2564 *		else
2565 */
2566		    if( pScrn->displayWidth == 1024 )
2567		    {
2568			if( cr6d && LCD_ACTIVE )
2569			    cr79 = 0x08;
2570			else
2571			    cr79 = 0x0e;
2572		    }
2573		}
2574	    }
2575	}
2576
2577        if( (psav->Chipset != S3_SAVAGE2000) &&
2578	    !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2579	    VGAOUT16(vgaCRIndex, (cr79 << 8) | 0x79);
2580
2581	/* Make sure 16-bit memory access is enabled. */
2582
2583	VGAOUT16(vgaCRIndex, 0x0c31);
2584
2585	/* Enable the graphics engine. */
2586
2587	VGAOUT16(vgaCRIndex, 0x0140);
2588
2589	/* Handle the pitch. */
2590
2591        VGAOUT8(vgaCRIndex, 0x50);
2592        VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2593
2594	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
2595	VGAOUT16(vgaCRIndex, ((width & 0xff) << 8) | 0x13 );
2596	VGAOUT16(vgaCRIndex, ((width & 0x300) << 4) | 0x51 );
2597
2598	/* Some non-S3 BIOSes enable block write even on non-SGRAM devices. */
2599
2600	switch( psav->Chipset )
2601	{
2602	    case S3_SAVAGE2000:
2603		VGAOUT8(vgaCRIndex, 0x73);
2604		VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & 0xdf );
2605		break;
2606
2607	    case S3_SAVAGE3D:
2608	    case S3_SAVAGE4:
2609		VGAOUT8(vgaCRIndex, 0x68);
2610		if( !(VGAIN8(vgaCRReg) & 0x80) )
2611		{
2612		    /* Not SGRAM; disable block write. */
2613		    VGAOUT8(vgaCRIndex, 0x88);
2614		    VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0x10);
2615		}
2616		break;
2617	}
2618
2619	/* set the correct clock for some BIOSes */
2620	VGAOUT8(VGA_MISC_OUT_W,
2621		VGAIN8(VGA_MISC_OUT_R) | 0x0C);
2622	/* Some BIOSes turn on clock doubling on non-doubled modes */
2623	if (pScrn->bitsPerPixel < 24) {
2624	    VGAOUT8(vgaCRIndex, 0x67);
2625	    if (!(VGAIN8(vgaCRReg) & 0x10)) {
2626		VGAOUT8(0x3c4, 0x15);
2627		VGAOUT8(0x3c5, VGAIN8(0x3C5) & ~0x10);
2628		VGAOUT8(0x3c4, 0x18);
2629		VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x80);
2630	    }
2631	}
2632
2633	SavageInitialize2DEngine(pScrn);
2634
2635	VGAOUT16(vgaCRIndex, 0x0140);
2636
2637	SavageSetGBD(pScrn);
2638
2639
2640#ifdef XF86DRI
2641    	if (psav->directRenderingEnabled)
2642    	    DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
2643    	psav->LockHeld = 0;
2644#endif
2645
2646	return;
2647    }
2648
2649    VGAOUT8(0x3c2, 0x23);
2650    VGAOUT16(vgaCRIndex, 0x4838);
2651    VGAOUT16(vgaCRIndex, 0xa039);
2652    VGAOUT16(0x3c4, 0x0608);
2653
2654    vgaHWProtect(pScrn, TRUE);
2655
2656    /* will we be reenabling STREAMS for the new mode? */
2657    psav->STREAMSRunning = 0;
2658
2659    /* reset GE to make sure nothing is going on */
2660    VGAOUT8(vgaCRIndex, 0x66);
2661    if(VGAIN8(vgaCRReg) & 0x01)
2662	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2663
2664    /*
2665     * Some Savage/MX and /IX systems go nuts when trying to exit the
2666     * server after WindowMaker has displayed a gradient background.  I
2667     * haven't been able to find what causes it, but a non-destructive
2668     * switch to mode 3 here seems to eliminate the issue.
2669     */
2670
2671    if( ((restore->CR31 & 0x0a) == 0) && psav->pVbe ) {
2672	SavageSetTextMode( psav );
2673    }
2674
2675    VGAOUT8(vgaCRIndex, 0x67);
2676    (void) VGAIN8(vgaCRReg);
2677    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2678    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no STREAMS yet old and new */
2679
2680    /* restore extended regs */
2681    VGAOUT8(vgaCRIndex, 0x66);
2682    VGAOUT8(vgaCRReg, restore->CR66);
2683    VGAOUT8(vgaCRIndex, 0x3a);
2684    VGAOUT8(vgaCRReg, restore->CR3A);
2685    VGAOUT8(vgaCRIndex, 0x31);
2686    VGAOUT8(vgaCRReg, restore->CR31);
2687    VGAOUT8(vgaCRIndex, 0x32);
2688    VGAOUT8(vgaCRReg, restore->CR32);
2689    VGAOUT8(vgaCRIndex, 0x58);
2690    VGAOUT8(vgaCRReg, restore->CR58);
2691    VGAOUT8(vgaCRIndex, 0x53);
2692    VGAOUT8(vgaCRReg, restore->CR53 & 0x7f);
2693
2694    VGAOUT16(0x3c4, 0x0608);
2695
2696    /* Restore DCLK registers. */
2697
2698    VGAOUT8(0x3c4, 0x0e);
2699    VGAOUT8(0x3c5, restore->SR0E);
2700    VGAOUT8(0x3c4, 0x0f);
2701    VGAOUT8(0x3c5, restore->SR0F);
2702    VGAOUT8(0x3c4, 0x29);
2703    VGAOUT8(0x3c5, restore->SR29);
2704    VGAOUT8(0x3c4, 0x15);
2705    VGAOUT8(0x3c5, restore->SR15);
2706
2707    /* Restore flat panel expansion registers. */
2708    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2709	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2710	int i;
2711	for( i = 0; i < 8; i++ ) {
2712	    VGAOUT8(0x3c4, 0x54+i);
2713	    VGAOUT8(0x3c5, restore->SR54[i]);
2714	}
2715    }
2716
2717    /* restore the standard vga regs */
2718    if (xf86IsPrimaryPci(psav->PciInfo))
2719	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
2720    else
2721	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
2722
2723    /* extended mode timing registers */
2724    VGAOUT8(vgaCRIndex, 0x53);
2725    VGAOUT8(vgaCRReg, restore->CR53);
2726    VGAOUT8(vgaCRIndex, 0x5d);
2727    VGAOUT8(vgaCRReg, restore->CR5D);
2728    VGAOUT8(vgaCRIndex, 0x5e);
2729    VGAOUT8(vgaCRReg, restore->CR5E);
2730    VGAOUT8(vgaCRIndex, 0x3b);
2731    VGAOUT8(vgaCRReg, restore->CR3B);
2732    VGAOUT8(vgaCRIndex, 0x3c);
2733    VGAOUT8(vgaCRReg, restore->CR3C);
2734    VGAOUT8(vgaCRIndex, 0x43);
2735    VGAOUT8(vgaCRReg, restore->CR43);
2736    VGAOUT8(vgaCRIndex, 0x65);
2737    VGAOUT8(vgaCRReg, restore->CR65);
2738
2739    /* restore the desired video mode with cr67 */
2740    VGAOUT8(vgaCRIndex, 0x67);
2741    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2742    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no streams for new and old streams engines */
2743
2744    /* other mode timing and extended regs */
2745    VGAOUT8(vgaCRIndex, 0x34);
2746    VGAOUT8(vgaCRReg, restore->CR34);
2747    VGAOUT8(vgaCRIndex, 0x40);
2748    VGAOUT8(vgaCRReg, restore->CR40);
2749    VGAOUT8(vgaCRIndex, 0x42);
2750    VGAOUT8(vgaCRReg, restore->CR42);
2751    VGAOUT8(vgaCRIndex, 0x45);
2752    VGAOUT8(vgaCRReg, restore->CR45);
2753    VGAOUT8(vgaCRIndex, 0x50);
2754    VGAOUT8(vgaCRReg, restore->CR50);
2755    VGAOUT8(vgaCRIndex, 0x51);
2756    VGAOUT8(vgaCRReg, restore->CR51);
2757
2758    /* memory timings */
2759    VGAOUT8(vgaCRIndex, 0x36);
2760    VGAOUT8(vgaCRReg, restore->CR36);
2761    VGAOUT8(vgaCRIndex, 0x60);
2762    VGAOUT8(vgaCRReg, restore->CR60);
2763    VGAOUT8(vgaCRIndex, 0x68);
2764    VGAOUT8(vgaCRReg, restore->CR68);
2765    VerticalRetraceWait();
2766    VGAOUT8(vgaCRIndex, 0x69);
2767    VGAOUT8(vgaCRReg, restore->CR69);
2768    VGAOUT8(vgaCRIndex, 0x6f);
2769    VGAOUT8(vgaCRReg, restore->CR6F);
2770
2771    VGAOUT8(vgaCRIndex, 0x33);
2772    VGAOUT8(vgaCRReg, restore->CR33);
2773    VGAOUT8(vgaCRIndex, 0x86);
2774    VGAOUT8(vgaCRReg, restore->CR86);
2775    VGAOUT8(vgaCRIndex, 0x88);
2776    VGAOUT8(vgaCRReg, restore->CR88);
2777    VGAOUT8(vgaCRIndex, 0x90);
2778    VGAOUT8(vgaCRReg, restore->CR90);
2779    VGAOUT8(vgaCRIndex, 0x91);
2780    VGAOUT8(vgaCRReg, restore->CR91);
2781    if( psav->Chipset == S3_SAVAGE4 )
2782    {
2783	VGAOUT8(vgaCRIndex, 0xb0);
2784	VGAOUT8(vgaCRReg, restore->CRB0);
2785    }
2786
2787    VGAOUT8(vgaCRIndex, 0x32);
2788    VGAOUT8(vgaCRReg, restore->CR32);
2789
2790    /* unlock extended seq regs */
2791    VGAOUT8(0x3c4, 0x08);
2792    VGAOUT8(0x3c5, 0x06);
2793
2794    /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
2795     * we should leave the default SR10 and SR11 values there.
2796     */
2797    if (restore->SR10 != 255) {
2798	VGAOUT8(0x3c4, 0x10);
2799	VGAOUT8(0x3c5, restore->SR10);
2800	VGAOUT8(0x3c4, 0x11);
2801	VGAOUT8(0x3c5, restore->SR11);
2802    }
2803
2804    /* restore extended seq regs for dclk */
2805    VGAOUT8(0x3c4, 0x0e);
2806    VGAOUT8(0x3c5, restore->SR0E);
2807    VGAOUT8(0x3c4, 0x0f);
2808    VGAOUT8(0x3c5, restore->SR0F);
2809    VGAOUT8(0x3c4, 0x12);
2810    VGAOUT8(0x3c5, restore->SR12);
2811    VGAOUT8(0x3c4, 0x13);
2812    VGAOUT8(0x3c5, restore->SR13);
2813    VGAOUT8(0x3c4, 0x29);
2814    VGAOUT8(0x3c5, restore->SR29);
2815
2816    VGAOUT8(0x3c4, 0x18);
2817    VGAOUT8(0x3c5, restore->SR18);
2818    VGAOUT8(0x3c4, 0x1b);
2819    if( psav->DGAactive )
2820	VGAOUT8(0x3c5, restore->SR1B & ~0x08 );
2821    else
2822	VGAOUT8(0x3c5, restore->SR1B);
2823
2824    /* load new m, n pll values for dclk & mclk */
2825    VGAOUT8(0x3c4, 0x15);
2826    tmp = VGAIN8(0x3c5) & ~0x21;
2827
2828    VGAOUT8(0x3c5, tmp | 0x03);
2829    VGAOUT8(0x3c5, tmp | 0x23);
2830    VGAOUT8(0x3c5, tmp | 0x03);
2831    VGAOUT8(0x3c5, restore->SR15);
2832    usleep( 100 );
2833
2834    VGAOUT8(0x3c4, 0x30);
2835    VGAOUT8(0x3c5, restore->SR30);
2836    VGAOUT8(0x3c4, 0x08);
2837    VGAOUT8(0x3c5, restore->SR08);
2838
2839    /* now write out cr67 in full, possibly starting STREAMS */
2840    VerticalRetraceWait();
2841    VGAOUT8(vgaCRIndex, 0x67);
2842#if 0
2843    VGAOUT8(vgaCRReg, 0x50);
2844    usleep(10000);
2845    VGAOUT8(vgaCRIndex, 0x67);
2846#endif
2847    VGAOUT8(vgaCRReg, restore->CR67);
2848
2849    VGAOUT8(vgaCRIndex, 0x66);
2850    cr66 = VGAIN8(vgaCRReg);
2851    VGAOUT8(vgaCRReg, cr66 | 0x80);
2852    VGAOUT8(vgaCRIndex, 0x3a);
2853    cr3a = VGAIN8(vgaCRReg);
2854    VGAOUT8(vgaCRReg, cr3a | 0x80);
2855
2856    if (Entering)
2857	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2858
2859    if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2860    {
2861	VerticalRetraceWait();
2862	OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
2863	OUTREG(MIU_CONTROL_REG, restore->MMPR1);
2864	OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
2865	OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
2866    }
2867
2868    /* If we're going into graphics mode and acceleration was enabled, */
2869    /* go set up the BCI buffer and the global bitmap descriptor. */
2870
2871#if 0
2872    if( Entering && (!psav->NoAccel) )
2873    {
2874	VGAOUT8(vgaCRIndex, 0x50);
2875	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2876	SavageInitialize2DEngine(pScrn);
2877    }
2878#endif
2879
2880    VGAOUT8(vgaCRIndex, 0x66);
2881    VGAOUT8(vgaCRReg, cr66);
2882    VGAOUT8(vgaCRIndex, 0x3a);
2883    VGAOUT8(vgaCRReg, cr3a);
2884
2885    if( Entering ) {
2886	SavageInitialize2DEngine(pScrn);
2887
2888	VGAOUT16(vgaCRIndex, 0x0140);
2889
2890	SavageSetGBD(pScrn);
2891    }
2892
2893    vgaHWProtect(pScrn, FALSE);
2894
2895
2896#ifdef XF86DRI
2897    if (psav->directRenderingEnabled)
2898        DRIUnlock(screenInfo.screens[pScrn->scrnIndex]);
2899    psav->LockHeld = 0;
2900#endif
2901
2902    return;
2903}
2904
2905
2906static Bool SavageMapMem(ScrnInfoPtr pScrn)
2907{
2908    SavagePtr psav = SAVPTR(pScrn);
2909    int mode;
2910    unsigned i;
2911
2912    TRACE(("SavageMapMem()\n"));
2913
2914    if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
2915	psav->MmioRegion.bar = 0;
2916	psav->MmioRegion.offset = SAVAGE_NEWMMIO_REGBASE_S3;
2917
2918	psav->FbRegion.bar = 0;
2919	psav->FbRegion.offset = 0;
2920
2921	psav->last_bar = 0;
2922    } else {
2923	psav->MmioRegion.bar = 0;
2924	psav->MmioRegion.offset = SAVAGE_NEWMMIO_REGBASE_S4;
2925
2926	psav->FbRegion.bar = 1;
2927	psav->FbRegion.offset = 0;
2928
2929	psav->last_bar = 1;
2930    }
2931
2932    /* On Paramount and Savage 2000, aperture 0 is PCI base 2.  On other
2933     * chipsets it's in the same BAR as the framebuffer.
2934     */
2935    if ((psav->Chipset == S3_SUPERSAVAGE)
2936	|| (psav->Chipset == S3_SAVAGE2000)) {
2937	psav->ApertureRegion.bar = 2;
2938	psav->ApertureRegion.offset = 0;
2939
2940	psav->last_bar = 2;
2941    } else {
2942	psav->ApertureRegion.bar = psav->FbRegion.bar;
2943	psav->ApertureRegion.offset = 0x02000000;
2944    }
2945
2946
2947    psav->MmioBase = psav->PciInfo->memBase[ psav->MmioRegion.bar ]
2948      + psav->MmioRegion.offset;
2949
2950    psav->FrameBufferBase = psav->PciInfo->memBase[ psav->FbRegion.bar ]
2951      + psav->FbRegion.offset;
2952
2953    psav->ApertureBase = psav->PciInfo->memBase[ psav->FbRegion.bar ]
2954      + psav->ApertureRegion.offset;
2955
2956
2957    /* FIXME: This seems fine even on Savage3D where the same BAR contains the
2958     * FIXME: MMIO space and the framebuffer.  Write-combining gets fixed up
2959     * FIXME: later.  Someone should investigate this, though.  And kick S3
2960     * FIXME: for doing something so silly.
2961     */
2962    mode = VIDMEM_MMIO;
2963    for (i = 0; i <= psav->last_bar; i++) {
2964	psav->bar_mappings[i] = xf86MapPciMem(pScrn->scrnIndex, mode,
2965					      psav->PciTag,
2966					      psav->PciInfo->memBase[i],
2967					      (1U << psav->PciInfo->size[i]));
2968	if (!psav->bar_mappings[i]) {
2969	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2970		       "Internal error: cound not map PCI region %u, last BAR = %u\n",
2971		       i, psav->last_bar);
2972	    return FALSE;
2973	}
2974
2975	mode = VIDMEM_FRAMEBUFFER;
2976    }
2977
2978    psav->MapBase = psav->bar_mappings[ psav->MmioRegion.bar ]
2979      + psav->MmioRegion.offset;
2980
2981    psav->BciMem = psav->MapBase + 0x10000;
2982
2983    SavageEnableMMIO(pScrn);
2984
2985    psav->FBBase = psav->bar_mappings[ psav->FbRegion.bar ]
2986      + psav->FbRegion.offset;
2987
2988    psav->FBStart = (psav->IsSecondary)
2989      ? psav->FBBase + 0x1000000 : psav->FBBase;
2990
2991    psav->ApertureMap = psav->bar_mappings[ psav->ApertureRegion.bar ]
2992      + psav->ApertureRegion.offset;
2993
2994    if (psav->IsSecondary) {
2995	psav->ApertureMap += 0x1000000;
2996    }
2997
2998    pScrn->memPhysBase = psav->PciInfo->memBase[0];
2999
3000    return TRUE;
3001}
3002
3003
3004static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
3005{
3006    SavagePtr psav = SAVPTR(pScrn);
3007    unsigned i;
3008
3009    TRACE(("SavageUnmapMem(%x,%x)\n", psav->MapBase, psav->FBBase));
3010
3011    if (psav->PrimaryVidMapped) {
3012	vgaHWUnmapMem(pScrn);
3013	psav->PrimaryVidMapped = FALSE;
3014    }
3015
3016    SavageDisableMMIO(pScrn);
3017
3018    for (i = (All) ? 0 : 1; i <= psav->last_bar; i++) {
3019	if (psav->bar_mappings[i]) {
3020	    xf86UnMapVidMem(pScrn->scrnIndex, psav->bar_mappings[i],
3021			    (1U << psav->PciInfo->size[i]));
3022	    psav->bar_mappings[i] = NULL;
3023	}
3024    }
3025
3026    if (All) {
3027	psav->MapBase = 0;
3028	psav->BciMem = 0;
3029    }
3030
3031    psav->FBBase = 0;
3032    psav->FBStart = 0;
3033    psav->ApertureMap = 0;
3034
3035    return;
3036}
3037
3038#ifdef XF86DRI
3039static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn)
3040{
3041    SavagePtr psav = SAVPTR(pScrn);
3042    int cpp = pScrn->bitsPerPixel / 8;
3043    int tiledBufferSize, RamNeededFor3D;
3044
3045    if (cpp == 2) {
3046        tiledBufferSize = ((pScrn->virtualX+63)/64)*((pScrn->virtualY+15)/16) * 2048;
3047    } else {
3048        tiledBufferSize = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16) * 2048;
3049    }
3050
3051    RamNeededFor3D = 4096 + /* hw cursor*/
3052                     psav->cobSize + /*COB*/
3053                     tiledBufferSize + /* front buffer */
3054                     tiledBufferSize + /* back buffer */
3055                     tiledBufferSize; /* depth buffer */
3056
3057    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
3058		"%d kB of Videoram needed for 3D; %d kB of Videoram available\n",
3059		RamNeededFor3D/1024, psav->videoRambytes/1024);
3060
3061    if (RamNeededFor3D <= psav->videoRambytes) {
3062        xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Sufficient Videoram available for 3D\n");
3063	return TRUE;
3064    } else {
3065        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D -- "
3066					"Try a lower color depth or smaller desktop.  "
3067			"For integrated savages try increasing the videoram in the BIOS.\n");
3068	return FALSE;
3069    }
3070}
3071#endif
3072
3073static void SavageInitStatus(ScrnInfoPtr pScrn)
3074{
3075    SavagePtr psav = SAVPTR(pScrn);
3076
3077    switch( psav->Chipset ) {
3078	case S3_SAVAGE3D:
3079	case S3_SAVAGE_MX:
3080	    psav->WaitQueue	= WaitQueue3D;
3081	    psav->WaitIdle	= WaitIdle3D;
3082	    psav->WaitIdleEmpty	= WaitIdleEmpty3D;
3083	    psav->bciUsedMask   = 0x1ffff;
3084	    psav->eventStatusReg= 1;
3085	    break;
3086
3087	case S3_SAVAGE4:
3088	case S3_PROSAVAGE:
3089	case S3_SUPERSAVAGE:
3090	case S3_PROSAVAGEDDR:
3091	case S3_TWISTER:
3092	    psav->WaitQueue	= WaitQueue4;
3093	    psav->WaitIdle	= WaitIdle4;
3094	    psav->WaitIdleEmpty	= WaitIdleEmpty4;
3095	    psav->bciUsedMask   = 0x1fffff;
3096	    psav->eventStatusReg= 1;
3097	    break;
3098
3099	case S3_SAVAGE2000:
3100	    psav->WaitQueue	= WaitQueue2K;
3101	    psav->WaitIdle	= WaitIdle2K;
3102	    psav->WaitIdleEmpty	= WaitIdleEmpty2K;
3103	    psav->bciUsedMask   = 0xfffff;
3104	    psav->eventStatusReg= 2;
3105	    break;
3106    }
3107}
3108
3109static void SavageInitShadowStatus(ScrnInfoPtr pScrn)
3110{
3111    SavagePtr psav = SAVPTR(pScrn);
3112
3113    psav->ShadowStatus = psav->ConfigShadowStatus;
3114
3115    SavageInitStatus(pScrn);
3116
3117    if( psav->ShadowStatus ) {
3118	psav->ShadowPhysical =
3119	    psav->FrameBufferBase + psav->CursorKByte*1024 + 4096 - 32;
3120
3121	psav->ShadowVirtual = (CARD32 *)
3122	    (psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
3123
3124	xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
3125		    "Shadow area physical %08lx, linear %p\n",
3126		    psav->ShadowPhysical, (void *)psav->ShadowVirtual );
3127
3128	psav->WaitQueue = ShadowWaitQueue;
3129	psav->WaitIdle = ShadowWait;
3130	psav->WaitIdleEmpty = ShadowWait;
3131    }
3132
3133    if( psav->Chipset == S3_SAVAGE2000 )
3134	psav->dwBCIWait2DIdle = 0xc0040000;
3135    else
3136	psav->dwBCIWait2DIdle = 0xc0020000;
3137}
3138
3139static Bool SavageScreenInit(int scrnIndex, ScreenPtr pScreen,
3140			     int argc, char **argv)
3141{
3142    ScrnInfoPtr pScrn;
3143    SavagePtr psav;
3144    EntityInfoPtr pEnt;
3145    int ret;
3146    int colormapFlags;
3147
3148    TRACE(("SavageScreenInit()\n"));
3149
3150    pScrn = xf86Screens[pScreen->myNum];
3151    psav = SAVPTR(pScrn);
3152
3153    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3154    if (!psav->pVbe)
3155	psav->pVbe = VBEInit(NULL, pEnt->index);
3156
3157    SavageEnableMMIO(pScrn);
3158
3159    if (!SavageMapMem(pScrn))
3160	return FALSE;
3161
3162    psav->FBStart2nd = 0;
3163
3164    if (psav->overlayDepth) {
3165	if ((pScrn->virtualX * pScrn->virtualY *
3166	     (DEPTH_BPP(DEPTH_2ND(pScrn))) >> 3)
3167	     > (psav->CursorKByte * 1024))
3168	    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,
3169		       "Not enough memory for overlay mode: disabling\n");
3170	else psav->FBStart2nd  = psav->FBStart
3171		 + ((pScrn->virtualX * pScrn->virtualY + 0xff) & ~0xff);
3172
3173    }
3174
3175    SavageInitShadowStatus(pScrn);
3176    psav->ShadowCounter = 0;
3177
3178    SavageSave(pScrn);
3179
3180    vgaHWBlankScreen(pScrn, TRUE);
3181
3182#ifdef XF86DRI
3183    if (!xf86ReturnOptValBool(psav->Options, OPTION_DRI, TRUE)) {
3184	psav->directRenderingEnabled = FALSE;
3185	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3186		   "Direct rendering forced off\n");
3187    } else if (psav->IsSecondary) {
3188	psav->directRenderingEnabled = FALSE;
3189    } else if (xf86IsEntityShared(psav->pEnt->index)) {
3190	    /* Xinerama has sync problem with DRI, disable it for now */
3191	    psav->directRenderingEnabled = FALSE;
3192	    xf86DrvMsg(scrnIndex, X_WARNING,
3193			"Direct Rendering Disabled -- "
3194			"Dual-head configuration is not working with "
3195			"DRI at present.\n");
3196    } else if (/*!psav->bTiled*/psav->bDisableTile) {
3197            xf86DrvMsg(scrnIndex, X_WARNING,
3198	    		"Direct Rendering requires a tiled framebuffer -- "
3199			"Set Option \"DisableTile\" \"false\"\n");
3200    } else if (psav->cobSize == 0) {
3201            xf86DrvMsg(scrnIndex, X_WARNING,
3202	    		"Direct Rendering requires the COB -- "
3203			"Set Option \"DisableCOB\" \"false\"\n");
3204    } else if (((psav->Chipset == S3_TWISTER)
3205        || (psav->Chipset == S3_PROSAVAGE)
3206        || (psav->Chipset == S3_SAVAGE4)
3207        || (psav->Chipset == S3_SAVAGE_MX)
3208	|| (psav->Chipset == S3_SAVAGE3D)
3209	|| (psav->Chipset == S3_SUPERSAVAGE)
3210        || (psav->Chipset == S3_PROSAVAGEDDR))
3211	&& (!psav->NoAccel)
3212	&& (SavageCheckAvailableRamFor3D(pScrn))) {
3213        /* Setup DRI after visuals have been established */
3214        psav->directRenderingEnabled = SAVAGEDRIScreenInit(pScreen);
3215	/* If DRI init failed, reset shadow status. */
3216	if (!psav->directRenderingEnabled &&
3217	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3218	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3219	    SavageInitShadowStatus(pScrn);
3220	}
3221	/* If shadow status was enabled for DRI, hook up the shadow
3222	 * waiting functions now. */
3223	else if (psav->ShadowStatus && !psav->ConfigShadowStatus) {
3224	    psav->WaitQueue = ShadowWaitQueue;
3225	    psav->WaitIdle = ShadowWait;
3226	    psav->WaitIdleEmpty = ShadowWait;
3227	}
3228    } else
3229        psav->directRenderingEnabled = FALSE;
3230
3231    if(psav->directRenderingEnabled) {
3232        xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"DRI is enabled\n");
3233    }
3234    else {
3235        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DRI isn't enabled\n");
3236    }
3237#endif
3238
3239    if (!SavageModeInit(pScrn, pScrn->currentMode))
3240	return FALSE;
3241
3242    miClearVisualTypes();
3243
3244    {
3245 	int visual;
3246
3247 	visual = ((psav->FBStart2nd && pScrn->bitsPerPixel > 8)
3248		   || pScrn->bitsPerPixel == 16) ? TrueColorMask
3249	    : miGetDefaultVisualMask(DEPTH_BPP(pScrn->depth));
3250 	if (!miSetVisualTypes(pScrn->depth, visual,
3251  			      pScrn->rgbBits, pScrn->defaultVisual))
3252  	    return FALSE;
3253
3254 	if (psav->FBStart2nd) {/* we have overlay */
3255 	    visual = psav->overlayDepth > 8 ? TrueColorMask :
3256 		miGetDefaultVisualMask(DEPTH_BPP(psav->overlayDepth));
3257 	    if (!miSetVisualTypes(psav->overlayDepth, visual,
3258 				  psav->overlayDepth > 8 ? 8 : 6,
3259 				  pScrn->defaultVisual))
3260 		return FALSE;
3261 	}
3262     }
3263     if (!miSetPixmapDepths ())
3264	 return FALSE;
3265
3266    ret = SavageInternalScreenInit(scrnIndex, pScreen);
3267    if (!ret)
3268	return FALSE;
3269
3270    xf86SetBlackWhitePixels(pScreen);
3271
3272    {
3273	VisualPtr visual;
3274	visual = pScreen->visuals + pScreen->numVisuals;
3275	while (--visual >= pScreen->visuals) {
3276	    if ((visual->class | DynamicClass) == DirectColor
3277		&& visual->nplanes > MAX_PSEUDO_DEPTH) {
3278		if (visual->nplanes == pScrn->depth) {
3279		    visual->offsetRed = pScrn->offset.red;
3280		    visual->offsetGreen = pScrn->offset.green;
3281		    visual->offsetBlue = pScrn->offset.blue;
3282		    visual->redMask = pScrn->mask.red;
3283		    visual->greenMask = pScrn->mask.green;
3284		    visual->blueMask = pScrn->mask.blue;
3285		} else if (visual->offsetRed > 8
3286			   || visual->offsetGreen > 8
3287			   || visual->offsetBlue > 8) {
3288	/*
3289	 * mi has set these wrong. fix it here -- we cannot use pScrn
3290	 * as this is set up for the default depth 8.
3291	 */
3292		    int tmp;
3293		    int c_s = 0;
3294
3295		    tmp = visual->offsetBlue;
3296		    visual->offsetBlue = visual->offsetRed;
3297		    visual->offsetRed = tmp;
3298		    tmp = visual->blueMask;
3299		    visual->blueMask = visual->redMask;
3300		    visual->redMask = tmp;
3301		    switch (DEPTH_2ND(pScrn)) {
3302			case 16:
3303			    visual->offsetRed = 11;
3304			    visual->offsetGreen = 5;
3305			    visual->offsetBlue = 0;
3306			    visual->redMask = 0xF800;
3307			    visual->greenMask = 0x7E0;
3308			    visual->blueMask = 0x1F;
3309			    break;
3310			case 24:
3311			    visual->offsetRed = 16;
3312			    visual->offsetGreen = 8;
3313			    visual->offsetBlue = 0;
3314			    visual->redMask = 0xFF0000;
3315			    visual->greenMask = 0xFF00;
3316			    visual->blueMask = 0xFF;
3317			    c_s = 2;
3318			    break;
3319		    }
3320		    psav->overlay.redMask = visual->redMask;
3321		    psav->overlay.greenMask = visual->greenMask;
3322		    psav->overlay.blueMask = visual->blueMask;
3323		    psav->overlay.redShift = visual->offsetRed + c_s;
3324		    psav->overlay.greenShift = visual->offsetGreen + c_s;
3325		    psav->overlay.blueShift = visual->offsetBlue + c_s;
3326		}
3327	    }
3328	}
3329    }
3330
3331    /* must be after RGB ordering fixed */
3332    fbPictureInit (pScreen, 0, 0);
3333
3334    if( !psav->NoAccel ) {
3335	SavageInitAccel(pScreen);
3336    }
3337
3338    miInitializeBackingStore(pScreen);
3339    xf86SetBackingStore(pScreen);
3340
3341    if( !psav->shadowFB && !psav->useEXA )
3342	SavageDGAInit(pScreen);
3343
3344    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
3345
3346    if (psav->hwcursor)
3347	if (!SavageHWCursorInit(pScreen))
3348	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3349	       "Hardware cursor initialization failed\n");
3350
3351    if (psav->shadowFB) {
3352	RefreshAreaFuncPtr refreshArea = SavageRefreshArea;
3353
3354	if(psav->rotate) {
3355	    if (!psav->PointerMoved) {
3356		psav->PointerMoved = pScrn->PointerMoved;
3357		pScrn->PointerMoved = SavagePointerMoved;
3358	    }
3359
3360	    switch(pScrn->bitsPerPixel) {
3361	    case 8:	refreshArea = SavageRefreshArea8;	break;
3362	    case 16:	refreshArea = SavageRefreshArea16;	break;
3363	    case 24:	refreshArea = SavageRefreshArea24;	break;
3364	    case 32:	refreshArea = SavageRefreshArea32;	break;
3365	    }
3366	}
3367
3368	ShadowFBInit(pScreen, refreshArea);
3369    }
3370
3371    if (!miCreateDefColormap(pScreen))
3372	    return FALSE;
3373
3374    colormapFlags =  CMAP_RELOAD_ON_MODE_SWITCH
3375	| ((psav->FBStart2nd) ? 0 : CMAP_PALETTED_TRUECOLOR);
3376
3377    if (psav->Chipset == S3_SAVAGE4) {
3378        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPaletteSavage4,
3379				 NULL, colormapFlags ))
3380	    return FALSE;
3381    } else {
3382        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPalette, NULL,
3383				 colormapFlags ))
3384 	    return FALSE;
3385    }
3386
3387    vgaHWBlankScreen(pScrn, FALSE);
3388
3389    psav->CloseScreen = pScreen->CloseScreen;
3390    pScreen->SaveScreen = SavageSaveScreen;
3391    pScreen->CloseScreen = SavageCloseScreen;
3392
3393    if (xf86DPMSInit(pScreen, SavageDPMS, 0) == FALSE)
3394	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed\n");
3395
3396#ifdef XF86DRI
3397    if (psav->directRenderingEnabled) {
3398        /* complete the DRI setup.*/
3399        psav->directRenderingEnabled = SAVAGEDRIFinishScreenInit(pScreen);
3400	/* If DRI initialization failed, reset shadow status and
3401	 * reinitialize 2D engine. */
3402	if (!psav->directRenderingEnabled &&
3403	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3404	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3405	    SavageInitShadowStatus(pScrn);
3406	    SavageInitialize2DEngine(pScrn);
3407	}
3408    }
3409    if (psav->directRenderingEnabled) {
3410        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
3411    } else {
3412        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
3413    }
3414#endif
3415
3416    SavagePanningCheck(pScrn);
3417#ifdef XvExtension
3418    if( !psav->FBStart2nd && !psav->NoAccel  /*&& !SavagePanningCheck(pScrn)*/ ) {
3419	if (psav->IsSecondary)
3420            /* Xv should work on crtc2, but I haven't gotten there yet.  -- AGD */
3421	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv currently disabled for crtc2.\n");
3422	else
3423	    SavageInitVideo( pScreen );
3424    }
3425#endif
3426
3427#ifdef XF86DRI
3428    if ((psav->directRenderingEnabled) && (!psav->bDisableXvMC)) {
3429        if (SAVAGEInitMC(pScreen))
3430            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is enabled\n");
3431        else
3432            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is not enabled\n");
3433    }
3434#endif
3435
3436    if (serverGeneration == 1)
3437	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
3438
3439    return TRUE;
3440}
3441
3442
3443static int SavageInternalScreenInit(int scrnIndex, ScreenPtr pScreen)
3444{
3445    int ret = TRUE;
3446    ScrnInfoPtr pScrn;
3447    SavagePtr psav;
3448    int width, height, displayWidth;
3449    unsigned char *FBStart;
3450
3451    TRACE(("SavageInternalScreenInit()\n"));
3452
3453    pScrn = xf86Screens[pScreen->myNum];
3454    psav = SAVPTR(pScrn);
3455
3456    displayWidth = pScrn->displayWidth;
3457
3458    if (psav->rotate) {
3459	height = pScrn->virtualX;
3460	width = pScrn->virtualY;
3461    } else {
3462	width = pScrn->virtualX;
3463	height = pScrn->virtualY;
3464    }
3465
3466
3467    if(psav->shadowFB) {
3468	psav->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
3469	psav->ShadowPtr = xalloc(psav->ShadowPitch * height);
3470	displayWidth = psav->ShadowPitch / (pScrn->bitsPerPixel >> 3);
3471	FBStart = psav->ShadowPtr;
3472    } else {
3473	psav->ShadowPtr = NULL;
3474	FBStart = psav->FBStart;
3475    }
3476
3477    if (!psav->FBStart2nd) {
3478
3479        ret = fbScreenInit(pScreen, FBStart, width, height,
3480                           pScrn->xDpi, pScrn->yDpi,
3481                           psav->ulAperturePitch / (pScrn->bitsPerPixel >> 3), /*displayWidth,*/
3482                           pScrn->bitsPerPixel);
3483
3484    } else {
3485	FbOverlayScrPrivPtr pScrPriv;
3486	int Depth2nd = DEPTH_2ND(pScrn);
3487	if (!fbSetupScreen (pScreen, FBStart, width, height,
3488			    pScrn->xDpi, pScrn->yDpi, displayWidth, 8))
3489	    return FALSE;
3490	if (pScrn->depth == 8) {
3491	    ret = fbOverlayFinishScreenInit (pScreen, FBStart,
3492					     psav->FBStart2nd, width,
3493					     height,pScrn->xDpi, pScrn->yDpi,
3494					     displayWidth,displayWidth,
3495					     8, DEPTH_BPP(Depth2nd),
3496					     8, Depth2nd);
3497	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3498	    pScrPriv->layer[0].key = pScrn->colorKey;
3499	} else {
3500	    ret = fbOverlayFinishScreenInit (pScreen, psav->FBStart2nd,
3501					     FBStart,
3502					     width, height,pScrn->xDpi,
3503					     pScrn->yDpi,
3504					     displayWidth,displayWidth,
3505					     DEPTH_BPP(Depth2nd), 8,
3506					     Depth2nd, 8);
3507	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3508	    pScrPriv->layer[1].key = pScrn->colorKey;
3509	}
3510    }
3511    return ret;
3512}
3513
3514
3515static int SavageGetRefresh(DisplayModePtr mode)
3516{
3517    int refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
3518    if (mode->Flags & V_INTERLACE)
3519	refresh *= 2.0;
3520    if (mode->Flags & V_DBLSCAN)
3521	refresh /= 2.0;
3522    if (mode->VScan > 1)
3523	refresh /= mode->VScan;
3524    return refresh;
3525}
3526
3527
3528static ModeStatus SavageValidMode(int index, DisplayModePtr pMode,
3529				  Bool verbose, int flags)
3530{
3531    ScrnInfoPtr pScrn = xf86Screens[index];
3532    SavagePtr psav = SAVPTR(pScrn);
3533    int refresh;
3534
3535    TRACE(("SavageValidMode\n"));
3536
3537    /* We prohibit modes bigger than the LCD panel. */
3538    /* TODO We should do this only if the panel is active. */
3539
3540    if( psav->TvOn )
3541    {
3542	if( pMode->HDisplay > psav->TVSizeX )
3543	    return MODE_VIRTUAL_X;
3544
3545	if( pMode->VDisplay > psav->TVSizeY )
3546	    return MODE_VIRTUAL_Y;
3547
3548    }
3549
3550    if((psav->DisplayType == MT_LCD) &&
3551      ((pMode->HDisplay > psav->PanelX) ||
3552       (pMode->VDisplay > psav->PanelY)))
3553	    return MODE_PANEL;
3554
3555    if (psav->UseBIOS) {
3556	refresh = SavageGetRefresh(pMode);
3557        return (SavageMatchBiosMode(pScrn,pMode->HDisplay,
3558                                   pMode->VDisplay,
3559                                   refresh,NULL,NULL));
3560    }
3561
3562    return MODE_OK;
3563}
3564
3565static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
3566{
3567    vgaHWPtr hwp = VGAHWPTR(pScrn);
3568    SavagePtr psav = SAVPTR(pScrn);
3569    int width, dclk, i, j; /*, refresh; */
3570    unsigned int m, n, r;
3571    unsigned char tmp = 0;
3572    SavageRegPtr new = &psav->ModeReg;
3573    vgaRegPtr vganew = &hwp->ModeReg;
3574    int vgaCRIndex, vgaCRReg, vgaIOBase;
3575    int refresh;
3576    unsigned int newmode=0, newrefresh=0;
3577
3578    vgaIOBase = hwp->IOBase;
3579    vgaCRIndex = vgaIOBase + 4;
3580    vgaCRReg = vgaIOBase + 5;
3581
3582    TRACE(("SavageModeInit(%dx%d, %dHz)\n",
3583	mode->HDisplay, mode->VDisplay, mode->Clock));
3584
3585#if 0
3586    ErrorF("Clock = %d, HDisplay = %d, HSStart = %d\n",
3587	    mode->Clock, mode->HDisplay, mode->HSyncStart);
3588    ErrorF("HSEnd = %d, HSkew = %d\n",
3589	    mode->HSyncEnd, mode->HSkew);
3590    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3591	    mode->VDisplay, mode->VSyncStart, mode->VSyncEnd);
3592    ErrorF("VTotal = %d\n",
3593	    mode->VTotal);
3594    ErrorF("HDisplay = %d, HSStart = %d\n",
3595	    mode->CrtcHDisplay, mode->CrtcHSyncStart);
3596    ErrorF("HSEnd = %d, HSkey = %d\n",
3597	    mode->CrtcHSyncEnd, mode->CrtcHSkew);
3598    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3599	    mode->CrtcVDisplay, mode->CrtcVSyncStart, mode->CrtcVSyncEnd);
3600    ErrorF("VTotal = %d\n",
3601	    mode->CrtcVTotal);
3602#endif
3603
3604    if (psav->IsSecondary) {
3605	refresh = SavageGetRefresh(mode);
3606
3607        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3608                            &newmode,&newrefresh);
3609	new->mode = newmode;
3610	new->refresh = newrefresh;
3611
3612        /* do it! */
3613        SavageWriteMode(pScrn, vganew, new, TRUE);
3614
3615        if (psav->FBStart2nd) {
3616	    SavageStreamsOn(pScrn);
3617	    SavageInitSecondaryStream(pScrn);
3618        }
3619
3620        SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
3621	return TRUE;
3622    }
3623
3624
3625    if (pScrn->bitsPerPixel == 8)
3626	psav->HorizScaleFactor = 1;
3627    else if (pScrn->bitsPerPixel == 16)
3628	psav->HorizScaleFactor = 1;	/* I don't think we ever want 2 */
3629    else
3630	psav->HorizScaleFactor = 1;
3631
3632    if (psav->HorizScaleFactor == 2)
3633	if (!mode->CrtcHAdjusted) {
3634	    mode->CrtcHDisplay *= 2;
3635	    mode->CrtcHSyncStart *= 2;
3636	    mode->CrtcHSyncEnd *= 2;
3637	    mode->CrtcHBlankStart *= 2;
3638	    mode->CrtcHBlankEnd *= 2;
3639	    mode->CrtcHTotal *= 2;
3640	    mode->CrtcHSkew *= 2;
3641	    mode->CrtcHAdjusted = TRUE;
3642	}
3643
3644    if (!vgaHWInit(pScrn, mode))
3645	return FALSE;
3646
3647    new->mode = 0;
3648
3649    /* We need to set CR67 whether or not we use the BIOS. */
3650
3651    dclk = mode->Clock;
3652    new->CR67 = 0x00;
3653
3654    switch( pScrn->depth ) {
3655    case 8:
3656	if( (psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000) )
3657	    new->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
3658	else
3659	    new->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
3660	break;
3661    case 15:
3662	if(
3663	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3664	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3665	)
3666	    new->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
3667	else
3668	    new->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
3669	break;
3670    case 16:
3671	if(
3672	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3673	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3674	)
3675	    new->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
3676	else
3677	    new->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
3678	break;
3679    case 24:
3680	if (psav->primStreamBpp == 24 )
3681	    new->CR67 = 0x70;
3682	else
3683	    new->CR67 = 0xd0;
3684	break;
3685    }
3686
3687
3688    if( psav->UseBIOS ) {
3689	int refresh;
3690	unsigned int newmode=0, newrefresh=0;
3691
3692	refresh = SavageGetRefresh(mode);
3693
3694        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3695                            &newmode,&newrefresh);
3696	new->mode = newmode;
3697	new->refresh = newrefresh;
3698    }
3699
3700    if( !new->mode ) {
3701	/*
3702	 * Either BIOS use is disabled, or we failed to find a suitable
3703	 * match.  Fall back to traditional register-crunching.
3704	 */
3705
3706	VGAOUT8(vgaCRIndex, 0x3a);
3707	tmp = VGAIN8(vgaCRReg);
3708	if (psav->pci_burst)
3709	    new->CR3A = (tmp & 0x7f) | 0x15;
3710	else
3711	    new->CR3A = tmp | 0x95;
3712
3713	new->CR53 = 0x00;
3714	new->CR31 = 0x8c;
3715	new->CR66 = 0x89;
3716
3717	VGAOUT8(vgaCRIndex, 0x58);
3718	new->CR58 = VGAIN8(vgaCRReg) & 0x80;
3719	new->CR58 |= 0x13;
3720
3721#if 0
3722	VGAOUT8(vgaCRIndex, 0x55);
3723	new->CR55 = VGAIN8(vgaCRReg);
3724	if (psav->hwcursor)
3725		new->CR55 |= 0x10;
3726#endif
3727
3728	new->SR15 = 0x03 | 0x80;
3729	new->SR18 = 0x00;
3730
3731
3732	/* enable gamma correction */
3733	if( pScrn->depth == 24 )
3734	    new->SR1B = 0x18;
3735	else
3736	    new->SR1B = 0x00;
3737
3738	/* set 8-bit CLUT */
3739	new->SR1B |= 0x10;
3740
3741	new->CR43 = new->CR45 = new->CR65 = 0x00;
3742
3743	VGAOUT8(vgaCRIndex, 0x40);
3744	new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
3745
3746	new->MMPR0 = 0x010400;
3747	new->MMPR1 = 0x00;
3748	new->MMPR2 = 0x0808;
3749	new->MMPR3 = 0x08080810;
3750
3751	if (psav->fifo_aggressive || psav->fifo_moderate ||
3752	    psav->fifo_conservative) {
3753		new->MMPR1 = 0x0200;
3754		new->MMPR2 = 0x1808;
3755		new->MMPR3 = 0x08081810;
3756	}
3757
3758	if (psav->MCLK <= 0) {
3759		new->SR10 = 255;
3760		new->SR11 = 255;
3761	}
3762
3763	psav->NeedSTREAMS = FALSE;
3764
3765	SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000,
3766			&m, &n, &r);
3767	new->SR12 = (r << 6) | (n & 0x3f);
3768	new->SR13 = m & 0xff;
3769	new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
3770
3771	if (psav->fifo_moderate) {
3772	    if (psav->primStreamBpp < 24)
3773		new->MMPR0 -= 0x8000;
3774	    else
3775		new->MMPR0 -= 0x4000;
3776	} else if (psav->fifo_aggressive) {
3777	    if (psav->primStreamBpp < 24)
3778		new->MMPR0 -= 0xc000;
3779	    else
3780		new->MMPR0 -= 0x6000;
3781	}
3782
3783	if (mode->Flags & V_INTERLACE)
3784	    new->CR42 = 0x20;
3785	else
3786	    new->CR42 = 0x00;
3787
3788	new->CR34 = 0x10;
3789
3790	i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
3791	    ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
3792	    ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
3793	    ((mode->CrtcHSyncStart & 0x800) >> 7);
3794
3795	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
3796	    i |= 0x08;
3797	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
3798	    i |= 0x20;
3799	j = (vganew->CRTC[0] + ((i & 0x01) << 8) +
3800	     vganew->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
3801	if (j - (vganew->CRTC[4] + ((i & 0x10) << 4)) < 4) {
3802	    if (vganew->CRTC[4] + ((i & 0x10) << 4) + 4 <=
3803	        vganew->CRTC[0] + ((i & 0x01) << 8))
3804		j = vganew->CRTC[4] + ((i & 0x10) << 4) + 4;
3805	    else
3806		j = vganew->CRTC[0] + ((i & 0x01) << 8) + 1;
3807	}
3808
3809	new->CR3B = j & 0xff;
3810	i |= (j & 0x100) >> 2;
3811	new->CR3C = (vganew->CRTC[0] + ((i & 0x01) << 8))  / 2 ;
3812	new->CR5D = i;
3813	new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) |
3814		    (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
3815		    (((mode->CrtcVSyncStart) & 0x400) >> 8) |
3816		    (((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
3817	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
3818	new->CR91 = vganew->CRTC[19] = 0xff & width;
3819	new->CR51 = (0x300 & width) >> 4;
3820	new->CR90 = 0x80 | (width >> 8);
3821	vganew->MiscOutReg |= 0x0c;
3822
3823	/* Set frame buffer description. */
3824
3825	if (psav->primStreamBpp <= 8)
3826	    new->CR50 = 0;
3827	else if (psav->primStreamBpp <= 16)
3828	    new->CR50 = 0x10;
3829	else
3830	    new->CR50 = 0x30;
3831
3832	if (pScrn->displayWidth == 640)
3833	    new->CR50 |= 0x40;
3834	else if (pScrn->displayWidth == 800)
3835	    new->CR50 |= 0x80;
3836	else if (pScrn->displayWidth == 1024)
3837	    new->CR50 |= 0x00;
3838	else if (pScrn->displayWidth == 1152)
3839	    new->CR50 |= 0x01;
3840	else if (pScrn->displayWidth == 1280)
3841	    new->CR50 |= 0xc0;
3842	else if (pScrn->displayWidth == 1600)
3843	    new->CR50 |= 0x81;
3844	else
3845	    new->CR50 |= 0xc1;	/* Use GBD */
3846
3847	if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
3848	    new->CR33 = 0x00;
3849	else
3850	    new->CR33 = 0x08;
3851
3852	vganew->CRTC[0x17] = 0xeb;
3853
3854	new->CR67 |= 1;
3855
3856	VGAOUT8(vgaCRIndex, 0x36);
3857	new->CR36 = VGAIN8(vgaCRReg);
3858	VGAOUT8(vgaCRIndex, 0x68);
3859	new->CR68 = VGAIN8(vgaCRReg);
3860
3861	new->CR69 = 0;
3862	VGAOUT8(vgaCRIndex, 0x6f);
3863	new->CR6F = VGAIN8(vgaCRReg);
3864	VGAOUT8(vgaCRIndex, 0x86);
3865	new->CR86 = VGAIN8(vgaCRReg) | 0x08;
3866	VGAOUT8(vgaCRIndex, 0x88);
3867	new->CR88 = VGAIN8(vgaCRReg) | DISABLE_BLOCK_WRITE_2D;
3868	VGAOUT8(vgaCRIndex, 0xb0);
3869	new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
3870    }
3871
3872    pScrn->vtSema = TRUE;
3873
3874    /* do it! */
3875    SavageWriteMode(pScrn, vganew, new, TRUE);
3876
3877    if (psav->FBStart2nd) {
3878        SavageStreamsOn(pScrn);
3879	SavageInitSecondaryStream(pScrn);
3880    }
3881
3882    SavageAdjustFrame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
3883
3884    return TRUE;
3885}
3886
3887
3888static Bool SavageCloseScreen(int scrnIndex, ScreenPtr pScreen)
3889{
3890    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
3891    vgaHWPtr hwp = VGAHWPTR(pScrn);
3892    SavagePtr psav = SAVPTR(pScrn);
3893    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
3894    SavageRegPtr SavageSavePtr = &psav->SavedReg;
3895
3896    TRACE(("SavageCloseScreen\n"));
3897
3898#ifdef XF86DRI
3899    if (psav->directRenderingEnabled) {
3900        SAVAGEDRICloseScreen(pScreen);
3901	/* reset shadow values */
3902	SavageInitShadowStatus(pScrn);
3903        psav->directRenderingEnabled=FALSE;
3904    }
3905#endif
3906
3907    if (psav->EXADriverPtr) {
3908	exaDriverFini(pScreen);
3909	psav->EXADriverPtr = NULL;
3910    }
3911
3912    if( psav->AccelInfoRec ) {
3913        XAADestroyInfoRec( psav->AccelInfoRec );
3914	psav->AccelInfoRec = NULL;
3915    }
3916
3917    if( psav->DGAModes ) {
3918	xfree( psav->DGAModes );
3919	psav->DGAModes = NULL;
3920	psav->numDGAModes = 0;
3921    }
3922
3923    if (pScrn->vtSema) {
3924        if (psav->FBStart2nd)
3925	    SavageStreamsOff(pScrn);
3926	SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
3927        SavageResetStreams(pScrn);
3928	vgaHWLock(hwp);
3929	SavageUnmapMem(pScrn, 0);
3930    }
3931
3932    if (psav->pVbe)
3933      vbeFree(psav->pVbe);
3934    psav->pVbe = NULL;
3935
3936    pScrn->vtSema = FALSE;
3937    pScreen->CloseScreen = psav->CloseScreen;
3938
3939    return (*pScreen->CloseScreen)(scrnIndex, pScreen);
3940}
3941
3942
3943static Bool SavageSaveScreen(ScreenPtr pScreen, int mode)
3944{
3945    ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
3946
3947    TRACE(("SavageSaveScreen(0x%x)\n", mode));
3948
3949    if( pScrn->vtSema && SAVPTR(pScrn)->hwcursor && SAVPTR(pScrn)->hwc_on )
3950    {
3951	if( xf86IsUnblank(mode) )
3952	    SavageShowCursor( pScrn );
3953	else
3954	    SavageHideCursor( pScrn );
3955	SAVPTR(pScrn)->hwc_on = TRUE; /*restore */
3956    }
3957
3958    return vgaHWSaveScreen(pScreen, mode);
3959}
3960
3961void SavageAdjustFrame(int scrnIndex, int x, int y, int flags)
3962{
3963    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
3964    SavagePtr psav = SAVPTR(pScrn);
3965
3966    if (psav->IsSecondary) {
3967	SavageDoAdjustFrame(pScrn, x, y, TRUE);
3968    } else {
3969	SavageDoAdjustFrame(pScrn, x, y, FALSE);
3970    }
3971
3972}
3973
3974void
3975SavageDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int crtc2)
3976{
3977    SavagePtr psav = SAVPTR(pScrn);
3978    int address=0,top=0,left=0,tile_height,tile_size;
3979
3980    TRACE(("SavageDoAdjustFrame(%d,%d,%x)\n", x, y, flags));
3981
3982    if (psav->Chipset == S3_SAVAGE2000) {
3983        tile_height = TILEHEIGHT_2000; /* 32 */
3984        tile_size = TILE_SIZE_BYTE_2000; /* 4096 */
3985    } else {
3986        tile_height = TILEHEIGHT; /* 16 */
3987        tile_size = TILE_SIZE_BYTE; /* 2048 */
3988    }
3989
3990    if (!psav->bTiled) {
3991        left = x - x % 64;
3992        top = y;
3993        address = (top * psav->lDelta) + left * (pScrn->bitsPerPixel >> 3);
3994        address = (address >> 5) << 5;
3995    } else {
3996        top = y - y % tile_height;
3997        if (pScrn->bitsPerPixel == 16) {
3998            left = x - x % TILEWIDTH_16BPP;
3999            address = top * psav->lDelta + left * tile_size / TILEWIDTH_16BPP;
4000        } else if (pScrn->bitsPerPixel == 32) {
4001            left = x - x % TILEWIDTH_32BPP;
4002            address = top * psav->lDelta + left * tile_size / TILEWIDTH_32BPP;
4003        }
4004    }
4005
4006    address += pScrn->fbOffset;
4007
4008    if (psav->Chipset == S3_SAVAGE_MX) {
4009	if (!crtc2) {
4010            OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
4011            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);/* IGA1 */
4012        } else {
4013            OUTREG32(PRI_STREAM2_FBUF_ADDR0, address & 0xFFFFFFFC);/* IGA2 */
4014            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFFC);
4015	}
4016    } else if (psav->Chipset == S3_SUPERSAVAGE) {
4017	if (!crtc2) {
4018            /* IGA1 */
4019            OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
4020            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
4021        } else {
4022            /* IGA2 */
4023            OUTREG32(PRI_STREAM2_FBUF_ADDR0, ((address & 0xFFFFFFF8) | 0x80000000));
4024            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFF8);
4025	}
4026    } else if (psav->Chipset == S3_SAVAGE2000) {
4027        /*  certain Y values seems to cause havoc, not sure why */
4028        OUTREG32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
4029        OUTREG32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
4030    } else {
4031        OUTREG32(PRI_STREAM_FBUF_ADDR0,address |  0xFFFFFFFC);
4032        OUTREG32(PRI_STREAM_FBUF_ADDR1,address |  0x80000000);
4033    }
4034
4035    return;
4036}
4037
4038Bool SavageSwitchMode(int scrnIndex, DisplayModePtr mode, int flags)
4039{
4040    ScrnInfoPtr    pScrn      = xf86Screens[scrnIndex];
4041    SavagePtr psav = SAVPTR(pScrn);
4042    Bool success;
4043
4044    TRACE(("SavageSwitchMode\n"));
4045
4046    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
4047        SavageStreamsOff(xf86Screens[scrnIndex]);
4048
4049    success = SavageModeInit(xf86Screens[scrnIndex], mode);
4050
4051    /* switching mode on primary will reset secondary.  it needs to be reset as well*/
4052    if (psav->IsPrimary) {
4053        DevUnion* pPriv;
4054        SavageEntPtr pSavEnt;
4055        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
4056              gSavageEntityIndex);
4057        pSavEnt = pPriv->ptr;
4058        SavageModeInit(pSavEnt->pSecondaryScrn, pSavEnt->pSecondaryScrn->currentMode);
4059    }
4060    SavagePanningCheck(pScrn);
4061
4062    return success;
4063}
4064
4065
4066void SavageEnableMMIO(ScrnInfoPtr pScrn)
4067{
4068    vgaHWPtr hwp = VGAHWPTR(pScrn);
4069    SavagePtr psav = SAVPTR(pScrn);
4070    int vgaCRIndex, vgaCRReg;
4071    unsigned char val;
4072
4073    TRACE(("SavageEnableMMIO\n"));
4074
4075    vgaHWSetStdFuncs(hwp);
4076    vgaHWSetMmioFuncs(hwp, psav->MapBase, 0x8000);
4077    val = VGAIN8(0x3c3);
4078    VGAOUT8(0x3c3, val | 0x01);
4079    val = VGAIN8(VGA_MISC_OUT_R);
4080    VGAOUT8(VGA_MISC_OUT_W, val | 0x01);
4081    vgaCRIndex = psav->vgaIOBase + 4;
4082    vgaCRReg = psav->vgaIOBase + 5;
4083
4084    if( psav->Chipset >= S3_SAVAGE4 )
4085    {
4086	VGAOUT8(vgaCRIndex, 0x40);
4087	val = VGAIN8(vgaCRReg);
4088	VGAOUT8(vgaCRReg, val | 1);
4089    }
4090
4091    return;
4092}
4093
4094
4095void SavageDisableMMIO(ScrnInfoPtr pScrn)
4096{
4097    vgaHWPtr hwp = VGAHWPTR(pScrn);
4098    SavagePtr psav = SAVPTR(pScrn);
4099    int vgaCRIndex, vgaCRReg;
4100    unsigned char val;
4101
4102    TRACE(("SavageDisableMMIO\n"));
4103
4104    vgaCRIndex = psav->vgaIOBase + 4;
4105    vgaCRReg = psav->vgaIOBase + 5;
4106
4107    if( psav->Chipset >= S3_SAVAGE4 )
4108    {
4109	VGAOUT8(vgaCRIndex, 0x40);
4110	val = VGAIN8(vgaCRReg);
4111	VGAOUT8(vgaCRReg, val | 1);
4112    }
4113
4114    vgaHWSetStdFuncs(hwp);
4115
4116    return;
4117}
4118
4119void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
4120		       LOCO *colors, VisualPtr pVisual)
4121{
4122    SavagePtr psav = SAVPTR(pScrn);
4123    int i, index;
4124    int updateKey = -1;
4125    unsigned char byte = 0;
4126
4127    /* choose CLUT */
4128    if (psav->IsPrimary) {
4129	/* enable CLUT 1 */
4130        VGAOUT8(0x3c4, 0x21);
4131        byte = VGAIN8(0x3c5);
4132        VGAOUT8(0x3c5, (byte & ~0x01));
4133	/* select CLUT 1 */
4134        VGAOUT8(0x3c4, 0x47);
4135        byte = VGAIN8(0x3c5);
4136        VGAOUT8(0x3c5, (byte & ~0x03) | 0x01); /* CLUT 1 */
4137    } else if (psav->IsSecondary) {
4138	/* enable CLUT 2 */
4139        VGAOUT8(0x3c4, 0x21);
4140        byte = VGAIN8(0x3c5);
4141        VGAOUT8(0x3c5, (byte & ~0x10));
4142	/* select CLUT 2 */
4143        VGAOUT8(0x3c4, 0x47);
4144        byte = VGAIN8(0x3c5);
4145        VGAOUT8(0x3c5, (byte & ~0x03) | 0x02); /* CLUT 2 */
4146    }
4147
4148    for (i=0; i<numColors; i++) {
4149	index = indicies[i];
4150	if (index == pScrn->colorKey) updateKey = index;
4151	VGAOUT8(0x3c8, index);
4152	VGAOUT8(0x3c9, colors[index].red);
4153	VGAOUT8(0x3c9, colors[index].green);
4154	VGAOUT8(0x3c9, colors[index].blue);
4155    }
4156
4157    /* restore saved CLUT index value */
4158    if (psav->IsPrimary || psav->IsSecondary) {
4159        VGAOUT8(0x3c4, 0x47);
4160        VGAOUT8(0x3c5, byte);
4161    }
4162
4163    if (updateKey != -1)
4164	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4165			colors[updateKey].blue);
4166}
4167
4168#define Shift(v,d)  ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))
4169
4170static void
4171SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b)
4172{
4173    ScreenPtr pScreen;
4174    SavagePtr psav = SAVPTR(pScrn);
4175    FbOverlayScrPrivPtr pScrOvlPriv;
4176    CARD32 key;
4177    int ul = 0, ol = 1;
4178
4179    if (pScrn->depth != 8) {
4180	ul = 1;
4181	ol = 0;
4182    }
4183    if (!(pScreen = pScrn->pScreen)
4184	|| !(pScrOvlPriv = fbOverlayGetScrPriv(pScreen)))
4185	return;
4186    key = ((Shift(r,psav->overlay.redShift) & psav->overlay.redMask)
4187	   | (Shift(g,psav->overlay.greenShift) & psav->overlay.greenMask)
4188	   | (Shift(b,psav->overlay.blueShift) & psav->overlay.blueMask));
4189    if (pScrOvlPriv->layer[ol].key != key) {
4190	pScrOvlPriv->layer[ol].key = key;
4191	(*pScrOvlPriv->PaintKey) (&pScrOvlPriv->layer[ol].u.run.pixmap->drawable,
4192				  &pScrOvlPriv->layer[ul].u.run.region,
4193				  pScrOvlPriv->layer[ol].key, ol);
4194    }
4195}
4196
4197#if 0
4198#define inStatus1() (hwp->readST01( hwp ))
4199#endif
4200
4201void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
4202		       LOCO *colors, VisualPtr pVisual)
4203{
4204    SavagePtr psav = SAVPTR(pScrn);
4205    int i, index;
4206    int updateKey = -1;
4207
4208    VerticalRetraceWait();
4209
4210    for (i=0; i<numColors; i++) {
4211          if (!(inStatus1()) & 0x08)
4212  	    VerticalRetraceWait();
4213	index = indicies[i];
4214	VGAOUT8(0x3c8, index);
4215	VGAOUT8(0x3c9, colors[index].red);
4216	VGAOUT8(0x3c9, colors[index].green);
4217	VGAOUT8(0x3c9, colors[index].blue);
4218	if (index == pScrn->colorKey) updateKey = index;
4219    }
4220    if (updateKey != -1)
4221	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4222			colors[updateKey].blue);
4223}
4224
4225static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
4226			   int min_n2, int max_n2, long freq_min,
4227			   long freq_max, unsigned int *mdiv,
4228			   unsigned int *ndiv, unsigned int *r)
4229{
4230    double ffreq, ffreq_min, ffreq_max;
4231    double div, diff, best_diff;
4232    unsigned int m;
4233    unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
4234
4235    ffreq = freq / 1000.0 / BASE_FREQ;
4236    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
4237    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
4238
4239    if (ffreq < ffreq_min / (1 << max_n2)) {
4240	    ErrorF("invalid frequency %1.3f Mhz\n",
4241		   ffreq*BASE_FREQ);
4242	    ffreq = ffreq_min / (1 << max_n2);
4243    }
4244    if (ffreq > ffreq_max / (1 << min_n2)) {
4245	    ErrorF("invalid frequency %1.3f Mhz\n",
4246		   ffreq*BASE_FREQ);
4247	    ffreq = ffreq_max / (1 << min_n2);
4248    }
4249
4250    /* work out suitable timings */
4251
4252    best_diff = ffreq;
4253
4254    for (n2=min_n2; n2<=max_n2; n2++) {
4255	for (n1=min_n1+2; n1<=max_n1+2; n1++) {
4256	    m = (int)(ffreq * n1 * (1 << n2) + 0.5);
4257	    if (m < min_m+2 || m > 127+2)
4258		continue;
4259	    div = (double)(m) / (double)(n1);
4260	    if ((div >= ffreq_min) &&
4261		(div <= ffreq_max)) {
4262		diff = ffreq - div / (1 << n2);
4263		if (diff < 0.0)
4264			diff = -diff;
4265		if (diff < best_diff) {
4266		    best_diff = diff;
4267		    best_m = m;
4268		    best_n1 = n1;
4269		    best_n2 = n2;
4270		}
4271	    }
4272	}
4273    }
4274
4275    *ndiv = best_n1 - 2;
4276    *r = best_n2;
4277    *mdiv = best_m - 2;
4278}
4279
4280
4281void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file)
4282{
4283    unsigned char cr66;
4284    int r, success = 0;
4285    CARD32 fifo_control = 0, miu_control = 0;
4286    CARD32 streams_timeout = 0, misc_timeout = 0;
4287    vgaHWPtr hwp = VGAHWPTR(pScrn);
4288    SavagePtr psav = SAVPTR(pScrn);
4289    int vgaCRIndex, vgaCRReg, vgaIOBase;
4290
4291    TRACE(("SavageGEReset(%d,%s)\n", line, file));
4292
4293    vgaIOBase = hwp->IOBase;
4294    vgaCRIndex = vgaIOBase + 4;
4295    vgaCRReg = vgaIOBase + 5;
4296
4297    if (from_timeout) {
4298	if (psav->GEResetCnt++ < 10 || xf86GetVerbosity() > 1)
4299	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4300		       "SavageGEReset called from %s line %d\n", file, line);
4301    } else
4302	psav->WaitIdleEmpty(psav);
4303
4304    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4305	fifo_control = INREG(FIFO_CONTROL_REG);
4306	miu_control = INREG(MIU_CONTROL_REG);
4307	streams_timeout = INREG(STREAMS_TIMEOUT_REG);
4308	misc_timeout = INREG(MISC_TIMEOUT_REG);
4309    }
4310
4311    VGAOUT8(vgaCRIndex, 0x66);
4312    cr66 = VGAIN8(vgaCRReg);
4313
4314    usleep(10000);
4315    for (r=1; r<10; r++) {
4316	VGAOUT8(vgaCRReg, cr66 | 0x02);
4317	usleep(10000);
4318	VGAOUT8(vgaCRReg, cr66 & ~0x02);
4319	usleep(10000);
4320
4321	if (!from_timeout)
4322	    psav->WaitIdleEmpty(psav);
4323	OUTREG(DEST_SRC_STR, psav->Bpl << 16 | psav->Bpl);
4324
4325	usleep(10000);
4326	switch(psav->Chipset) {
4327	    case S3_SAVAGE3D:
4328	    case S3_SAVAGE_MX:
4329	      success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
4330	      break;
4331	    case S3_SAVAGE4:
4332	    case S3_PROSAVAGE:
4333	    case S3_PROSAVAGEDDR:
4334	    case S3_TWISTER:
4335	    case S3_SUPERSAVAGE:
4336	      success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
4337	      break;
4338	    case S3_SAVAGE2000:
4339	      success = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
4340	      break;
4341	}
4342	if(!success) {
4343	    usleep(10000);
4344	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4345		"restarting S3 graphics engine reset %2d ...\n", r);
4346	}
4347	else
4348	    break;
4349    }
4350
4351    /* At this point, the FIFO is empty and the engine is idle. */
4352
4353    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4354	OUTREG(FIFO_CONTROL_REG, fifo_control);
4355	OUTREG(MIU_CONTROL_REG, miu_control);
4356	OUTREG(STREAMS_TIMEOUT_REG, streams_timeout);
4357	OUTREG(MISC_TIMEOUT_REG, misc_timeout);
4358    }
4359
4360    OUTREG(SRC_BASE, 0);
4361    OUTREG(DEST_BASE, 0);
4362    OUTREG(CLIP_L_R, ((0) << 16) | pScrn->displayWidth);
4363    OUTREG(CLIP_T_B, ((0) << 16) | psav->ScissB);
4364    OUTREG(MONO_PAT_0, ~0);
4365    OUTREG(MONO_PAT_1, ~0);
4366
4367    SavageSetGBD(pScrn);
4368
4369}
4370
4371
4372
4373/* This function is used to debug, it prints out the contents of s3 regs */
4374
4375void
4376SavagePrintRegs(ScrnInfoPtr pScrn)
4377{
4378    SavagePtr psav = SAVPTR(pScrn);
4379    unsigned char i;
4380    int vgaCRIndex = 0x3d4;
4381    int vgaCRReg = 0x3d5;
4382
4383    ErrorF( "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4384
4385    for( i = 0; i < 0x70; i++ ) {
4386	if( !(i % 16) )
4387	    ErrorF( "\nSR%xx ", i >> 4 );
4388	VGAOUT8( 0x3c4, i );
4389	ErrorF( " %02x", VGAIN8(0x3c5) );
4390    }
4391
4392    ErrorF( "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4393
4394    for( i = 0; i < 0xB7; i++ ) {
4395	if( !(i % 16) )
4396	    ErrorF( "\nCR%xx ", i >> 4 );
4397	VGAOUT8( vgaCRIndex, i );
4398	ErrorF( " %02x", VGAIN8(vgaCRReg) );
4399    }
4400
4401    ErrorF("\n\n");
4402}
4403
4404static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
4405{
4406    SavagePtr psav = SAVPTR(pScrn);
4407    unsigned char sr8 = 0x00, srd = 0x00;
4408
4409    TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
4410
4411    if (psav->DisplayType == MT_CRT) {
4412    	VGAOUT8(0x3c4, 0x08);
4413    	sr8 = VGAIN8(0x3c5);
4414    	sr8 |= 0x06;
4415    	VGAOUT8(0x3c5, sr8);
4416
4417    	VGAOUT8(0x3c4, 0x0d);
4418    	srd = VGAIN8(0x3c5);
4419
4420    	srd &= 0x03;
4421
4422    	switch (mode) {
4423	    case DPMSModeOn:
4424	    	break;
4425	    case DPMSModeStandby:
4426	    	srd |= 0x10;
4427	    	break;
4428	    case DPMSModeSuspend:
4429	    	srd |= 0x40;
4430	    	break;
4431	    case DPMSModeOff:
4432	    	srd |= 0x50;
4433	    	break;
4434	    default:
4435	    	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4436	    	break;
4437    	}
4438
4439    	VGAOUT8(0x3c4, 0x0d);
4440    	VGAOUT8(0x3c5, srd);
4441    }
4442
4443    if (psav->DisplayType == MT_LCD || psav->DisplayType == MT_DFP) {
4444	if (S3_MOBILE_TWISTER_SERIES(psav->Chipset) && psav->UseBIOS) {
4445	    SavageSetPanelEnabled(psav, (mode == DPMSModeOn));
4446	} else {
4447    	    switch (mode) {
4448	        case DPMSModeOn:
4449		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4450		    VGAOUT8(0x3c5, VGAIN8(0x3c5) | 0x10);
4451	            break;
4452	        case DPMSModeStandby:
4453	        case DPMSModeSuspend:
4454	        case DPMSModeOff:
4455		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4456		    VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10);
4457	            break;
4458	        default:
4459	            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4460	            break;
4461	    }
4462        }
4463    }
4464
4465    return;
4466}
4467
4468static void
4469SavageProbeDDC(ScrnInfoPtr pScrn, int index)
4470{
4471    vbeInfoPtr pVbe;
4472
4473    if (xf86LoadSubModule(pScrn, "vbe")) {
4474	xf86LoaderReqSymLists(vbeSymbols, NULL);
4475	pVbe = VBEInit(NULL, index);
4476	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
4477	vbeFree(pVbe);
4478    }
4479}
4480
4481static unsigned int
4482SavageDDC1Read(ScrnInfoPtr pScrn)
4483{
4484    register unsigned char tmp;
4485    SavagePtr psav = SAVPTR(pScrn);
4486
4487    UnLockExtRegs();
4488
4489    VerticalRetraceWait();
4490
4491    InI2CREG(tmp,psav->I2CPort);
4492
4493    return ((unsigned int) (tmp & 0x08));
4494}
4495
4496static Bool
4497SavageDDC1(int scrnIndex)
4498{
4499    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
4500    SavagePtr psav = SAVPTR(pScrn);
4501    unsigned char byte;
4502    xf86MonPtr pMon;
4503
4504    UnLockExtRegs();
4505
4506    /* initialize chipset */
4507    InI2CREG(byte,psav->I2CPort);
4508    OutI2CREG(byte | 0x12,psav->I2CPort);
4509
4510    pMon = xf86DoEDID_DDC1(scrnIndex,vgaHWddc1SetSpeedWeak(),SavageDDC1Read);
4511    if (!pMon)
4512        return FALSE;
4513
4514    xf86PrintEDID(pMon);
4515
4516    xf86SetDDCproperties(pScrn,pMon);
4517
4518    /* undo initialization */
4519    OutI2CREG(byte,psav->I2CPort);
4520
4521    return TRUE;
4522}
4523
4524static void
4525SavageGetTvMaxSize(SavagePtr psav)
4526{
4527    if( psav->PAL ) {
4528	psav->TVSizeX = 800;
4529	psav->TVSizeY = 600;
4530    }
4531    else {
4532	psav->TVSizeX = 640;
4533	psav->TVSizeY = 480;
4534    }
4535}
4536
4537
4538static Bool
4539SavagePanningCheck(ScrnInfoPtr pScrn)
4540{
4541    SavagePtr psav = SAVPTR(pScrn);
4542    DisplayModePtr pMode;
4543
4544    pMode = pScrn->currentMode;
4545    psav->iResX = pMode->CrtcHDisplay;
4546    psav->iResY = pMode->CrtcVDisplay;
4547
4548    if ((psav->iResX < psav->PanelX || psav->iResY < psav->PanelY))
4549        psav->FPExpansion = TRUE;
4550    else
4551        psav->FPExpansion = FALSE;
4552
4553    if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
4554	return TRUE;
4555    else
4556	return FALSE;
4557}
4558
4559static void
4560SavageResetStreams(ScrnInfoPtr pScrn)
4561{
4562    SavagePtr psav = SAVPTR(pScrn);
4563    unsigned char cr67;
4564    unsigned char cr69;
4565
4566    /* disable streams */
4567    switch (psav->Chipset) {
4568        case S3_SAVAGE_MX:
4569        case S3_SUPERSAVAGE:
4570            OUTREG32(PRI_STREAM_STRIDE,0);
4571            OUTREG32(PRI_STREAM2_STRIDE, 0);
4572            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4573            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4574            OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
4575            OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
4576	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4577            cr67 = INREG8(CRT_DATA_REG);
4578	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4579	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4580	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4581            OUTREG8(CRT_DATA_REG, cr67);
4582            break;
4583	case S3_SAVAGE3D:
4584        case S3_SAVAGE4:
4585        case S3_TWISTER:
4586        case S3_PROSAVAGE:
4587        case S3_PROSAVAGEDDR:
4588            OUTREG32(PRI_STREAM_STRIDE,0);
4589            OUTREG32(PRI_STREAM_FBUF_ADDR0,0);
4590            OUTREG32(PRI_STREAM_FBUF_ADDR1,0);
4591	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4592            cr67 = INREG8(CRT_DATA_REG);
4593	    cr67 &= ~0x0c; /* CR67[2] = 1 : enable stream 1 */
4594            OUTREG8(CRT_DATA_REG, cr67);
4595	    OUTREG8(CRT_ADDRESS_REG, 0x69);
4596            cr69 = INREG8(CRT_DATA_REG);
4597	    cr69 &= ~0x80; /* CR69[0] = 1 : Mem-mapped regs */
4598            OUTREG8(CRT_DATA_REG, cr69);
4599            break;
4600        case S3_SAVAGE2000:
4601            OUTREG32(PRI_STREAM_STRIDE,0);
4602            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4603            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4604	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4605            cr67 = INREG8(CRT_DATA_REG);
4606	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4607	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4608	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4609            OUTREG8(CRT_DATA_REG, cr67);
4610            break;
4611        default:
4612            break;
4613    }
4614
4615}
4616