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