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