savage_driver.c revision aa9e3350
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        if((strptr = (char *)xf86GetOptValString(psav->Options, OPTION_ACCELMETHOD))) {
1270	    if(!xf86NameCmp(strptr,"XAA")) {
1271	        from = X_CONFIG;
1272	        psav->useEXA = FALSE;
1273	    } else if(!xf86NameCmp(strptr,"EXA")) {
1274	       from = X_CONFIG;
1275	       psav->useEXA = TRUE;
1276	    }
1277       }
1278       xf86DrvMsg(pScrn->scrnIndex, from, "Using %s acceleration architecture\n",
1279		psav->useEXA ? "EXA" : "XAA");
1280    }
1281
1282    if ((s = xf86GetOptValString(psav->Options, OPTION_OVERLAY))) {
1283
1284	if (psav->shadowFB) {
1285	    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
1286		       "Option \"Overlay\" not supported with shadowFB\n");
1287	} else {
1288	    if (pScrn->depth == 8) {
1289		if (!*s || !xf86NameCmp(s, "24")) {
1290		    psav->overlayDepth = 24;
1291		    psav->NoAccel = TRUE; /* Preliminary */
1292		    pScrn->colorKey = TRANSPARENCY_KEY;
1293		    pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1294		} else if (!xf86NameCmp(s, "16")) {
1295		    psav->overlayDepth = 16;
1296		    psav->NoAccel = TRUE; /* Preliminary */
1297		    pScrn->colorKey = TRANSPARENCY_KEY;
1298		    pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1299		} else {
1300		    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
1301			       "\"%s\" Ingnoring\n",s);
1302		}
1303	    } else if (pScrn->depth != 15) {
1304		psav->overlayDepth = 8;
1305		psav->NoAccel = TRUE; /* Preliminary */
1306		pScrn->colorKey = TRANSPARENCY_KEY;
1307		pScrn->overlayFlags = OVERLAY_8_32_DUALFB;
1308		if (*s && (xf86NameCmp(s, "8")))
1309		    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Wrong argument: "
1310			       "\"%s\" for depth %i overlay depth must be 8\n",
1311			       s,pScrn->depth);
1312	    } else {
1313		 xf86DrvMsg(pScrn->scrnIndex,X_WARNING,"Overlay not "
1314			       "supported for depth 15\n");
1315	    }
1316	    if (psav->overlayDepth) {
1317		xf86DrvMsg(pScrn->scrnIndex,X_INFO,"%i/%i Overlay enabled\n",
1318			   pScrn->depth,psav->overlayDepth);
1319		psav->primStreamBpp = 8;
1320	    }
1321	}
1322    }
1323
1324    if (pScrn->bitsPerPixel == 24 && !psav->NoAccel) {
1325	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1326		   "HW acceleration not possible with depth 32 and bpp 24.\n");
1327	psav->NoAccel = TRUE;
1328    }
1329
1330    /*
1331     * The SWCursor setting takes priority over HWCursor.  The default
1332     * if neither is specified is HW, unless ShadowFB is specified,
1333     * then SW.
1334     */
1335
1336    from = X_DEFAULT;
1337    psav->hwcursor = psav->shadowFB ? FALSE : TRUE;
1338    if (xf86GetOptValBool(psav->Options, OPTION_HWCURSOR, &psav->hwcursor))
1339	from = X_CONFIG;
1340    if (xf86ReturnOptValBool(psav->Options, OPTION_SWCURSOR, FALSE)) {
1341	psav->hwcursor = FALSE;
1342	from = X_CONFIG;
1343    }
1344    xf86DrvMsg(pScrn->scrnIndex, from, "Using %s cursor\n",
1345        psav->hwcursor ? "HW" : "SW");
1346
1347    from = X_DEFAULT;
1348    psav->UseBIOS = TRUE;
1349    if (xf86GetOptValBool(psav->Options, OPTION_USEBIOS, &psav->UseBIOS) )
1350	from = X_CONFIG;
1351    xf86DrvMsg(pScrn->scrnIndex, from, "%ssing video BIOS to set modes\n",
1352        psav->UseBIOS ? "U" : "Not u" );
1353
1354    psav->LCDClock = 0.0;
1355    if( xf86GetOptValFreq( psav->Options, OPTION_LCDCLOCK, OPTUNITS_MHZ, &psav->LCDClock ) )
1356	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1357		    "Option: LCDClock %1.2f MHz\n", psav->LCDClock );
1358
1359    if( xf86GetOptValBool( psav->Options, OPTION_SHADOW_STATUS, &psav->ShadowStatus)) {
1360	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1361		    "Option: ShadowStatus %sabled\n", psav->ShadowStatus ? "en" : "dis" );
1362	psav->ForceShadowStatus = TRUE;
1363    } else
1364	psav->ForceShadowStatus = FALSE;
1365    /* If ShadowStatus is off it will be automatically enabled for DRI.
1366     * If DRI initialization fails fall back to ConfigShadowStatus. */
1367    psav->ConfigShadowStatus = psav->ShadowStatus;
1368
1369    if( xf86GetOptValBool( psav->Options, OPTION_CRT_ONLY, &psav->CrtOnly))
1370	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1371		    "Option: CrtOnly enabled\n" );
1372
1373    if( xf86GetOptValBool( psav->Options, OPTION_TV_ON, &psav->TvOn)) {
1374        psav->PAL = FALSE;
1375        SavageGetTvMaxSize(psav);
1376    }
1377
1378    if( xf86GetOptValBool( psav->Options, OPTION_TV_PAL, &psav->PAL)) {
1379        SavageGetTvMaxSize(psav);
1380	psav->TvOn = TRUE;
1381    }
1382
1383    if( psav->TvOn )
1384	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1385		    "TV enabled in %s format\n",
1386		    psav->PAL ? "PAL" : "NTSC" );
1387
1388    psav->ForceInit = 0;
1389    if( xf86GetOptValBool( psav->Options, OPTION_FORCE_INIT, &psav->ForceInit))
1390	xf86DrvMsg( pScrn->scrnIndex, X_CONFIG,
1391		    "Option: ForceInit enabled\n" );
1392
1393    if (pScrn->numEntities > 1) {
1394	SavageFreeRec(pScrn);
1395	return FALSE;
1396    }
1397
1398    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
1399#ifndef XSERVER_LIBPCIACCESS
1400    if (pEnt->resources) {
1401	free(pEnt);
1402	SavageFreeRec(pScrn);
1403	return FALSE;
1404    }
1405#endif
1406    psav->EntityIndex = pEnt->index;
1407
1408    if (xf86LoadSubModule(pScrn, "vbe")) {
1409	psav->pVbe = VBEInit(NULL, pEnt->index);
1410    }
1411
1412#ifndef XSERVER_LIBPCIACCESS
1413    xf86RegisterResources(pEnt->index, NULL, ResNone);
1414    xf86SetOperatingState(resVgaIo, pEnt->index, ResUnusedOpr);
1415    xf86SetOperatingState(resVgaMem, pEnt->index, ResDisableOpr);
1416#endif
1417
1418    from = X_DEFAULT;
1419    if (pEnt->device->chipset && *pEnt->device->chipset) {
1420	pScrn->chipset = pEnt->device->chipset;
1421	psav->ChipId = pEnt->device->chipID;
1422	from = X_CONFIG;
1423    } else if (pEnt->device->chipID >= 0) {
1424	psav->ChipId = pEnt->device->chipID;
1425	pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
1426						   psav->Chipset);
1427	from = X_CONFIG;
1428	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipID override: 0x%04X\n",
1429		   pEnt->device->chipID);
1430    } else {
1431	from = X_PROBED;
1432	psav->ChipId = DEVICE_ID(psav->PciInfo);
1433	pScrn->chipset = (char *)xf86TokenToString(SavageChipsets,
1434						   psav->Chipset);
1435    }
1436
1437    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Chip: id %04x, \"%s\"\n",
1438	       psav->ChipId, xf86TokenToString( SavageChips, psav->ChipId ) );
1439
1440    if (pEnt->device->chipRev >= 0) {
1441	psav->ChipRev = pEnt->device->chipRev;
1442	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ChipRev override: %d\n",
1443		   psav->ChipRev);
1444    } else
1445	psav->ChipRev = CHIP_REVISION(psav->PciInfo);
1446
1447    xf86DrvMsg(pScrn->scrnIndex, from, "Engine: \"%s\"\n", pScrn->chipset);
1448
1449    if (pEnt->device->videoRam != 0)
1450    	pScrn->videoRam = pEnt->device->videoRam;
1451
1452    free(pEnt);
1453
1454#ifndef XSERVER_LIBPCIACCESS
1455    psav->PciTag = pciTag(psav->PciInfo->bus, psav->PciInfo->device,
1456			  psav->PciInfo->func);
1457#endif
1458
1459
1460    /* Set AGP Mode from config */
1461    /* We support 1X 2X and 4X  */
1462#ifdef SAVAGEDRI
1463#ifdef XSERVER_LIBPCIACCESS
1464    /* Try to read the AGP capabilty block from the device.  If there is
1465     * no AGP info, the device is PCI.
1466     */
1467
1468    psav->IsPCI = (pci_device_get_agp_info(psav->PciInfo) == NULL);
1469#else
1470				/* AGP/PCI (FK: copied from radeon_driver.c) */
1471    /* Proper autodetection of an AGP capable device requires examining
1472     * PCI config registers to determine if the device implements extended
1473     * PCI capabilities, and then walking the capability list as indicated
1474     * in the PCI 2.2 and AGP 2.0 specifications, to determine if AGP
1475     * capability is present.  The procedure is outlined as follows:
1476     *
1477     * 1) Test bit 4 (CAP_LIST) of the PCI status register of the device
1478     *    to determine wether or not this device implements any extended
1479     *    capabilities.  If this bit is zero, then the device is a PCI 2.1
1480     *    or earlier device and is not AGP capable, and we can conclude it
1481     *    to be a PCI device.
1482     *
1483     * 2) If bit 4 of the status register is set, then the device implements
1484     *    extended capabilities.  There is an 8 bit wide capabilities pointer
1485     *    register located at offset 0x34 in PCI config space which points to
1486     *    the first capability in a linked list of extended capabilities that
1487     *    this device implements.  The lower two bits of this register are
1488     *    reserved and MBZ so must be masked out.
1489     *
1490     * 3) The extended capabilities list is formed by one or more extended
1491     *    capabilities structures which are aligned on DWORD boundaries.
1492     *    The first byte of the structure is the capability ID (CAP_ID)
1493     *    indicating what extended capability this structure refers to.  The
1494     *    second byte of the structure is an offset from the beginning of
1495     *    PCI config space pointing to the next capability in the linked
1496     *    list (NEXT_PTR) or NULL (0x00) at the end of the list.  The lower
1497     *    two bits of this pointer are reserved and MBZ.  By examining the
1498     *    CAP_ID of each capability and walking through the list, we will
1499     *    either find the AGP_CAP_ID (0x02) indicating this device is an
1500     *    AGP device, or we'll reach the end of the list, indicating it is
1501     *    a PCI device.
1502     *
1503     * Mike A. Harris <mharris@redhat.com>
1504     *
1505     * References:
1506     *	- PCI Local Bus Specification Revision 2.2, Chapter 6
1507     *	- AGP Interface Specification Revision 2.0, Section 6.1.5
1508     */
1509
1510    psav->IsPCI = TRUE;
1511
1512    if (pciReadLong(psav->PciTag, PCI_CMD_STAT_REG) & SAVAGE_CAP_LIST) {
1513	CARD32 cap_ptr, cap_id;
1514
1515	cap_ptr = pciReadLong(psav->PciTag,
1516			      SAVAGE_CAPABILITIES_PTR_PCI_CONFIG)
1517	    & SAVAGE_CAP_PTR_MASK;
1518
1519	while(cap_ptr != SAVAGE_CAP_ID_NULL) {
1520	    cap_id = pciReadLong(psav->PciTag, cap_ptr);
1521	    if ((cap_id & 0xff) == SAVAGE_CAP_ID_AGP) {
1522		psav->IsPCI = FALSE;
1523		break;
1524	    }
1525	    cap_ptr = (cap_id >> 8) & SAVAGE_CAP_PTR_MASK;
1526	}
1527    }
1528#endif
1529
1530    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "%s card detected\n",
1531	       (psav->IsPCI) ? "PCI" : "AGP");
1532
1533    if ((s = xf86GetOptValString(psav->Options, OPTION_BUS_TYPE))) {
1534	if (strcmp(s, "AGP") == 0) {
1535	    if (psav->IsPCI) {
1536		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1537			   "BusType AGP not available on PCI card\n");
1538	    } else {
1539		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to AGP\n");
1540	    }
1541	} else if (strcmp(s, "PCI") == 0) {
1542	    psav->IsPCI = TRUE;
1543	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "BusType set to PCI\n");
1544	} else {
1545	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1546		       "Invalid BusType option, using %s DMA\n",
1547		       psav->IsPCI ? "PCI" : "AGP");
1548	}
1549    }
1550
1551    psav->AgpDMA = !psav->IsPCI;
1552    if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_TYPE))) {
1553	if (strcmp(s, "AGP") == 0) {
1554	    if (psav->IsPCI) {
1555		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1556			   "AGP DMA not available on PCI card, using PCI DMA\n");
1557	    } else {
1558		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using AGP DMA\n");
1559	    }
1560	} else if (strcmp(s, "PCI") == 0) {
1561	    psav->AgpDMA = FALSE;
1562	    xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Using PCI DMA\n");
1563	} else {
1564	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1565		       "Invalid DmaType option, using %s DMA\n",
1566		       psav->AgpDMA ? "AGP" : "PCI");
1567	}
1568    } else {
1569	xf86DrvMsg(pScrn->scrnIndex, X_DEFAULT,
1570		   "Using %s DMA\n", psav->AgpDMA ? "AGP" : "PCI");
1571    }
1572
1573    psav->CommandDMA = TRUE;
1574    psav->VertexDMA = TRUE;
1575    from = X_DEFAULT;
1576    if ((s = xf86GetOptValString(psav->Options, OPTION_DMA_MODE))) {
1577	from = X_CONFIG;
1578	if (strcmp(s, "Command") == 0)
1579	    psav->VertexDMA = FALSE;
1580	else if (strcmp(s, "Vertex") == 0)
1581	    psav->CommandDMA = FALSE;
1582	else if (strcmp(s, "None") == 0)
1583	    psav->VertexDMA = psav->CommandDMA = FALSE;
1584	else if (strcmp(s, "Any") != 0) {
1585	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Invalid DmaMode option\n");
1586	    from = X_DEFAULT;
1587	}
1588    }
1589    if (psav->CommandDMA && S3_SAVAGE3D_SERIES(psav->Chipset)) {
1590	xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
1591		   "Savage3D/MX/IX does not support command DMA.\n");
1592	psav->CommandDMA = FALSE;
1593    }
1594    if ((psav->CommandDMA || psav->VertexDMA) &&
1595	psav->Chipset == S3_SUPERSAVAGE) {
1596	xf86DrvMsg(pScrn->scrnIndex, from == X_CONFIG ? X_WARNING : X_INFO,
1597		   "DMA is not supported on SuperSavages.\n");
1598	psav->CommandDMA = psav->VertexDMA = FALSE;
1599    }
1600    if (psav->CommandDMA && psav->VertexDMA)
1601	xf86DrvMsg(pScrn->scrnIndex, from,
1602		   "Will try command and vertex DMA mode\n");
1603    else if (psav->CommandDMA && !psav->VertexDMA)
1604	xf86DrvMsg(pScrn->scrnIndex, from,
1605		   "Will try only command DMA mode\n");
1606    else if (!psav->CommandDMA && psav->VertexDMA)
1607	xf86DrvMsg(pScrn->scrnIndex, from,
1608		   "Will try only vertex DMA mode\n");
1609    else
1610	xf86DrvMsg(pScrn->scrnIndex, from,
1611		   "DMA disabled\n");
1612
1613    if (!psav->IsPCI) {
1614	from = X_DEFAULT;
1615	psav->agpMode = SAVAGE_DEFAULT_AGP_MODE;
1616	/*psav->agpMode = SAVAGE_MAX_AGP_MODE;*/
1617	psav->agpSize = 16;
1618
1619	if (xf86GetOptValInteger(psav->Options,
1620				 OPTION_AGP_MODE, &(psav->agpMode))) {
1621	    if (psav->agpMode < 1) {
1622		psav->agpMode = 1;
1623	    }
1624	    if (psav->agpMode > SAVAGE_MAX_AGP_MODE) {
1625		psav->agpMode = SAVAGE_MAX_AGP_MODE;
1626	    }
1627	    if ((psav->agpMode > 2) &&
1628		(psav->Chipset == S3_SAVAGE3D ||
1629		 psav->Chipset == S3_SAVAGE_MX))
1630		psav->agpMode = 2; /* old savages only support 2x */
1631	    from = X_CONFIG;
1632	}
1633
1634	xf86DrvMsg(pScrn->scrnIndex, from, "Using AGP %dx mode\n",
1635		   psav->agpMode);
1636
1637	from = X_DEFAULT;
1638	if (xf86GetOptValInteger(psav->Options,
1639				 OPTION_AGP_SIZE, (int *)&(psav->agpSize))) {
1640	    switch (psav->agpSize) {
1641	    case 4:
1642	    case 8:
1643	    case 16:
1644	    case 32:
1645	    case 64:
1646	    case 128:
1647	    case 256:
1648		from = X_CONFIG;
1649		break;
1650	    default:
1651		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1652			   "Illegal AGP size: %d MB, defaulting to 16 MB\n", psav->agpSize);
1653		psav->agpSize = 16;
1654	    }
1655	}
1656
1657	xf86DrvMsg(pScrn->scrnIndex, from,
1658		   "Using %d MB AGP aperture\n", psav->agpSize);
1659    } else {
1660	psav->agpMode = 0;
1661	psav->agpSize = 0;
1662    }
1663
1664#endif
1665
1666    /* we can use Option "DisableTile TRUE" to disable tile mode */
1667    psav->bDisableTile = FALSE;
1668    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_TILE,&psav->bDisableTile)) {
1669        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1670                   "Option: %s Tile Mode and Program it \n",(psav->bDisableTile?"Disable":"Enable"));
1671    }
1672
1673#ifdef SAVAGEDRI
1674    /* disabled by default...doesn't seem to work */
1675    psav->bDisableXvMC = TRUE; /* if you want to free up more mem for DRI,etc. */
1676    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_XVMC, &psav->bDisableXvMC)) {
1677        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1678                   "Option: %s Hardware XvMC support\n",(psav->bDisableXvMC?"Disable":"Enable"));
1679    }
1680#endif
1681
1682    psav->disableCOB = FALSE; /* if you are having problems on savage4+ */
1683    if (xf86GetOptValBool(psav->Options, OPTION_DISABLE_COB, &psav->disableCOB)) {
1684        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1685                   "Option: %s the COB\n",(psav->disableCOB?"Disable":"Enable"));
1686    }
1687    if (psav->Chipset == S3_PROSAVAGE ||
1688	psav->Chipset == S3_TWISTER   ||
1689	psav->Chipset == S3_PROSAVAGEDDR)
1690	psav->BCIforXv = TRUE;
1691    else
1692    	psav->BCIforXv = FALSE; /* use the BCI for Xv */
1693    if (xf86GetOptValBool(psav->Options, OPTION_BCI_FOR_XV, &psav->BCIforXv)) {
1694        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1695                   "Option: %s use of the BCI for Xv\n",(psav->BCIforXv?"Enable":"Disable"));
1696    }
1697    psav->dvi = FALSE;
1698    if (xf86GetOptValBool(psav->Options, OPTION_DVI, &psav->dvi)) {
1699        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1700                   "%s DVI port support (Savage4 only)\n",(psav->dvi?"Force":"Disable"));
1701    }
1702
1703#ifdef SAVAGEDRI
1704    psav->AGPforXv = FALSE;
1705    if (xf86GetOptValBool(psav->Options, OPTION_AGP_FOR_XV, &psav->AGPforXv)) {
1706        if (psav->AGPforXv) {
1707            if (psav->agpSize == 0) {
1708                psav->AGPforXv = FALSE;
1709                xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "AGP not available, cannot use AGP for Xv\n");
1710            }
1711        }
1712        xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1713                   "Option: %s use of AGP buffer for Xv\n",(psav->AGPforXv?"Enable":"Disable"));
1714    }
1715#endif
1716
1717    /* Add more options here. */
1718
1719
1720    psav               = SAVPTR(pScrn);
1721    psav->IsSecondary  = FALSE;
1722    psav->IsPrimary    = FALSE;
1723    psav->pEnt         = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1724
1725    if (xf86IsEntityShared(psav->pEnt->index)) {
1726	if (xf86IsPrimInitDone(psav->pEnt->index)) {
1727
1728	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
1729
1730	    psav->IsSecondary = TRUE;
1731	    pSavageEnt->pSecondaryScrn = pScrn;
1732	    psav->TvOn = pSavageEnt->TvOn;
1733	} else {
1734	    SavageEntPtr pSavageEnt = SavageEntPriv(pScrn);
1735
1736	    xf86SetPrimInitDone(psav->pEnt->index);
1737
1738	    psav->IsPrimary = TRUE;
1739	    pSavageEnt->pPrimaryScrn        = pScrn;
1740	    pSavageEnt->TvOn = psav->TvOn;
1741	}
1742    }
1743
1744    switch(psav->Chipset) {
1745	case S3_SAVAGE_MX:
1746	case S3_SUPERSAVAGE:
1747	    psav->HasCRTC2 = TRUE;
1748	    break;
1749        default:
1750            psav->HasCRTC2 = FALSE;
1751    }
1752
1753    if ((psav->IsSecondary || psav->IsPrimary) && !psav->UseBIOS) {
1754	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "BIOS currently required for Dualhead mode setting.\n");
1755	return FALSE;
1756    }
1757
1758    if (psav->IsSecondary &&
1759	(pScrn->bitsPerPixel > 16) &&
1760	!psav->NoAccel &&
1761	(psav->Chipset == S3_SAVAGE_MX)) {
1762	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No acceleration in Dualhead mode at depth 24\n");
1763	return FALSE;
1764    }
1765
1766    /* maybe throw in some more sanity checks here */
1767
1768    if (!SavageMapMem(pScrn)) {
1769	SavageFreeRec(pScrn);
1770        vbeFree(psav->pVbe);
1771	psav->pVbe = NULL;
1772	return FALSE;
1773    }
1774
1775    vgaCRIndex = psav->vgaIOBase + 4;
1776    vgaCRReg = psav->vgaIOBase + 5;
1777
1778    xf86EnableIO();
1779    /* unprotect CRTC[0-7] */
1780    VGAOUT8(vgaCRIndex, 0x11);
1781    tmp = VGAIN8(vgaCRReg);
1782    VGAOUT8(vgaCRReg, tmp & 0x7f);
1783
1784    /* unlock extended regs */
1785    VGAOUT16(vgaCRIndex, 0x4838);
1786    VGAOUT16(vgaCRIndex, 0xa039);
1787    VGAOUT16(0x3c4, 0x0608);
1788
1789    VGAOUT8(vgaCRIndex, 0x40);
1790    tmp = VGAIN8(vgaCRReg);
1791    VGAOUT8(vgaCRReg, tmp & ~0x01);
1792
1793    /* unlock sys regs */
1794    VGAOUT8(vgaCRIndex, 0x38);
1795    VGAOUT8(vgaCRReg, 0x48);
1796
1797    {
1798	Gamma zeros = {0.0, 0.0, 0.0};
1799
1800	if (!xf86SetGamma(pScrn, zeros)) {
1801	    vbeFree(psav->pVbe);
1802	    psav->pVbe = NULL;
1803	    SavageFreeRec(pScrn);
1804	    return FALSE;
1805	}
1806    }
1807
1808    /* Unlock system registers. */
1809    VGAOUT16(vgaCRIndex, 0x4838);
1810
1811    /* Next go on to detect amount of installed ram */
1812
1813    VGAOUT8(vgaCRIndex, 0x36);            /* for register CR36 (CONFG_REG1), */
1814    config1 = VGAIN8(vgaCRReg);           /* get amount of vram installed */
1815
1816    /* Compute the amount of video memory and offscreen memory. */
1817
1818    if (!pScrn->videoRam) {
1819	static const unsigned char RamSavage3D[] = { 8, 4, 4, 2 };
1820	static unsigned char RamSavage4[] =  { 2, 4, 8, 12, 16, 32, 64, 32 };
1821	static const unsigned char RamSavageMX[] = { 2, 8, 4, 16, 8, 16, 4, 16 };
1822	static const unsigned char RamSavageNB[] = { 0, 2, 4, 8, 16, 32, 16, 2 };
1823
1824	switch( psav->Chipset ) {
1825	case S3_SAVAGE3D:
1826	    pScrn->videoRam = RamSavage3D[ (config1 & 0xC0) >> 6 ] * 1024;
1827	    break;
1828
1829	case S3_SAVAGE4:
1830	    /*
1831	     * The Savage4 has one ugly special case to consider.  On
1832	     * systems with 4 banks of 2Mx32 SDRAM, the BIOS says 4MB
1833	     * when it really means 8MB.  Why do it the same when you
1834	     * can do it different...
1835	     */
1836	    VGAOUT8(vgaCRIndex, 0x68);	/* memory control 1 */
1837	    if( (VGAIN8(vgaCRReg) & 0xC0) == (0x01 << 6) )
1838		RamSavage4[1] = 8;
1839
1840	    /*FALLTHROUGH*/
1841
1842	case S3_SAVAGE2000:
1843	    pScrn->videoRam = RamSavage4[ (config1 & 0xE0) >> 5 ] * 1024;
1844	    break;
1845
1846	case S3_SAVAGE_MX:
1847	case S3_SUPERSAVAGE:
1848	    pScrn->videoRam = RamSavageMX[ (config1 & 0x0E) >> 1 ] * 1024;
1849	    break;
1850
1851	case S3_PROSAVAGE:
1852	case S3_PROSAVAGEDDR:
1853	case S3_TWISTER:
1854	    pScrn->videoRam = RamSavageNB[ (config1 & 0xE0) >> 5 ] * 1024;
1855	    break;
1856
1857	default:
1858	    /* How did we get here? */
1859	    pScrn->videoRam = 0;
1860	    break;
1861	}
1862
1863	psav->videoRambytes = pScrn->videoRam * 1024;
1864
1865	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1866		"probed videoram:  %dk\n",
1867		pScrn->videoRam);
1868    } else {
1869	psav->videoRambytes = pScrn->videoRam * 1024;
1870
1871	xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
1872	       "videoram =  %dk\n",
1873		pScrn->videoRam);
1874    }
1875
1876    /* Get video RAM */
1877    if( !pScrn->videoRam && psav->pVbe )
1878    {
1879        /* If VBE is available, ask it about onboard memory. */
1880
1881	VbeInfoBlock* vib;
1882
1883	vib = VBEGetVBEInfo( psav->pVbe );
1884	pScrn->videoRam = vib->TotalMemory * 64;
1885	VBEFreeVBEInfo( vib );
1886
1887	/* VBE often cuts 64k off of the RAM total. */
1888
1889	if( pScrn->videoRam & 64 )
1890	    pScrn->videoRam += 64;
1891
1892	psav->videoRambytes = pScrn->videoRam * 1024;
1893    }
1894
1895
1896    /*
1897     * If we're running with acceleration, compute the command overflow
1898     * buffer location.  The command overflow buffer must END at a
1899     * 4MB boundary; for all practical purposes, that means the very
1900     * end of the frame buffer.
1901     */
1902    if (psav->NoAccel) {
1903        psav->cobIndex = 0;
1904        psav->cobSize = 0;
1905    }
1906    else if( ((S3_SAVAGE4_SERIES(psav->Chipset)) ||
1907             (S3_SUPERSAVAGE == psav->Chipset)) && psav->disableCOB ) {
1908        /*
1909         * The Savage4 and ProSavage have COB coherency bugs which render
1910         * the buffer useless.
1911         */
1912	/*
1913        psav->cobIndex = 2;
1914        psav->cobSize = 0x8000 << psav->cobIndex;
1915	*/
1916        psav->cobIndex = 0;
1917        psav->cobSize = 0;
1918	psav->bciThresholdHi = 32;
1919	psav->bciThresholdLo = 0;
1920    } else {
1921        /* We use 128kB for the COB on all other chips. */
1922        psav->cobSize = 0x20000;
1923	if (S3_SAVAGE3D_SERIES(psav->Chipset) ||
1924	    psav->Chipset == S3_SAVAGE2000) {
1925	    psav->cobIndex = 7; /* rev.A savage4 apparently also uses 7 */
1926	} else {
1927	    psav->cobIndex = 2;
1928	}
1929	/* max command size: 2560 entries */
1930	psav->bciThresholdHi = psav->cobSize/4 + 32 - 2560;
1931	psav->bciThresholdLo = psav->bciThresholdHi - 2560;
1932    }
1933
1934    /* align cob to 128k */
1935    psav->cobOffset = (psav->videoRambytes - psav->cobSize) & ~0x1ffff;
1936
1937    /* The cursor must be aligned on a 4k boundary. */
1938    psav->CursorKByte = (psav->cobOffset >> 10) - 4;
1939    psav->endfb = (psav->CursorKByte << 10) - 1;
1940
1941    if (psav->IsPrimary) {
1942        pScrn->videoRam /= 2;
1943	psav->videoRambytes = pScrn->videoRam * 1024;
1944	psav->CursorKByte = (psav->videoRambytes >> 10) - 4;
1945	psav->endfb = (psav->CursorKByte << 10) - 1;
1946	psav->videoRambytes *= 2;
1947	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1948		"Using %dk of videoram for primary head\n",
1949		pScrn->videoRam);
1950    }
1951
1952    if(psav->IsSecondary)
1953    {
1954        pScrn->videoRam /= 2;
1955	/*psav->videoRambytes = pScrn->videoRam * 1024;*/
1956	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1957		"Using %dk of videoram for secondary head\n",
1958		pScrn->videoRam);
1959    }
1960
1961    pScrn->fbOffset = (psav->IsSecondary)
1962      ? pScrn->videoRam * 1024 : 0;
1963
1964    /* reset graphics engine to avoid memory corruption */
1965    VGAOUT8(vgaCRIndex, 0x66);
1966    cr66 = VGAIN8(vgaCRReg);
1967    VGAOUT8(vgaCRReg, cr66 | 0x02);
1968    usleep(10000);
1969
1970    VGAOUT8(vgaCRIndex, 0x66);
1971    VGAOUT8(vgaCRReg, cr66 & ~0x02);	/* clear reset flag */
1972    usleep(10000);
1973
1974    /* Set status word positions based on chip type. */
1975    SavageInitStatus(pScrn);
1976
1977    /* check for DVI/flat panel */
1978    dvi = FALSE;
1979    if (psav->Chipset == S3_SAVAGE4) {
1980	unsigned char sr30 = 0x00;
1981	VGAOUT8(0x3c4, 0x30);
1982	/* clear bit 1 */
1983	VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x02);
1984    	sr30 = VGAIN8(0x3c5);
1985    	if (sr30 & 0x02 /*0x04 */) {
1986            dvi = TRUE;
1987	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Digital Flat Panel Detected\n");
1988	}
1989    }
1990
1991    if( (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
1992	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) && !psav->CrtOnly ) {
1993	psav->DisplayType = MT_LCD;
1994    } else if (dvi || ((psav->Chipset == S3_SAVAGE4) && psav->dvi)) {
1995	psav->DisplayType = MT_DFP;
1996    } else {
1997	psav->DisplayType = MT_CRT;
1998    }
1999
2000    if (psav->IsSecondary)
2001	psav->DisplayType = MT_CRT;
2002
2003    /* Do the DDC dance. */
2004    SavageDoDDC(pScrn);
2005
2006    /* set up ramdac max clock - might be altered by SavageGetPanelInfo */
2007    if (pScrn->bitsPerPixel >= 24)
2008        psav->maxClock = 220000;
2009    else
2010        psav->maxClock = 250000;
2011
2012    /* detect current mclk */
2013    VGAOUT8(0x3c4, 0x08);
2014    sr8 = VGAIN8(0x3c5);
2015    VGAOUT8(0x3c5, 0x06);
2016    VGAOUT8(0x3c4, 0x10);
2017    n = VGAIN8(0x3c5);
2018    VGAOUT8(0x3c4, 0x11);
2019    m = VGAIN8(0x3c5);
2020    VGAOUT8(0x3c4, 0x08);
2021    VGAOUT8(0x3c5, sr8);
2022    m &= 0x7f;
2023    n1 = n & 0x1f;
2024    n2 = (n >> 5) & 0x03;
2025    mclk = ((1431818 * (m+2)) / (n1+2) / (1 << n2) + 50) / 100;
2026    xf86DrvMsg(pScrn->scrnIndex, X_PROBED, "Detected current MCLK value of %1.3f MHz\n",
2027	       mclk / 1000.0);
2028
2029    pScrn->maxHValue = 2048 << 3;	/* 11 bits of h_total 8-pixel units */
2030    pScrn->maxVValue = 2048;		/* 11 bits of v_total */
2031    pScrn->virtualX = pScrn->display->virtualX;
2032    pScrn->virtualY = pScrn->display->virtualY;
2033
2034    /* Check LCD panel information */
2035
2036    if(psav->DisplayType == MT_LCD)
2037	SavageGetPanelInfo(pScrn);
2038
2039    /* DisplayType will be reset if panel is not active */
2040    if(psav->DisplayType == MT_LCD)
2041	SavageAddPanelMode(pScrn);
2042
2043#if 0
2044    if (psav->CrtOnly && !psav->UseBIOS) {
2045	VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
2046	VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10); /* disable FP */
2047        if (S3_SAVAGE_MOBILE_SERIES(psav->Chipset) /*||
2048	    S3_MOBILE_TWISTER_SERIES(psav->Chipset)*/) { /* not sure this works on mobile prosavage */
2049		VGAOUT8(0x3c4, 0x31);
2050		VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x04); /* make sure crtc1 is crt source */
2051    	}
2052    }
2053#endif
2054
2055    if( psav->UseBIOS )
2056    {
2057	/* Go probe the BIOS for all the modes and refreshes at this depth. */
2058
2059	if( psav->ModeTable )
2060	{
2061	    SavageFreeBIOSModeTable( psav, &psav->ModeTable );
2062	}
2063
2064	psav->ModeTable = SavageGetBIOSModeTable( psav, psav->primStreamBpp );
2065
2066	if( !psav->ModeTable || !psav->ModeTable->NumModes ) {
2067	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2068		       "Failed to fetch any BIOS modes.  Disabling BIOS.\n");
2069	    psav->UseBIOS = FALSE;
2070	}
2071	else
2072	/*if( xf86Verbose )*/
2073	{
2074	    SavageModeEntryPtr pmt;
2075
2076	    xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
2077		       "Found %d modes at this depth:\n",
2078		       psav->ModeTable->NumModes);
2079
2080	    for(
2081		i = 0, pmt = psav->ModeTable->Modes;
2082		i < psav->ModeTable->NumModes;
2083		i++, pmt++ )
2084	    {
2085		int j;
2086		ErrorF( "    [%03x] %d x %d",
2087			pmt->VesaMode, pmt->Width, pmt->Height );
2088		for( j = 0; j < pmt->RefreshCount; j++ )
2089		{
2090		    ErrorF( ", %dHz", pmt->RefreshRate[j] );
2091		}
2092		ErrorF( "\n");
2093	    }
2094	}
2095    }
2096
2097    clockRanges = xnfalloc(sizeof(ClockRange));
2098    clockRanges->next = NULL;
2099    clockRanges->minClock = 10000;
2100    clockRanges->maxClock = psav->maxClock;
2101    clockRanges->clockIndex = -1;
2102    clockRanges->interlaceAllowed = TRUE;
2103    clockRanges->doubleScanAllowed = TRUE;
2104    clockRanges->ClockDivFactor = 1.0;
2105    clockRanges->ClockMulFactor = 1.0;
2106
2107    i = xf86ValidateModes(pScrn, pScrn->monitor->Modes,
2108			  pScrn->display->modes, clockRanges, NULL,
2109			  256, 2048, 16 * pScrn->bitsPerPixel,
2110			  128, 2048,
2111			  pScrn->virtualX, pScrn->virtualY,
2112			  psav->videoRambytes, LOOKUP_BEST_REFRESH);
2113
2114    if (i == -1) {
2115	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86ValidateModes failure\n");
2116	SavageFreeRec(pScrn);
2117	vbeFree(psav->pVbe);
2118	psav->pVbe = NULL;
2119	return FALSE;
2120    }
2121
2122    xf86PruneDriverModes(pScrn);
2123
2124    if (i == 0 || pScrn->modes == NULL) {
2125	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes found\n");
2126	SavageFreeRec(pScrn);
2127	vbeFree(psav->pVbe);
2128	psav->pVbe = NULL;
2129	return FALSE;
2130    }
2131
2132    xf86SetCrtcForModes(pScrn, INTERLACE_HALVE_V);
2133    pScrn->currentMode = pScrn->modes;
2134    xf86PrintModes(pScrn);
2135    xf86SetDpi(pScrn, 0, 0);
2136
2137    if (xf86LoadSubModule(pScrn, "fb") == NULL) {
2138	SavageFreeRec(pScrn);
2139	vbeFree(psav->pVbe);
2140	psav->pVbe = NULL;
2141	return FALSE;
2142    }
2143
2144    if( !psav->NoAccel ) {
2145        char *modName = NULL;
2146
2147	if (psav->useEXA) {
2148	    modName = "exa";
2149	    XF86ModReqInfo req;
2150	    int errmaj, errmin;
2151	    memset(&req, 0, sizeof(req));
2152	    req.majorversion = 2;
2153	    req.minorversion = 0;
2154
2155	    if( !LoadSubModule(pScrn->module, modName,
2156		NULL, NULL, NULL, &req, &errmaj, &errmin) ) {
2157		LoaderErrorMsg(NULL, modName, errmaj, errmin);
2158	    	SavageFreeRec(pScrn);
2159	    	vbeFree(psav->pVbe);
2160	    	psav->pVbe = NULL;
2161	    	return FALSE;
2162	    }
2163	} else {
2164	    modName = "xaa";
2165	    if( !xf86LoadSubModule(pScrn, modName) ) {
2166		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2167			   "Falling back to shadowfb\n");
2168		psav->NoAccel = 1;
2169		psav->shadowFB = 1;
2170	    }
2171	}
2172    }
2173
2174    if (psav->hwcursor) {
2175	if (!xf86LoadSubModule(pScrn, "ramdac")) {
2176	    SavageFreeRec(pScrn);
2177	    vbeFree(psav->pVbe);
2178	    psav->pVbe = NULL;
2179	    return FALSE;
2180	}
2181    }
2182
2183    if (psav->shadowFB) {
2184	if (!xf86LoadSubModule(pScrn, "shadowfb")) {
2185	    SavageFreeRec(pScrn);
2186	    vbeFree(psav->pVbe);
2187	    psav->pVbe = NULL;
2188	    return FALSE;
2189	}
2190    }
2191    vbeFree(psav->pVbe);
2192
2193    psav->pVbe = NULL;
2194
2195    return TRUE;
2196}
2197
2198
2199static Bool SavageEnterVT(VT_FUNC_ARGS_DECL)
2200{
2201    SCRN_INFO_PTR(arg);
2202#ifdef SAVAGEDRI
2203    SavagePtr psav = SAVPTR(pScrn);
2204    ScreenPtr pScreen;
2205#endif
2206
2207    gpScrn = pScrn;
2208    SavageEnableMMIO(pScrn);
2209
2210#ifdef SAVAGEDRI
2211    if (psav->directRenderingEnabled) {
2212        pScreen = xf86ScrnToScreen(pScrn);
2213        SAVAGEDRIResume(pScreen);
2214        DRIUnlock(pScreen);
2215        psav->LockHeld = 0;
2216    }
2217#endif
2218    if (!SAVPTR(pScrn)->IsSecondary)
2219    	SavageSave(pScrn);
2220    if(SavageModeInit(pScrn, pScrn->currentMode)) {
2221	/* some BIOSes seem to enable HW cursor on PM resume */
2222	if (!SAVPTR(pScrn)->hwc_on)
2223	    SavageHideCursor( pScrn );
2224	return TRUE;
2225    }
2226
2227    return FALSE;
2228}
2229
2230
2231static void SavageLeaveVT(VT_FUNC_ARGS_DECL)
2232{
2233    SCRN_INFO_PTR(arg);
2234    vgaHWPtr hwp = VGAHWPTR(pScrn);
2235    SavagePtr psav = SAVPTR(pScrn);
2236    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2237    SavageRegPtr SavageSavePtr = &psav->SavedReg;
2238#ifdef SAVAGEDRI
2239    ScreenPtr pScreen;
2240#endif
2241
2242    TRACE(("SavageLeaveVT(%d)\n", flags));
2243    gpScrn = pScrn;
2244
2245#ifdef SAVAGEDRI
2246    if (psav->directRenderingEnabled) {
2247        pScreen = xf86ScrnToScreen(pScrn);
2248        DRILock(pScreen, 0);
2249        psav->LockHeld = 1;
2250    }
2251#endif
2252    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
2253        SavageStreamsOff(pScrn);
2254    SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
2255    SavageResetStreams(pScrn);
2256    SavageDisableMMIO(pScrn);
2257
2258}
2259
2260
2261static void SavageSave(ScrnInfoPtr pScrn)
2262{
2263    unsigned char cr3a, cr53, cr66;
2264    vgaHWPtr hwp = VGAHWPTR(pScrn);
2265    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
2266    SavagePtr psav = SAVPTR(pScrn);
2267    SavageRegPtr save = &psav->SavedReg;
2268    unsigned short vgaCRReg = psav->vgaIOBase + 5;
2269    unsigned short vgaCRIndex = psav->vgaIOBase + 4;
2270
2271    TRACE(("SavageSave()\n"));
2272
2273    VGAOUT16(vgaCRIndex, 0x4838);
2274    VGAOUT16(vgaCRIndex, 0xa039);
2275    VGAOUT16(0x3c4, 0x0608);
2276
2277    VGAOUT8(vgaCRIndex, 0x66);
2278    cr66 = VGAIN8(vgaCRReg);
2279    VGAOUT8(vgaCRReg, cr66 | 0x80);
2280    VGAOUT8(vgaCRIndex, 0x3a);
2281    cr3a = VGAIN8(vgaCRReg);
2282    VGAOUT8(vgaCRReg, cr3a | 0x80);
2283    VGAOUT8(vgaCRIndex, 0x53);
2284    cr53 = VGAIN8(vgaCRReg);
2285    VGAOUT8(vgaCRReg, cr53 & 0x7f);
2286
2287    if (xf86IsPrimaryPci(psav->PciInfo))
2288	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_ALL);
2289    else
2290	vgaHWSave(pScrn, vgaSavePtr, VGA_SR_MODE);
2291
2292    VGAOUT8(vgaCRIndex, 0x66);
2293    VGAOUT8(vgaCRReg, cr66);
2294    VGAOUT8(vgaCRIndex, 0x3a);
2295    VGAOUT8(vgaCRReg, cr3a);
2296
2297    VGAOUT8(vgaCRIndex, 0x66);
2298    VGAOUT8(vgaCRReg, cr66);
2299    VGAOUT8(vgaCRIndex, 0x3a);
2300    VGAOUT8(vgaCRReg, cr3a);
2301
2302    /* unlock extended seq regs */
2303    VGAOUT8(0x3c4, 0x08);
2304    save->SR08 = VGAIN8(0x3c5);
2305    VGAOUT8(0x3c5, 0x06);
2306
2307    /* now save all the extended regs we need */
2308    VGAOUT8(vgaCRIndex, 0x31);
2309    save->CR31 = VGAIN8(vgaCRReg);
2310    VGAOUT8(vgaCRIndex, 0x32);
2311    save->CR32 = VGAIN8(vgaCRReg);
2312    VGAOUT8(vgaCRIndex, 0x34);
2313    save->CR34 = VGAIN8(vgaCRReg);
2314    VGAOUT8(vgaCRIndex, 0x36);
2315    save->CR36 = VGAIN8(vgaCRReg);
2316    VGAOUT8(vgaCRIndex, 0x3a);
2317    save->CR3A = VGAIN8(vgaCRReg);
2318    VGAOUT8(vgaCRIndex, 0x40);
2319    save->CR40 = VGAIN8(vgaCRReg);
2320    VGAOUT8(vgaCRIndex, 0x42);
2321    save->CR42 = VGAIN8(vgaCRReg);
2322    VGAOUT8(vgaCRIndex, 0x45);
2323    save->CR45 = VGAIN8(vgaCRReg);
2324    VGAOUT8(vgaCRIndex, 0x50);
2325    save->CR50 = VGAIN8(vgaCRReg);
2326    VGAOUT8(vgaCRIndex, 0x51);
2327    save->CR51 = VGAIN8(vgaCRReg);
2328    VGAOUT8(vgaCRIndex, 0x53);
2329    save->CR53 = VGAIN8(vgaCRReg);
2330    VGAOUT8(vgaCRIndex, 0x58);
2331    save->CR58 = VGAIN8(vgaCRReg);
2332    VGAOUT8(vgaCRIndex, 0x60);
2333    save->CR60 = VGAIN8(vgaCRReg);
2334    VGAOUT8(vgaCRIndex, 0x66);
2335    save->CR66 = VGAIN8(vgaCRReg);
2336    VGAOUT8(vgaCRIndex, 0x67);
2337    save->CR67 = VGAIN8(vgaCRReg);
2338    VGAOUT8(vgaCRIndex, 0x68);
2339    save->CR68 = VGAIN8(vgaCRReg);
2340    VGAOUT8(vgaCRIndex, 0x69);
2341    save->CR69 = VGAIN8(vgaCRReg);
2342    VGAOUT8(vgaCRIndex, 0x6f);
2343    save->CR6F = VGAIN8(vgaCRReg);
2344
2345    VGAOUT8(vgaCRIndex, 0x33);
2346    save->CR33 = VGAIN8(vgaCRReg);
2347    VGAOUT8(vgaCRIndex, 0x86);
2348    save->CR86 = VGAIN8(vgaCRReg);
2349    VGAOUT8(vgaCRIndex, 0x88);
2350    save->CR88 = VGAIN8(vgaCRReg);
2351    VGAOUT8(vgaCRIndex, 0x90);
2352    save->CR90 = VGAIN8(vgaCRReg);
2353    VGAOUT8(vgaCRIndex, 0x91);
2354    save->CR91 = VGAIN8(vgaCRReg);
2355    VGAOUT8(vgaCRIndex, 0xb0);
2356    save->CRB0 = VGAIN8(vgaCRReg) | 0x80;
2357
2358    /* extended mode timing regs */
2359    VGAOUT8(vgaCRIndex, 0x3b);
2360    save->CR3B = VGAIN8(vgaCRReg);
2361    VGAOUT8(vgaCRIndex, 0x3c);
2362    save->CR3C = VGAIN8(vgaCRReg);
2363    VGAOUT8(vgaCRIndex, 0x43);
2364    save->CR43 = VGAIN8(vgaCRReg);
2365    VGAOUT8(vgaCRIndex, 0x5d);
2366    save->CR5D = VGAIN8(vgaCRReg);
2367    VGAOUT8(vgaCRIndex, 0x5e);
2368    save->CR5E = VGAIN8(vgaCRReg);
2369    VGAOUT8(vgaCRIndex, 0x65);
2370    save->CR65 = VGAIN8(vgaCRReg);
2371
2372    /* save seq extended regs for DCLK PLL programming */
2373    VGAOUT8(0x3c4, 0x0e);
2374    save->SR0E = VGAIN8(0x3c5);
2375    VGAOUT8(0x3c4, 0x0f);
2376    save->SR0F = VGAIN8(0x3c5);
2377    VGAOUT8(0x3c4, 0x10);
2378    save->SR10 = VGAIN8(0x3c5);
2379    VGAOUT8(0x3c4, 0x11);
2380    save->SR11 = VGAIN8(0x3c5);
2381    VGAOUT8(0x3c4, 0x12);
2382    save->SR12 = VGAIN8(0x3c5);
2383    VGAOUT8(0x3c4, 0x13);
2384    save->SR13 = VGAIN8(0x3c5);
2385    VGAOUT8(0x3c4, 0x29);
2386    save->SR29 = VGAIN8(0x3c5);
2387
2388    VGAOUT8(0x3c4, 0x15);
2389    save->SR15 = VGAIN8(0x3c5);
2390    VGAOUT8(0x3c4, 0x30);
2391    save->SR30 = VGAIN8(0x3c5);
2392    VGAOUT8(0x3c4, 0x18);
2393    save->SR18 = VGAIN8(0x3c5);
2394    VGAOUT8(0x3c4, 0x1b);
2395    save->SR1B = VGAIN8(0x3c5);
2396
2397    /* Save flat panel expansion registers. */
2398
2399    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2400	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2401	int i;
2402	for( i = 0; i < 8; i++ ) {
2403	    VGAOUT8(0x3c4, 0x54+i);
2404	    save->SR54[i] = VGAIN8(0x3c5);
2405	}
2406    }
2407
2408    VGAOUT8(vgaCRIndex, 0x66);
2409    cr66 = VGAIN8(vgaCRReg);
2410    VGAOUT8(vgaCRReg, cr66 | 0x80);
2411    VGAOUT8(vgaCRIndex, 0x3a);
2412    cr3a = VGAIN8(vgaCRReg);
2413    VGAOUT8(vgaCRReg, cr3a | 0x80);
2414
2415    /* now save MIU regs */
2416    if( ! S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
2417	save->MMPR0 = INREG(FIFO_CONTROL_REG);
2418	save->MMPR1 = INREG(MIU_CONTROL_REG);
2419	save->MMPR2 = INREG(STREAMS_TIMEOUT_REG);
2420	save->MMPR3 = INREG(MISC_TIMEOUT_REG);
2421    }
2422
2423    VGAOUT8(vgaCRIndex, 0x3a);
2424    VGAOUT8(vgaCRReg, cr3a);
2425    VGAOUT8(vgaCRIndex, 0x66);
2426    VGAOUT8(vgaCRReg, cr66);
2427
2428    if (!psav->ModeStructInit) {
2429	vgaHWCopyReg(&hwp->ModeReg, vgaSavePtr);
2430	memcpy(&psav->ModeReg, save, sizeof(SavageRegRec));
2431	psav->ModeStructInit = TRUE;
2432    }
2433
2434#if 0
2435    if (xf86GetVerbosity() > 1)
2436	SavagePrintRegs(pScrn);
2437#endif
2438
2439    return;
2440}
2441
2442
2443static void SavageWriteMode(ScrnInfoPtr pScrn, vgaRegPtr vgaSavePtr,
2444			    SavageRegPtr restore, Bool Entering)
2445{
2446    unsigned char tmp, cr3a, cr66;
2447    vgaHWPtr hwp = VGAHWPTR(pScrn);
2448    SavagePtr psav = SAVPTR(pScrn);
2449    int vgaCRIndex, vgaCRReg, vgaIOBase;
2450
2451
2452    vgaIOBase = hwp->IOBase;
2453    vgaCRIndex = vgaIOBase + 4;
2454    vgaCRReg = vgaIOBase + 5;
2455
2456    TRACE(("SavageWriteMode(%x)\n", restore->mode));
2457
2458#ifdef SAVAGEDRI
2459    if (psav->directRenderingEnabled) {
2460        DRILock(xf86ScrnToScreen(pScrn), 0);
2461        psav->LockHeld = 1;
2462    }
2463#endif
2464
2465    if (psav->IsSecondary) {
2466	/* Set up the mode.  Don't clear video RAM. */
2467	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2468	SavageSetGBD(pScrn);
2469	return;
2470    }
2471
2472    if( Entering &&
2473	(!S3_SAVAGE_MOBILE_SERIES(psav->Chipset) || (psav->ForceInit))
2474    )
2475	SavageInitialize2DEngine(pScrn);
2476
2477    /*
2478     * If we figured out a VESA mode number for this timing, just use
2479     * the S3 BIOS to do the switching, with a few additional tweaks.
2480     */
2481
2482    if( psav->UseBIOS && restore->mode > 0x13 )
2483    {
2484	int width;
2485	unsigned short cr6d;
2486	unsigned short cr79 = 0;
2487
2488	/* Set up the mode.  Don't clear video RAM. */
2489	SavageSetVESAMode( psav, restore->mode | 0x8000, restore->refresh );
2490
2491	/* Restore the DAC. */
2492	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_CMAP);
2493
2494	/* Unlock the extended registers. */
2495
2496#if 0
2497	/* Which way is better? */
2498	hwp->writeCrtc( hwp, 0x38, 0x48 );
2499	hwp->writeCrtc( hwp, 0x39, 0xa0 );
2500	hwp->writeSeq( hwp, 0x08, 0x06 );
2501#endif
2502
2503	VGAOUT16(vgaCRIndex, 0x4838);
2504	VGAOUT16(vgaCRIndex, 0xA039);
2505	VGAOUT16(0x3c4, 0x0608);
2506
2507	/* Enable linear addressing. */
2508
2509	VGAOUT16(vgaCRIndex, 0x1358);
2510
2511	/* Disable old MMIO. */
2512
2513	VGAOUT8(vgaCRIndex, 0x53);
2514	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & ~0x10);
2515
2516	/* Disable HW cursor */
2517
2518	VGAOUT16(vgaCRIndex, 0x0045);
2519
2520	/* Set the color mode. */
2521
2522	VGAOUT8(vgaCRIndex, 0x67);
2523	VGAOUT8(vgaCRReg, restore->CR67);
2524
2525	/* Enable gamma correction, set CLUT to 8 bit */
2526
2527	VGAOUT8(0x3c4, 0x1b);
2528	if( (pScrn->bitsPerPixel == 32) && !psav->DGAactive
2529	    && ! psav->FBStart2nd )
2530		VGAOUT8(0x3c5, 0x18 );
2531	else
2532		VGAOUT8(0x3c5, 0x10 );
2533
2534	/* We may need TV/panel fixups here.  See s3bios.c line 2904. */
2535
2536	/* Set FIFO fetch delay. */
2537	VGAOUT8(vgaCRIndex, 0x85);
2538	VGAOUT8(vgaCRReg, (VGAIN8(vgaCRReg) & 0xf8) | 0x03);
2539
2540	/* Patch CR79.  These values are magical. */
2541
2542	if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2543	{
2544	    VGAOUT8(vgaCRIndex, 0x6d);
2545	    cr6d = VGAIN8(vgaCRReg);
2546
2547	    cr79 = 0x04;
2548
2549	    if( pScrn->displayWidth >= 1024 )
2550	    {
2551		if(psav->primStreamBpp == 32 )
2552		{
2553		    if( restore->refresh >= 130 )
2554			cr79 = 0x03;
2555		    else if( pScrn->displayWidth >= 1280 )
2556			cr79 = 0x02;
2557		    else if(
2558			(pScrn->displayWidth == 1024) &&
2559			(restore->refresh >= 75)
2560		    )
2561		    {
2562			if( cr6d & LCD_ACTIVE )
2563			    cr79 = 0x05;
2564			else
2565			    cr79 = 0x08;
2566		    }
2567		}
2568		else if( psav->primStreamBpp == 16)
2569		{
2570
2571/* The windows driver uses 0x13 for 16-bit 130Hz, but I see terrible
2572 * screen artifacts with that value.  Let's keep it low for now.
2573 *		if( restore->refresh >= 130 )
2574 *		    cr79 = 0x13;
2575 *		else
2576 */
2577		    if( pScrn->displayWidth == 1024 )
2578		    {
2579			if( cr6d & LCD_ACTIVE )
2580			    cr79 = 0x08;
2581			else
2582			    cr79 = 0x0e;
2583		    }
2584		}
2585	    }
2586	}
2587
2588        if( (psav->Chipset != S3_SAVAGE2000) &&
2589	    !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2590	    VGAOUT16(vgaCRIndex, (cr79 << 8) | 0x79);
2591
2592	/* Make sure 16-bit memory access is enabled. */
2593
2594	VGAOUT16(vgaCRIndex, 0x0c31);
2595
2596	/* Enable the graphics engine. */
2597
2598	VGAOUT16(vgaCRIndex, 0x0140);
2599
2600	/* Handle the pitch. */
2601
2602        VGAOUT8(vgaCRIndex, 0x50);
2603        VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2604
2605	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
2606	VGAOUT16(vgaCRIndex, ((width & 0xff) << 8) | 0x13 );
2607	VGAOUT16(vgaCRIndex, ((width & 0x300) << 4) | 0x51 );
2608
2609	/* Some non-S3 BIOSes enable block write even on non-SGRAM devices. */
2610
2611	switch( psav->Chipset )
2612	{
2613	    case S3_SAVAGE2000:
2614		VGAOUT8(vgaCRIndex, 0x73);
2615		VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) & 0xdf );
2616		break;
2617
2618	    case S3_SAVAGE3D:
2619	    case S3_SAVAGE4:
2620		VGAOUT8(vgaCRIndex, 0x68);
2621		if( !(VGAIN8(vgaCRReg) & 0x80) )
2622		{
2623		    /* Not SGRAM; disable block write. */
2624		    VGAOUT8(vgaCRIndex, 0x88);
2625		    VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0x10);
2626		}
2627		break;
2628	}
2629
2630	/* set the correct clock for some BIOSes */
2631	VGAOUT8(VGA_MISC_OUT_W,
2632		VGAIN8(VGA_MISC_OUT_R) | 0x0C);
2633	/* Some BIOSes turn on clock doubling on non-doubled modes */
2634	if (pScrn->bitsPerPixel < 24) {
2635	    VGAOUT8(vgaCRIndex, 0x67);
2636	    if (!(VGAIN8(vgaCRReg) & 0x10)) {
2637		VGAOUT8(0x3c4, 0x15);
2638		VGAOUT8(0x3c5, VGAIN8(0x3C5) & ~0x10);
2639		VGAOUT8(0x3c4, 0x18);
2640		VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x80);
2641	    }
2642	}
2643
2644	SavageInitialize2DEngine(pScrn);
2645
2646	VGAOUT16(vgaCRIndex, 0x0140);
2647
2648	SavageSetGBD(pScrn);
2649
2650
2651#ifdef SAVAGEDRI
2652    	if (psav->directRenderingEnabled)
2653    	    DRIUnlock(xf86ScrnToScreen(pScrn));
2654    	psav->LockHeld = 0;
2655#endif
2656
2657	return;
2658    }
2659
2660    VGAOUT8(0x3c2, 0x23);
2661    VGAOUT16(vgaCRIndex, 0x4838);
2662    VGAOUT16(vgaCRIndex, 0xa039);
2663    VGAOUT16(0x3c4, 0x0608);
2664
2665    vgaHWProtect(pScrn, TRUE);
2666
2667    /* will we be reenabling STREAMS for the new mode? */
2668    psav->STREAMSRunning = 0;
2669
2670    /* reset GE to make sure nothing is going on */
2671    VGAOUT8(vgaCRIndex, 0x66);
2672    if(VGAIN8(vgaCRReg) & 0x01)
2673	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2674
2675    /*
2676     * Some Savage/MX and /IX systems go nuts when trying to exit the
2677     * server after WindowMaker has displayed a gradient background.  I
2678     * haven't been able to find what causes it, but a non-destructive
2679     * switch to mode 3 here seems to eliminate the issue.
2680     */
2681
2682    if( ((restore->CR31 & 0x0a) == 0) && psav->pVbe ) {
2683	SavageSetTextMode( psav );
2684    }
2685
2686    VGAOUT8(vgaCRIndex, 0x67);
2687    (void) VGAIN8(vgaCRReg);
2688    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2689    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no STREAMS yet old and new */
2690
2691    /* restore extended regs */
2692    VGAOUT8(vgaCRIndex, 0x66);
2693    VGAOUT8(vgaCRReg, restore->CR66);
2694    VGAOUT8(vgaCRIndex, 0x3a);
2695    VGAOUT8(vgaCRReg, restore->CR3A);
2696    VGAOUT8(vgaCRIndex, 0x31);
2697    VGAOUT8(vgaCRReg, restore->CR31);
2698    VGAOUT8(vgaCRIndex, 0x32);
2699    VGAOUT8(vgaCRReg, restore->CR32);
2700    VGAOUT8(vgaCRIndex, 0x58);
2701    VGAOUT8(vgaCRReg, restore->CR58);
2702    VGAOUT8(vgaCRIndex, 0x53);
2703    VGAOUT8(vgaCRReg, restore->CR53 & 0x7f);
2704
2705    VGAOUT16(0x3c4, 0x0608);
2706
2707    /* Restore DCLK registers. */
2708
2709    VGAOUT8(0x3c4, 0x0e);
2710    VGAOUT8(0x3c5, restore->SR0E);
2711    VGAOUT8(0x3c4, 0x0f);
2712    VGAOUT8(0x3c5, restore->SR0F);
2713    VGAOUT8(0x3c4, 0x29);
2714    VGAOUT8(0x3c5, restore->SR29);
2715    VGAOUT8(0x3c4, 0x15);
2716    VGAOUT8(0x3c5, restore->SR15);
2717
2718    /* Restore flat panel expansion registers. */
2719    if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
2720	S3_MOBILE_TWISTER_SERIES(psav->Chipset)) {
2721	int i;
2722	for( i = 0; i < 8; i++ ) {
2723	    VGAOUT8(0x3c4, 0x54+i);
2724	    VGAOUT8(0x3c5, restore->SR54[i]);
2725	}
2726    }
2727
2728    /* restore the standard vga regs */
2729    if (xf86IsPrimaryPci(psav->PciInfo))
2730	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_ALL);
2731    else
2732	vgaHWRestore(pScrn, vgaSavePtr, VGA_SR_MODE);
2733
2734    /* extended mode timing registers */
2735    VGAOUT8(vgaCRIndex, 0x53);
2736    VGAOUT8(vgaCRReg, restore->CR53);
2737    VGAOUT8(vgaCRIndex, 0x5d);
2738    VGAOUT8(vgaCRReg, restore->CR5D);
2739    VGAOUT8(vgaCRIndex, 0x5e);
2740    VGAOUT8(vgaCRReg, restore->CR5E);
2741    VGAOUT8(vgaCRIndex, 0x3b);
2742    VGAOUT8(vgaCRReg, restore->CR3B);
2743    VGAOUT8(vgaCRIndex, 0x3c);
2744    VGAOUT8(vgaCRReg, restore->CR3C);
2745    VGAOUT8(vgaCRIndex, 0x43);
2746    VGAOUT8(vgaCRReg, restore->CR43);
2747    VGAOUT8(vgaCRIndex, 0x65);
2748    VGAOUT8(vgaCRReg, restore->CR65);
2749
2750    /* restore the desired video mode with cr67 */
2751    VGAOUT8(vgaCRIndex, 0x67);
2752    /*VGAOUT8(vgaCRReg, restore->CR67 & ~0x0c);*/ /* no STREAMS yet */
2753    VGAOUT8(vgaCRReg, restore->CR67 & ~0x0e); /* no streams for new and old streams engines */
2754
2755    /* other mode timing and extended regs */
2756    VGAOUT8(vgaCRIndex, 0x34);
2757    VGAOUT8(vgaCRReg, restore->CR34);
2758    VGAOUT8(vgaCRIndex, 0x40);
2759    VGAOUT8(vgaCRReg, restore->CR40);
2760    VGAOUT8(vgaCRIndex, 0x42);
2761    VGAOUT8(vgaCRReg, restore->CR42);
2762    VGAOUT8(vgaCRIndex, 0x45);
2763    VGAOUT8(vgaCRReg, restore->CR45);
2764    VGAOUT8(vgaCRIndex, 0x50);
2765    VGAOUT8(vgaCRReg, restore->CR50);
2766    VGAOUT8(vgaCRIndex, 0x51);
2767    VGAOUT8(vgaCRReg, restore->CR51);
2768
2769    /* memory timings */
2770    VGAOUT8(vgaCRIndex, 0x36);
2771    VGAOUT8(vgaCRReg, restore->CR36);
2772    VGAOUT8(vgaCRIndex, 0x60);
2773    VGAOUT8(vgaCRReg, restore->CR60);
2774    VGAOUT8(vgaCRIndex, 0x68);
2775    VGAOUT8(vgaCRReg, restore->CR68);
2776    VerticalRetraceWait();
2777    VGAOUT8(vgaCRIndex, 0x69);
2778    VGAOUT8(vgaCRReg, restore->CR69);
2779    VGAOUT8(vgaCRIndex, 0x6f);
2780    VGAOUT8(vgaCRReg, restore->CR6F);
2781
2782    VGAOUT8(vgaCRIndex, 0x33);
2783    VGAOUT8(vgaCRReg, restore->CR33);
2784    VGAOUT8(vgaCRIndex, 0x86);
2785    VGAOUT8(vgaCRReg, restore->CR86);
2786    VGAOUT8(vgaCRIndex, 0x88);
2787    VGAOUT8(vgaCRReg, restore->CR88);
2788    VGAOUT8(vgaCRIndex, 0x90);
2789    VGAOUT8(vgaCRReg, restore->CR90);
2790    VGAOUT8(vgaCRIndex, 0x91);
2791    VGAOUT8(vgaCRReg, restore->CR91);
2792    if( psav->Chipset == S3_SAVAGE4 )
2793    {
2794	VGAOUT8(vgaCRIndex, 0xb0);
2795	VGAOUT8(vgaCRReg, restore->CRB0);
2796    }
2797
2798    VGAOUT8(vgaCRIndex, 0x32);
2799    VGAOUT8(vgaCRReg, restore->CR32);
2800
2801    /* unlock extended seq regs */
2802    VGAOUT8(0x3c4, 0x08);
2803    VGAOUT8(0x3c5, 0x06);
2804
2805    /* Restore extended sequencer regs for MCLK. SR10 == 255 indicates that
2806     * we should leave the default SR10 and SR11 values there.
2807     */
2808    if (restore->SR10 != 255) {
2809	VGAOUT8(0x3c4, 0x10);
2810	VGAOUT8(0x3c5, restore->SR10);
2811	VGAOUT8(0x3c4, 0x11);
2812	VGAOUT8(0x3c5, restore->SR11);
2813    }
2814
2815    /* restore extended seq regs for dclk */
2816    VGAOUT8(0x3c4, 0x0e);
2817    VGAOUT8(0x3c5, restore->SR0E);
2818    VGAOUT8(0x3c4, 0x0f);
2819    VGAOUT8(0x3c5, restore->SR0F);
2820    VGAOUT8(0x3c4, 0x12);
2821    VGAOUT8(0x3c5, restore->SR12);
2822    VGAOUT8(0x3c4, 0x13);
2823    VGAOUT8(0x3c5, restore->SR13);
2824    VGAOUT8(0x3c4, 0x29);
2825    VGAOUT8(0x3c5, restore->SR29);
2826
2827    VGAOUT8(0x3c4, 0x18);
2828    VGAOUT8(0x3c5, restore->SR18);
2829    VGAOUT8(0x3c4, 0x1b);
2830    if( psav->DGAactive )
2831	VGAOUT8(0x3c5, restore->SR1B & ~0x08 );
2832    else
2833	VGAOUT8(0x3c5, restore->SR1B);
2834
2835    /* load new m, n pll values for dclk & mclk */
2836    VGAOUT8(0x3c4, 0x15);
2837    tmp = VGAIN8(0x3c5) & ~0x21;
2838
2839    VGAOUT8(0x3c5, tmp | 0x03);
2840    VGAOUT8(0x3c5, tmp | 0x23);
2841    VGAOUT8(0x3c5, tmp | 0x03);
2842    VGAOUT8(0x3c5, restore->SR15);
2843    usleep( 100 );
2844
2845    VGAOUT8(0x3c4, 0x30);
2846    VGAOUT8(0x3c5, restore->SR30);
2847    VGAOUT8(0x3c4, 0x08);
2848    VGAOUT8(0x3c5, restore->SR08);
2849
2850    /* now write out cr67 in full, possibly starting STREAMS */
2851    VerticalRetraceWait();
2852    VGAOUT8(vgaCRIndex, 0x67);
2853#if 0
2854    VGAOUT8(vgaCRReg, 0x50);
2855    usleep(10000);
2856    VGAOUT8(vgaCRIndex, 0x67);
2857#endif
2858    VGAOUT8(vgaCRReg, restore->CR67);
2859
2860    VGAOUT8(vgaCRIndex, 0x66);
2861    cr66 = VGAIN8(vgaCRReg);
2862    VGAOUT8(vgaCRReg, cr66 | 0x80);
2863    VGAOUT8(vgaCRIndex, 0x3a);
2864    cr3a = VGAIN8(vgaCRReg);
2865    VGAOUT8(vgaCRReg, cr3a | 0x80);
2866
2867    if (Entering)
2868	SavageGEReset(pScrn,0,__LINE__,__FILE__);
2869
2870    if( !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
2871    {
2872	VerticalRetraceWait();
2873	OUTREG(FIFO_CONTROL_REG, restore->MMPR0);
2874	OUTREG(MIU_CONTROL_REG, restore->MMPR1);
2875	OUTREG(STREAMS_TIMEOUT_REG, restore->MMPR2);
2876	OUTREG(MISC_TIMEOUT_REG, restore->MMPR3);
2877    }
2878
2879    /* If we're going into graphics mode and acceleration was enabled, */
2880    /* go set up the BCI buffer and the global bitmap descriptor. */
2881
2882#if 0
2883    if( Entering && (!psav->NoAccel) )
2884    {
2885	VGAOUT8(vgaCRIndex, 0x50);
2886	VGAOUT8(vgaCRReg, VGAIN8(vgaCRReg) | 0xC1);
2887	SavageInitialize2DEngine(pScrn);
2888    }
2889#endif
2890
2891    VGAOUT8(vgaCRIndex, 0x66);
2892    VGAOUT8(vgaCRReg, cr66);
2893    VGAOUT8(vgaCRIndex, 0x3a);
2894    VGAOUT8(vgaCRReg, cr3a);
2895
2896    if( Entering ) {
2897	SavageInitialize2DEngine(pScrn);
2898
2899	VGAOUT16(vgaCRIndex, 0x0140);
2900
2901	SavageSetGBD(pScrn);
2902    }
2903
2904    vgaHWProtect(pScrn, FALSE);
2905
2906
2907#ifdef SAVAGEDRI
2908    if (psav->directRenderingEnabled)
2909        DRIUnlock(xf86ScrnToScreen(pScrn));
2910    psav->LockHeld = 0;
2911#endif
2912
2913    return;
2914}
2915
2916
2917static Bool SavageMapMem(ScrnInfoPtr pScrn)
2918{
2919    SavagePtr psav = SAVPTR(pScrn);
2920    int err;
2921
2922    TRACE(("SavageMapMem()\n"));
2923
2924    if( S3_SAVAGE3D_SERIES(psav->Chipset) ) {
2925#ifdef XSERVER_LIBPCIACCESS
2926        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
2927            + psav->PciInfo->regions[0].base_addr;
2928        psav->FbRegion.base = psav->PciInfo->regions[0].base_addr;
2929#else
2930        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S3
2931            + psav->PciInfo->memBase[0];
2932        psav->FbRegion.base = psav->PciInfo->memBase[0];
2933#endif
2934    } else {
2935#ifdef XSERVER_LIBPCIACCESS
2936        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
2937            + psav->PciInfo->regions[0].base_addr;
2938        psav->FbRegion.base = psav->PciInfo->regions[1].base_addr;
2939#else
2940        psav->MmioRegion.base = SAVAGE_NEWMMIO_REGBASE_S4
2941            + psav->PciInfo->memBase[0];
2942        psav->FbRegion.base = psav->PciInfo->memBase[1];
2943#endif
2944    }
2945
2946    psav->MmioRegion.size = SAVAGE_NEWMMIO_REGSIZE;
2947    psav->FbRegion.size = psav->videoRambytes;
2948
2949    /* On Paramount and Savage 2000, aperture 0 is PCI base 2.  On other
2950     * chipsets it's in the same BAR as the framebuffer.
2951     */
2952
2953    psav->ApertureRegion.size = (psav->IsPrimary || psav->IsSecondary)
2954        ? (0x01000000 * 2) : (0x01000000 * 5);
2955
2956    if ((psav->Chipset == S3_SUPERSAVAGE)
2957        || (psav->Chipset == S3_SAVAGE2000)) {
2958#ifdef XSERVER_LIBPCIACCESS
2959        psav->ApertureRegion.base = psav->PciInfo->regions[2].base_addr;
2960        if (psav->ApertureRegion.size > psav->PciInfo->regions[2].size)
2961            psav->ApertureRegion.size = psav->PciInfo->regions[2].size;
2962#else
2963        psav->ApertureRegion.base = psav->PciInfo->memBase[2];
2964#endif
2965    } else {
2966        psav->ApertureRegion.base = psav->FbRegion.base + 0x02000000;
2967    }
2968
2969
2970
2971    if (psav->FbRegion.size != 0) {
2972#ifdef XSERVER_LIBPCIACCESS
2973        err = pci_device_map_range(psav->PciInfo, psav->FbRegion.base,
2974                                   psav->FbRegion.size,
2975                                   (PCI_DEV_MAP_FLAG_WRITABLE
2976                                    | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
2977                                   & psav->FbRegion.memory);
2978#else
2979        psav->FbRegion.memory =
2980            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
2981                          psav->PciTag, psav->FbRegion.base,
2982                          psav->FbRegion.size);
2983        err = (psav->FbRegion.memory == NULL) ? errno : 0;
2984#endif
2985        if (err) {
2986            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2987                       "Internal error: could not map framebuffer range (%d, %s).\n",
2988                       err, strerror(err));
2989            return FALSE;
2990        }
2991
2992        psav->FBBase = psav->FbRegion.memory;
2993        psav->FBStart = (psav->IsSecondary)
2994            ? psav->FBBase + 0x1000000 : psav->FBBase;
2995    }
2996
2997    if (psav->ApertureRegion.memory == NULL) {
2998#ifdef XSERVER_LIBPCIACCESS
2999        err = pci_device_map_range(psav->PciInfo, psav->ApertureRegion.base,
3000                                   psav->ApertureRegion.size,
3001                                   (PCI_DEV_MAP_FLAG_WRITABLE
3002                                    | PCI_DEV_MAP_FLAG_WRITE_COMBINE),
3003                                   & psav->ApertureRegion.memory);
3004#else
3005        psav->ApertureRegion.memory =
3006            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_FRAMEBUFFER,
3007                          psav->PciTag, psav->ApertureRegion.base,
3008                          psav->ApertureRegion.size);
3009        err = (psav->ApertureRegion.memory == NULL) ? errno : 0;
3010#endif
3011        if (err) {
3012            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3013                       "Internal error: could not map aperture range (%d, %s).\n",
3014                       err, strerror(err));
3015            return FALSE;
3016        }
3017
3018        psav->ApertureMap = (psav->IsSecondary)
3019            ? psav->ApertureRegion.memory + 0x1000000
3020            : psav->ApertureRegion.memory;
3021    }
3022
3023    if (psav->MmioRegion.memory == NULL) {
3024#ifdef XSERVER_LIBPCIACCESS
3025        err = pci_device_map_range(psav->PciInfo, psav->MmioRegion.base,
3026                                   psav->MmioRegion.size,
3027                                   (PCI_DEV_MAP_FLAG_WRITABLE),
3028                                   & psav->MmioRegion.memory);
3029#else
3030        psav->MmioRegion.memory =
3031            xf86MapPciMem(pScrn->scrnIndex, VIDMEM_MMIO,
3032                          psav->PciTag, psav->MmioRegion.base,
3033                          psav->MmioRegion.size);
3034        err = (psav->MmioRegion.memory == NULL) ? errno : 0;
3035#endif
3036        if (err) {
3037            xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3038                       "Internal error: could not map MMIO range (%d, %s).\n",
3039                       err, strerror(err));
3040            return FALSE;
3041        }
3042
3043        psav->MapBase = psav->MmioRegion.memory;
3044        psav->BciMem = psav->MapBase + 0x10000;
3045
3046        SavageEnableMMIO(pScrn);
3047    }
3048
3049    pScrn->memPhysBase = psav->FbRegion.base;
3050    return TRUE;
3051}
3052
3053
3054static void SavageUnmapMem(ScrnInfoPtr pScrn, int All)
3055{
3056    SavagePtr psav = SAVPTR(pScrn);
3057
3058    TRACE(("SavageUnmapMem(%p,%p)\n", psav->MapBase, psav->FBBase));
3059
3060    if (psav->PrimaryVidMapped) {
3061        vgaHWUnmapMem(pScrn);
3062        psav->PrimaryVidMapped = FALSE;
3063    }
3064
3065    SavageDisableMMIO(pScrn);
3066
3067    if (All && (psav->MmioRegion.memory != NULL)) {
3068#ifdef XSERVER_LIBPCIACCESS
3069        pci_device_unmap_range(psav->PciInfo,
3070                               psav->MmioRegion.memory,
3071                               psav->MmioRegion.size);
3072#else
3073        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->MapBase,
3074                        SAVAGE_NEWMMIO_REGSIZE);
3075#endif
3076
3077        psav->MmioRegion.memory = NULL;
3078        psav->MapBase = 0;
3079        psav->BciMem = 0;
3080    }
3081
3082    if (psav->FbRegion.memory != NULL) {
3083#ifdef XSERVER_LIBPCIACCESS
3084        pci_device_unmap_range(psav->PciInfo,
3085                               psav->FbRegion.memory,
3086                               psav->FbRegion.size);
3087#else
3088        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->FbRegion.base,
3089                        psav->FbRegion.size);
3090#endif
3091    }
3092
3093    if (psav->ApertureRegion.memory != NULL) {
3094#ifdef XSERVER_LIBPCIACCESS
3095        pci_device_unmap_range(psav->PciInfo,
3096                               psav->ApertureRegion.memory,
3097                               psav->ApertureRegion.size);
3098#else
3099        xf86UnMapVidMem(pScrn->scrnIndex, (pointer)psav->ApertureRegion.base,
3100                        psav->ApertureRegion.size);
3101#endif
3102    }
3103
3104    psav->FbRegion.memory = NULL;
3105    psav->ApertureRegion.memory = NULL;
3106    psav->FBBase = 0;
3107    psav->FBStart = 0;
3108    psav->ApertureMap = 0;
3109
3110    return;
3111}
3112
3113#ifdef SAVAGEDRI
3114static Bool SavageCheckAvailableRamFor3D(ScrnInfoPtr pScrn)
3115{
3116    SavagePtr psav = SAVPTR(pScrn);
3117    int cpp = pScrn->bitsPerPixel / 8;
3118    int tiledBufferSize, RamNeededFor3D;
3119
3120    if (cpp == 2) {
3121        tiledBufferSize = ((pScrn->virtualX+63)/64)*((pScrn->virtualY+15)/16) * 2048;
3122    } else {
3123        tiledBufferSize = ((pScrn->virtualX+31)/32)*((pScrn->virtualY+15)/16) * 2048;
3124    }
3125
3126    RamNeededFor3D = 4096 + /* hw cursor*/
3127                     psav->cobSize + /*COB*/
3128                     tiledBufferSize + /* front buffer */
3129                     tiledBufferSize + /* back buffer */
3130                     tiledBufferSize; /* depth buffer */
3131
3132    xf86DrvMsg(pScrn->scrnIndex,X_INFO,
3133		"%d kB of Videoram needed for 3D; %d kB of Videoram available\n",
3134		RamNeededFor3D/1024, psav->videoRambytes/1024);
3135
3136    if (RamNeededFor3D <= psav->videoRambytes) {
3137        xf86DrvMsg(pScrn->scrnIndex,X_INFO,"Sufficient Videoram available for 3D\n");
3138	return TRUE;
3139    } else {
3140        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"Insufficient Videoram available for 3D -- "
3141					"Try a lower color depth or smaller desktop.  "
3142			"For integrated savages try increasing the videoram in the BIOS.\n");
3143	return FALSE;
3144    }
3145}
3146#endif
3147
3148static void SavageInitStatus(ScrnInfoPtr pScrn)
3149{
3150    SavagePtr psav = SAVPTR(pScrn);
3151
3152    switch( psav->Chipset ) {
3153	case S3_SAVAGE3D:
3154	case S3_SAVAGE_MX:
3155	    psav->WaitQueue	= WaitQueue3D;
3156	    psav->WaitIdle	= WaitIdle3D;
3157	    psav->WaitIdleEmpty	= WaitIdleEmpty3D;
3158	    psav->bciUsedMask   = 0x1ffff;
3159	    psav->eventStatusReg= 1;
3160	    break;
3161
3162	case S3_SAVAGE4:
3163	case S3_PROSAVAGE:
3164	case S3_SUPERSAVAGE:
3165	case S3_PROSAVAGEDDR:
3166	case S3_TWISTER:
3167	    psav->WaitQueue	= WaitQueue4;
3168	    psav->WaitIdle	= WaitIdle4;
3169	    psav->WaitIdleEmpty	= WaitIdleEmpty4;
3170	    psav->bciUsedMask   = 0x1fffff;
3171	    psav->eventStatusReg= 1;
3172	    break;
3173
3174	case S3_SAVAGE2000:
3175	    psav->WaitQueue	= WaitQueue2K;
3176	    psav->WaitIdle	= WaitIdle2K;
3177	    psav->WaitIdleEmpty	= WaitIdleEmpty2K;
3178	    psav->bciUsedMask   = 0xfffff;
3179	    psav->eventStatusReg= 2;
3180	    break;
3181    }
3182}
3183
3184static void SavageInitShadowStatus(ScrnInfoPtr pScrn)
3185{
3186    SavagePtr psav = SAVPTR(pScrn);
3187
3188    psav->ShadowStatus = psav->ConfigShadowStatus;
3189
3190    SavageInitStatus(pScrn);
3191
3192    if( psav->ShadowStatus ) {
3193	psav->ShadowPhysical =
3194	    psav->FbRegion.base + psav->CursorKByte*1024 + 4096 - 32;
3195
3196	psav->ShadowVirtual = (CARD32 *)
3197	    (psav->FBBase + psav->CursorKByte*1024 + 4096 - 32);
3198
3199	xf86DrvMsg( pScrn->scrnIndex, X_PROBED,
3200		    "Shadow area physical %08lx, linear %p\n",
3201		    psav->ShadowPhysical, (void *)psav->ShadowVirtual );
3202
3203	psav->WaitQueue = ShadowWaitQueue;
3204	psav->WaitIdle = ShadowWait;
3205	psav->WaitIdleEmpty = ShadowWait;
3206    }
3207
3208    if( psav->Chipset == S3_SAVAGE2000 )
3209	psav->dwBCIWait2DIdle = 0xc0040000;
3210    else
3211	psav->dwBCIWait2DIdle = 0xc0020000;
3212}
3213
3214static Bool SavageScreenInit(SCREEN_INIT_ARGS_DECL)
3215{
3216    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
3217    SavagePtr psav;
3218    EntityInfoPtr pEnt;
3219    int ret;
3220    int colormapFlags;
3221
3222    TRACE(("SavageScreenInit()\n"));
3223
3224    psav = SAVPTR(pScrn);
3225
3226    pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
3227    if (!psav->pVbe)
3228	psav->pVbe = VBEInit(NULL, pEnt->index);
3229
3230    SavageEnableMMIO(pScrn);
3231
3232    if (!SavageMapMem(pScrn))
3233	return FALSE;
3234
3235    psav->FBStart2nd = 0;
3236
3237    if (psav->overlayDepth) {
3238	if ((pScrn->virtualX * pScrn->virtualY *
3239	     (DEPTH_BPP(DEPTH_2ND(pScrn))) >> 3)
3240	     > (psav->CursorKByte * 1024))
3241	    xf86DrvMsg(pScrn->scrnIndex,X_WARNING,
3242		       "Not enough memory for overlay mode: disabling\n");
3243	else psav->FBStart2nd  = psav->FBStart
3244		 + ((pScrn->virtualX * pScrn->virtualY + 0xff) & ~0xff);
3245
3246    }
3247
3248    SavageInitShadowStatus(pScrn);
3249    psav->ShadowCounter = 0;
3250
3251    SavageSave(pScrn);
3252
3253    vgaHWBlankScreen(pScrn, TRUE);
3254
3255#ifdef SAVAGEDRI
3256    if (!xf86ReturnOptValBool(psav->Options, OPTION_DRI, TRUE)) {
3257	psav->directRenderingEnabled = FALSE;
3258	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3259		   "Direct rendering forced off\n");
3260    } else if (psav->IsSecondary) {
3261	psav->directRenderingEnabled = FALSE;
3262    } else if (xf86IsEntityShared(psav->pEnt->index)) {
3263	    /* Xinerama has sync problem with DRI, disable it for now */
3264	    psav->directRenderingEnabled = FALSE;
3265	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3266			"Direct Rendering Disabled -- "
3267			"Dual-head configuration is not working with "
3268			"DRI at present.\n");
3269    } else if (/*!psav->bTiled*/psav->bDisableTile) {
3270            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3271	    		"Direct Rendering requires a tiled framebuffer -- "
3272			"Set Option \"DisableTile\" \"false\"\n");
3273    } else if (psav->cobSize == 0) {
3274            xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3275	    		"Direct Rendering requires the COB -- "
3276			"Set Option \"DisableCOB\" \"false\"\n");
3277    } else if (((psav->Chipset == S3_TWISTER)
3278        || (psav->Chipset == S3_PROSAVAGE)
3279        || (psav->Chipset == S3_SAVAGE4)
3280        || (psav->Chipset == S3_SAVAGE_MX)
3281	|| (psav->Chipset == S3_SAVAGE3D)
3282	|| (psav->Chipset == S3_SUPERSAVAGE)
3283        || (psav->Chipset == S3_PROSAVAGEDDR))
3284	&& (!psav->NoAccel)
3285	&& (SavageCheckAvailableRamFor3D(pScrn))) {
3286        /* Setup DRI after visuals have been established */
3287        psav->directRenderingEnabled = SAVAGEDRIScreenInit(pScreen);
3288	/* If DRI init failed, reset shadow status. */
3289	if (!psav->directRenderingEnabled &&
3290	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3291	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3292	    SavageInitShadowStatus(pScrn);
3293	}
3294	/* If shadow status was enabled for DRI, hook up the shadow
3295	 * waiting functions now. */
3296	else if (psav->ShadowStatus && !psav->ConfigShadowStatus) {
3297	    psav->WaitQueue = ShadowWaitQueue;
3298	    psav->WaitIdle = ShadowWait;
3299	    psav->WaitIdleEmpty = ShadowWait;
3300	}
3301    } else
3302        psav->directRenderingEnabled = FALSE;
3303
3304    if(psav->directRenderingEnabled) {
3305        xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"DRI is enabled\n");
3306    }
3307    else {
3308        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"DRI isn't enabled\n");
3309    }
3310#endif
3311
3312    if (!SavageModeInit(pScrn, pScrn->currentMode))
3313	return FALSE;
3314
3315    miClearVisualTypes();
3316
3317    {
3318 	int visual;
3319
3320 	visual = ((psav->FBStart2nd && pScrn->bitsPerPixel > 8)
3321		   || pScrn->bitsPerPixel == 16) ? TrueColorMask
3322	    : miGetDefaultVisualMask(DEPTH_BPP(pScrn->depth));
3323 	if (!miSetVisualTypes(pScrn->depth, visual,
3324  			      pScrn->rgbBits, pScrn->defaultVisual))
3325  	    return FALSE;
3326
3327 	if (psav->FBStart2nd) {/* we have overlay */
3328 	    visual = psav->overlayDepth > 8 ? TrueColorMask :
3329 		miGetDefaultVisualMask(DEPTH_BPP(psav->overlayDepth));
3330 	    if (!miSetVisualTypes(psav->overlayDepth, visual,
3331 				  psav->overlayDepth > 8 ? 8 : 6,
3332 				  pScrn->defaultVisual))
3333 		return FALSE;
3334 	}
3335     }
3336     if (!miSetPixmapDepths ())
3337	 return FALSE;
3338
3339    ret = SavageInternalScreenInit(pScreen);
3340    if (!ret)
3341	return FALSE;
3342
3343    xf86SetBlackWhitePixels(pScreen);
3344
3345    {
3346	VisualPtr visual;
3347	visual = pScreen->visuals + pScreen->numVisuals;
3348	while (--visual >= pScreen->visuals) {
3349	    if ((visual->class | DynamicClass) == DirectColor
3350		&& visual->nplanes > MAX_PSEUDO_DEPTH) {
3351		if (visual->nplanes == pScrn->depth) {
3352		    visual->offsetRed = pScrn->offset.red;
3353		    visual->offsetGreen = pScrn->offset.green;
3354		    visual->offsetBlue = pScrn->offset.blue;
3355		    visual->redMask = pScrn->mask.red;
3356		    visual->greenMask = pScrn->mask.green;
3357		    visual->blueMask = pScrn->mask.blue;
3358		} else if (visual->offsetRed > 8
3359			   || visual->offsetGreen > 8
3360			   || visual->offsetBlue > 8) {
3361	/*
3362	 * mi has set these wrong. fix it here -- we cannot use pScrn
3363	 * as this is set up for the default depth 8.
3364	 */
3365		    int tmp;
3366		    int c_s = 0;
3367
3368		    tmp = visual->offsetBlue;
3369		    visual->offsetBlue = visual->offsetRed;
3370		    visual->offsetRed = tmp;
3371		    tmp = visual->blueMask;
3372		    visual->blueMask = visual->redMask;
3373		    visual->redMask = tmp;
3374		    switch (DEPTH_2ND(pScrn)) {
3375			case 16:
3376			    visual->offsetRed = 11;
3377			    visual->offsetGreen = 5;
3378			    visual->offsetBlue = 0;
3379			    visual->redMask = 0xF800;
3380			    visual->greenMask = 0x7E0;
3381			    visual->blueMask = 0x1F;
3382			    break;
3383			case 24:
3384			    visual->offsetRed = 16;
3385			    visual->offsetGreen = 8;
3386			    visual->offsetBlue = 0;
3387			    visual->redMask = 0xFF0000;
3388			    visual->greenMask = 0xFF00;
3389			    visual->blueMask = 0xFF;
3390			    c_s = 2;
3391			    break;
3392		    }
3393		    psav->overlay.redMask = visual->redMask;
3394		    psav->overlay.greenMask = visual->greenMask;
3395		    psav->overlay.blueMask = visual->blueMask;
3396		    psav->overlay.redShift = visual->offsetRed + c_s;
3397		    psav->overlay.greenShift = visual->offsetGreen + c_s;
3398		    psav->overlay.blueShift = visual->offsetBlue + c_s;
3399		}
3400	    }
3401	}
3402    }
3403
3404    /* must be after RGB ordering fixed */
3405    fbPictureInit (pScreen, 0, 0);
3406
3407    if( !psav->NoAccel ) {
3408	SavageInitAccel(pScreen);
3409    }
3410
3411    miInitializeBackingStore(pScreen);
3412    xf86SetBackingStore(pScreen);
3413
3414    if( !psav->shadowFB && !psav->useEXA )
3415	SavageDGAInit(pScreen);
3416
3417    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
3418
3419    if (psav->hwcursor)
3420	if (!SavageHWCursorInit(pScreen))
3421	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3422	       "Hardware cursor initialization failed\n");
3423
3424    if (psav->shadowFB) {
3425	RefreshAreaFuncPtr refreshArea = SavageRefreshArea;
3426
3427	if(psav->rotate) {
3428	    if (!psav->PointerMoved) {
3429		psav->PointerMoved = pScrn->PointerMoved;
3430		pScrn->PointerMoved = SavagePointerMoved;
3431	    }
3432
3433	    switch(pScrn->bitsPerPixel) {
3434	    case 8:	refreshArea = SavageRefreshArea8;	break;
3435	    case 16:	refreshArea = SavageRefreshArea16;	break;
3436	    case 24:	refreshArea = SavageRefreshArea24;	break;
3437	    case 32:	refreshArea = SavageRefreshArea32;	break;
3438	    }
3439	}
3440
3441	ShadowFBInit(pScreen, refreshArea);
3442    }
3443
3444    if (!miCreateDefColormap(pScreen))
3445	    return FALSE;
3446
3447    colormapFlags =  CMAP_RELOAD_ON_MODE_SWITCH
3448	| ((psav->FBStart2nd) ? 0 : CMAP_PALETTED_TRUECOLOR);
3449
3450    if (psav->Chipset == S3_SAVAGE4) {
3451        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPaletteSavage4,
3452				 NULL, colormapFlags ))
3453	    return FALSE;
3454    } else {
3455        if (!xf86HandleColormaps(pScreen, 256, pScrn->rgbBits, SavageLoadPalette, NULL,
3456				 colormapFlags ))
3457 	    return FALSE;
3458    }
3459
3460    vgaHWBlankScreen(pScrn, FALSE);
3461
3462    psav->CloseScreen = pScreen->CloseScreen;
3463    pScreen->SaveScreen = SavageSaveScreen;
3464    pScreen->CloseScreen = SavageCloseScreen;
3465
3466    if (xf86DPMSInit(pScreen, SavageDPMS, 0) == FALSE)
3467	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "DPMS initialization failed\n");
3468
3469#ifdef SAVAGEDRI
3470    if (psav->directRenderingEnabled) {
3471        /* complete the DRI setup.*/
3472        psav->directRenderingEnabled = SAVAGEDRIFinishScreenInit(pScreen);
3473	/* If DRI initialization failed, reset shadow status and
3474	 * reinitialize 2D engine. */
3475	if (!psav->directRenderingEnabled &&
3476	    psav->ShadowStatus != psav->ConfigShadowStatus) {
3477	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Resetting ShadowStatus.\n");
3478	    SavageInitShadowStatus(pScrn);
3479	    SavageInitialize2DEngine(pScrn);
3480	}
3481    }
3482    if (psav->directRenderingEnabled) {
3483        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Direct rendering enabled\n");
3484    } else {
3485        xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Direct rendering disabled\n");
3486    }
3487#endif
3488
3489    SavagePanningCheck(pScrn, pScrn->currentMode);
3490#ifdef XvExtension
3491    if( !psav->FBStart2nd && !psav->NoAccel  /*&& !SavagePanningCheck(pScrn)*/ ) {
3492	if (psav->IsSecondary)
3493            /* Xv should work on crtc2, but I haven't gotten there yet.  -- AGD */
3494	    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Xv currently disabled for crtc2.\n");
3495	else
3496	    SavageInitVideo( pScreen );
3497    }
3498#endif
3499
3500#ifdef SAVAGEDRI
3501    if ((psav->directRenderingEnabled) && (!psav->bDisableXvMC)) {
3502        if (SAVAGEInitMC(pScreen))
3503            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is enabled\n");
3504        else
3505            xf86DrvMsg(pScrn->scrnIndex,X_CONFIG,"XvMC is not enabled\n");
3506    }
3507
3508    if (!psav->directRenderingEnabled && psav->AGPforXv) {
3509        xf86DrvMsg(pScrn->scrnIndex,X_ERROR,"AGPforXV requires DRI to be enabled.\n");
3510	psav->AGPforXv = FALSE;
3511    }
3512#endif
3513
3514    if (serverGeneration == 1)
3515	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
3516
3517    return TRUE;
3518}
3519
3520
3521static int SavageInternalScreenInit(ScreenPtr pScreen)
3522{
3523    int ret = TRUE;
3524    ScrnInfoPtr pScrn;
3525    SavagePtr psav;
3526    int width, height, displayWidth;
3527    unsigned char *FBStart;
3528
3529    TRACE(("SavageInternalScreenInit()\n"));
3530
3531    pScrn = xf86ScreenToScrn(pScreen);
3532    psav = SAVPTR(pScrn);
3533
3534    displayWidth = pScrn->displayWidth;
3535
3536    if (psav->rotate) {
3537	height = pScrn->virtualX;
3538	width = pScrn->virtualY;
3539    } else {
3540	width = pScrn->virtualX;
3541	height = pScrn->virtualY;
3542    }
3543
3544
3545    if(psav->shadowFB) {
3546	psav->ShadowPitch = BitmapBytePad(pScrn->bitsPerPixel * width);
3547	psav->ShadowPtr = malloc(psav->ShadowPitch * height);
3548	displayWidth = psav->ShadowPitch / (pScrn->bitsPerPixel >> 3);
3549	FBStart = psav->ShadowPtr;
3550    } else {
3551	psav->ShadowPtr = NULL;
3552	FBStart = psav->FBStart;
3553    }
3554
3555    if (!psav->FBStart2nd) {
3556
3557        ret = fbScreenInit(pScreen, FBStart, width, height,
3558                           pScrn->xDpi, pScrn->yDpi,
3559                           psav->ulAperturePitch / (pScrn->bitsPerPixel >> 3), /*displayWidth,*/
3560                           pScrn->bitsPerPixel);
3561
3562    } else {
3563	FbOverlayScrPrivPtr pScrPriv;
3564	int Depth2nd = DEPTH_2ND(pScrn);
3565	if (!fbSetupScreen (pScreen, FBStart, width, height,
3566			    pScrn->xDpi, pScrn->yDpi, displayWidth, 8))
3567	    return FALSE;
3568	if (pScrn->depth == 8) {
3569	    ret = fbOverlayFinishScreenInit (pScreen, FBStart,
3570					     psav->FBStart2nd, width,
3571					     height,pScrn->xDpi, pScrn->yDpi,
3572					     displayWidth,displayWidth,
3573					     8, DEPTH_BPP(Depth2nd),
3574					     8, Depth2nd);
3575	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3576	    pScrPriv->layer[0].key = pScrn->colorKey;
3577	} else {
3578	    ret = fbOverlayFinishScreenInit (pScreen, psav->FBStart2nd,
3579					     FBStart,
3580					     width, height,pScrn->xDpi,
3581					     pScrn->yDpi,
3582					     displayWidth,displayWidth,
3583					     DEPTH_BPP(Depth2nd), 8,
3584					     Depth2nd, 8);
3585	    pScrPriv = fbOverlayGetScrPriv(pScreen);
3586	    pScrPriv->layer[1].key = pScrn->colorKey;
3587	}
3588    }
3589    return ret;
3590}
3591
3592
3593static int SavageGetRefresh(DisplayModePtr mode)
3594{
3595    int refresh = (mode->Clock * 1000) / (mode->HTotal * mode->VTotal);
3596    if (mode->Flags & V_INTERLACE)
3597	refresh *= 2.0;
3598    if (mode->Flags & V_DBLSCAN)
3599	refresh /= 2.0;
3600    if (mode->VScan > 1)
3601	refresh /= mode->VScan;
3602    return refresh;
3603}
3604
3605
3606static ModeStatus SavageValidMode(SCRN_ARG_TYPE arg, DisplayModePtr pMode,
3607				  Bool verbose, int flags)
3608{
3609    SCRN_INFO_PTR(arg);
3610    SavagePtr psav = SAVPTR(pScrn);
3611    int refresh;
3612
3613    TRACE(("SavageValidMode\n"));
3614
3615    /* We prohibit modes bigger than the LCD panel. */
3616    /* TODO We should do this only if the panel is active. */
3617
3618    if( psav->TvOn )
3619    {
3620	if( pMode->HDisplay > psav->TVSizeX )
3621	    return MODE_VIRTUAL_X;
3622
3623	if( pMode->VDisplay > psav->TVSizeY )
3624	    return MODE_VIRTUAL_Y;
3625
3626    }
3627
3628    if((psav->DisplayType == MT_LCD) &&
3629      ((pMode->HDisplay > psav->PanelX) ||
3630       (pMode->VDisplay > psav->PanelY)))
3631	    return MODE_PANEL;
3632
3633    if (psav->UseBIOS) {
3634	refresh = SavageGetRefresh(pMode);
3635        return (SavageMatchBiosMode(pScrn,pMode->HDisplay,
3636                                   pMode->VDisplay,
3637                                   refresh,NULL,NULL));
3638    }
3639
3640    return MODE_OK;
3641}
3642
3643static Bool SavageModeInit(ScrnInfoPtr pScrn, DisplayModePtr mode)
3644{
3645    vgaHWPtr hwp = VGAHWPTR(pScrn);
3646    SavagePtr psav = SAVPTR(pScrn);
3647    int width, dclk, i, j; /*, refresh; */
3648    unsigned int m, n, r;
3649    unsigned char tmp = 0;
3650    SavageRegPtr new = &psav->ModeReg;
3651    vgaRegPtr vganew = &hwp->ModeReg;
3652    int vgaCRIndex, vgaCRReg, vgaIOBase;
3653    int refresh;
3654    unsigned int newmode=0, newrefresh=0;
3655
3656    vgaIOBase = hwp->IOBase;
3657    vgaCRIndex = vgaIOBase + 4;
3658    vgaCRReg = vgaIOBase + 5;
3659
3660    TRACE(("SavageModeInit(%dx%d, %dkHz)\n",
3661	mode->HDisplay, mode->VDisplay, mode->Clock));
3662
3663#if 0
3664    ErrorF("Clock = %d, HDisplay = %d, HSStart = %d\n",
3665	    mode->Clock, mode->HDisplay, mode->HSyncStart);
3666    ErrorF("HSEnd = %d, HSkew = %d\n",
3667	    mode->HSyncEnd, mode->HSkew);
3668    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3669	    mode->VDisplay, mode->VSyncStart, mode->VSyncEnd);
3670    ErrorF("VTotal = %d\n",
3671	    mode->VTotal);
3672    ErrorF("HDisplay = %d, HSStart = %d\n",
3673	    mode->CrtcHDisplay, mode->CrtcHSyncStart);
3674    ErrorF("HSEnd = %d, HSkey = %d\n",
3675	    mode->CrtcHSyncEnd, mode->CrtcHSkew);
3676    ErrorF("VDisplay - %d, VSStart = %d, VSEnd = %d\n",
3677	    mode->CrtcVDisplay, mode->CrtcVSyncStart, mode->CrtcVSyncEnd);
3678    ErrorF("VTotal = %d\n",
3679	    mode->CrtcVTotal);
3680#endif
3681
3682    if (psav->IsSecondary) {
3683	refresh = SavageGetRefresh(mode);
3684
3685        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3686                            &newmode,&newrefresh);
3687	new->mode = newmode;
3688	new->refresh = newrefresh;
3689
3690        /* do it! */
3691        SavageWriteMode(pScrn, vganew, new, TRUE);
3692
3693        if (psav->FBStart2nd) {
3694	    SavageStreamsOn(pScrn);
3695	    SavageInitSecondaryStream(pScrn);
3696        }
3697
3698        SavageAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
3699	return TRUE;
3700    }
3701
3702
3703    if (pScrn->bitsPerPixel == 8)
3704	psav->HorizScaleFactor = 1;
3705    else if (pScrn->bitsPerPixel == 16)
3706	psav->HorizScaleFactor = 1;	/* I don't think we ever want 2 */
3707    else
3708	psav->HorizScaleFactor = 1;
3709
3710    if (psav->HorizScaleFactor == 2)
3711	if (!mode->CrtcHAdjusted) {
3712	    mode->CrtcHDisplay *= 2;
3713	    mode->CrtcHSyncStart *= 2;
3714	    mode->CrtcHSyncEnd *= 2;
3715	    mode->CrtcHBlankStart *= 2;
3716	    mode->CrtcHBlankEnd *= 2;
3717	    mode->CrtcHTotal *= 2;
3718	    mode->CrtcHSkew *= 2;
3719	    mode->CrtcHAdjusted = TRUE;
3720	}
3721
3722    if (!vgaHWInit(pScrn, mode))
3723	return FALSE;
3724
3725    new->mode = 0;
3726
3727    /* We need to set CR67 whether or not we use the BIOS. */
3728
3729    dclk = mode->Clock;
3730    new->CR67 = 0x00;
3731
3732    switch( pScrn->depth ) {
3733    case 8:
3734	if( (psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000) )
3735	    new->CR67 = 0x10;	/* 8bpp, 2 pixels/clock */
3736	else
3737	    new->CR67 = 0x00;	/* 8bpp, 1 pixel/clock */
3738	break;
3739    case 15:
3740	if(
3741	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3742	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3743	)
3744	    new->CR67 = 0x30;	/* 15bpp, 2 pixel/clock */
3745	else
3746	    new->CR67 = 0x20;	/* 15bpp, 1 pixels/clock */
3747	break;
3748    case 16:
3749	if(
3750	    S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ||
3751	    ((psav->Chipset == S3_SAVAGE2000) && (dclk >= 230000))
3752	)
3753	    new->CR67 = 0x50;	/* 16bpp, 2 pixel/clock */
3754	else
3755	    new->CR67 = 0x40;	/* 16bpp, 1 pixels/clock */
3756	break;
3757    case 24:
3758	if (psav->primStreamBpp == 24 )
3759	    new->CR67 = 0x70;
3760	else
3761	    new->CR67 = 0xd0;
3762	break;
3763    }
3764
3765
3766    if( psav->UseBIOS ) {
3767	int refresh;
3768	unsigned int newmode=0, newrefresh=0;
3769
3770	refresh = SavageGetRefresh(mode);
3771
3772        SavageMatchBiosMode(pScrn,mode->HDisplay,mode->VDisplay,refresh,
3773                            &newmode,&newrefresh);
3774	new->mode = newmode;
3775	new->refresh = newrefresh;
3776    }
3777
3778    if( !new->mode ) {
3779	/*
3780	 * Either BIOS use is disabled, or we failed to find a suitable
3781	 * match.  Fall back to traditional register-crunching.
3782	 */
3783
3784	VGAOUT8(vgaCRIndex, 0x3a);
3785	tmp = VGAIN8(vgaCRReg);
3786	if (psav->pci_burst)
3787	    new->CR3A = (tmp & 0x7f) | 0x15;
3788	else
3789	    new->CR3A = tmp | 0x95;
3790
3791	new->CR53 = 0x00;
3792	new->CR31 = 0x8c;
3793	new->CR66 = 0x89;
3794
3795	VGAOUT8(vgaCRIndex, 0x58);
3796	new->CR58 = VGAIN8(vgaCRReg) & 0x80;
3797	new->CR58 |= 0x13;
3798
3799#if 0
3800	VGAOUT8(vgaCRIndex, 0x55);
3801	new->CR55 = VGAIN8(vgaCRReg);
3802	if (psav->hwcursor)
3803		new->CR55 |= 0x10;
3804#endif
3805
3806	new->SR15 = 0x03 | 0x80;
3807	new->SR18 = 0x00;
3808
3809
3810	/* enable gamma correction */
3811	if( pScrn->depth == 24 )
3812	    new->SR1B = 0x18;
3813	else
3814	    new->SR1B = 0x00;
3815
3816	/* set 8-bit CLUT */
3817	new->SR1B |= 0x10;
3818
3819	new->CR43 = new->CR45 = new->CR65 = 0x00;
3820
3821	VGAOUT8(vgaCRIndex, 0x40);
3822	new->CR40 = VGAIN8(vgaCRReg) & ~0x01;
3823
3824	new->MMPR0 = 0x010400;
3825	new->MMPR1 = 0x00;
3826	new->MMPR2 = 0x0808;
3827	new->MMPR3 = 0x08080810;
3828
3829	if (psav->fifo_aggressive || psav->fifo_moderate ||
3830	    psav->fifo_conservative) {
3831		new->MMPR1 = 0x0200;
3832		new->MMPR2 = 0x1808;
3833		new->MMPR3 = 0x08081810;
3834	}
3835
3836	if (psav->MCLK <= 0) {
3837		new->SR10 = 255;
3838		new->SR11 = 255;
3839	}
3840
3841	psav->NeedSTREAMS = FALSE;
3842
3843	SavageCalcClock(dclk, 1, 1, 127, 0, 4, 180000, 360000,
3844			&m, &n, &r);
3845	new->SR12 = (r << 6) | (n & 0x3f);
3846	new->SR13 = m & 0xff;
3847	new->SR29 = (r & 4) | (m & 0x100) >> 5 | (n & 0x40) >> 2;
3848
3849	if (psav->fifo_moderate) {
3850	    if (psav->primStreamBpp < 24)
3851		new->MMPR0 -= 0x8000;
3852	    else
3853		new->MMPR0 -= 0x4000;
3854	} else if (psav->fifo_aggressive) {
3855	    if (psav->primStreamBpp < 24)
3856		new->MMPR0 -= 0xc000;
3857	    else
3858		new->MMPR0 -= 0x6000;
3859	}
3860
3861	if (mode->Flags & V_INTERLACE)
3862	    new->CR42 = 0x20;
3863	else
3864	    new->CR42 = 0x00;
3865
3866	new->CR34 = 0x10;
3867
3868	i = ((((mode->CrtcHTotal >> 3) - 5) & 0x100) >> 8) |
3869	    ((((mode->CrtcHDisplay >> 3) - 1) & 0x100) >> 7) |
3870	    ((((mode->CrtcHSyncStart >> 3) - 1) & 0x100) >> 6) |
3871	    ((mode->CrtcHSyncStart & 0x800) >> 7);
3872
3873	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 64)
3874	    i |= 0x08;
3875	if ((mode->CrtcHSyncEnd >> 3) - (mode->CrtcHSyncStart >> 3) > 32)
3876	    i |= 0x20;
3877	j = (vganew->CRTC[0] + ((i & 0x01) << 8) +
3878	     vganew->CRTC[4] + ((i & 0x10) << 4) + 1) / 2;
3879	if (j - (vganew->CRTC[4] + ((i & 0x10) << 4)) < 4) {
3880	    if (vganew->CRTC[4] + ((i & 0x10) << 4) + 4 <=
3881	        vganew->CRTC[0] + ((i & 0x01) << 8))
3882		j = vganew->CRTC[4] + ((i & 0x10) << 4) + 4;
3883	    else
3884		j = vganew->CRTC[0] + ((i & 0x01) << 8) + 1;
3885	}
3886
3887	new->CR3B = j & 0xff;
3888	i |= (j & 0x100) >> 2;
3889	new->CR3C = (vganew->CRTC[0] + ((i & 0x01) << 8))  / 2 ;
3890	new->CR5D = i;
3891	new->CR5E = (((mode->CrtcVTotal - 2) & 0x400) >> 10) |
3892		    (((mode->CrtcVDisplay - 1) & 0x400) >> 9) |
3893		    (((mode->CrtcVSyncStart) & 0x400) >> 8) |
3894		    (((mode->CrtcVSyncStart) & 0x400) >> 6) | 0x40;
3895	width = (pScrn->displayWidth * (psav->primStreamBpp / 8)) >> 3;
3896	new->CR91 = vganew->CRTC[19] = 0xff & width;
3897	new->CR51 = (0x300 & width) >> 4;
3898	new->CR90 = 0x80 | (width >> 8);
3899	vganew->MiscOutReg |= 0x0c;
3900
3901	/* Set frame buffer description. */
3902
3903	if (psav->primStreamBpp <= 8)
3904	    new->CR50 = 0;
3905	else if (psav->primStreamBpp <= 16)
3906	    new->CR50 = 0x10;
3907	else
3908	    new->CR50 = 0x30;
3909
3910	if (pScrn->displayWidth == 640)
3911	    new->CR50 |= 0x40;
3912	else if (pScrn->displayWidth == 800)
3913	    new->CR50 |= 0x80;
3914	else if (pScrn->displayWidth == 1024)
3915	    new->CR50 |= 0x00;
3916	else if (pScrn->displayWidth == 1152)
3917	    new->CR50 |= 0x01;
3918	else if (pScrn->displayWidth == 1280)
3919	    new->CR50 |= 0xc0;
3920	else if (pScrn->displayWidth == 1600)
3921	    new->CR50 |= 0x81;
3922	else
3923	    new->CR50 |= 0xc1;	/* Use GBD */
3924
3925	if( S3_SAVAGE_MOBILE_SERIES(psav->Chipset) )
3926	    new->CR33 = 0x00;
3927	else
3928	    new->CR33 = 0x08;
3929
3930	vganew->CRTC[0x17] = 0xeb;
3931
3932	new->CR67 |= 1;
3933
3934	VGAOUT8(vgaCRIndex, 0x36);
3935	new->CR36 = VGAIN8(vgaCRReg);
3936	VGAOUT8(vgaCRIndex, 0x68);
3937	new->CR68 = VGAIN8(vgaCRReg);
3938
3939	new->CR69 = 0;
3940	VGAOUT8(vgaCRIndex, 0x6f);
3941	new->CR6F = VGAIN8(vgaCRReg);
3942	VGAOUT8(vgaCRIndex, 0x86);
3943	new->CR86 = VGAIN8(vgaCRReg) | 0x08;
3944	VGAOUT8(vgaCRIndex, 0x88);
3945	new->CR88 = VGAIN8(vgaCRReg) | DISABLE_BLOCK_WRITE_2D;
3946	VGAOUT8(vgaCRIndex, 0xb0);
3947	new->CRB0 = VGAIN8(vgaCRReg) | 0x80;
3948    }
3949
3950    pScrn->vtSema = TRUE;
3951
3952    /* do it! */
3953    SavageWriteMode(pScrn, vganew, new, TRUE);
3954
3955    if (psav->FBStart2nd) {
3956        SavageStreamsOn(pScrn);
3957	SavageInitSecondaryStream(pScrn);
3958    }
3959
3960    SavageAdjustFrame(ADJUST_FRAME_ARGS(pScrn, pScrn->frameX0, pScrn->frameY0));
3961
3962    return TRUE;
3963}
3964
3965
3966static Bool SavageCloseScreen(CLOSE_SCREEN_ARGS_DECL)
3967{
3968    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
3969    vgaHWPtr hwp = VGAHWPTR(pScrn);
3970    SavagePtr psav = SAVPTR(pScrn);
3971    vgaRegPtr vgaSavePtr = &hwp->SavedReg;
3972    SavageRegPtr SavageSavePtr = &psav->SavedReg;
3973
3974    TRACE(("SavageCloseScreen\n"));
3975
3976#ifdef SAVAGEDRI
3977    if (psav->directRenderingEnabled) {
3978        SAVAGEDRICloseScreen(pScreen);
3979	/* reset shadow values */
3980	SavageInitShadowStatus(pScrn);
3981        psav->directRenderingEnabled=FALSE;
3982    }
3983#endif
3984
3985    if (psav->EXADriverPtr) {
3986	exaDriverFini(pScreen);
3987	psav->EXADriverPtr = NULL;
3988    }
3989
3990#ifdef HAVE_XAA_H
3991    if( psav->AccelInfoRec ) {
3992        XAADestroyInfoRec( psav->AccelInfoRec );
3993	psav->AccelInfoRec = NULL;
3994    }
3995#endif
3996
3997    if( psav->DGAModes ) {
3998	free( psav->DGAModes );
3999	psav->DGAModes = NULL;
4000	psav->numDGAModes = 0;
4001    }
4002
4003    if (pScrn->vtSema) {
4004        if (psav->FBStart2nd)
4005	    SavageStreamsOff(pScrn);
4006	SavageWriteMode(pScrn, vgaSavePtr, SavageSavePtr, FALSE);
4007        SavageResetStreams(pScrn);
4008	vgaHWLock(hwp);
4009	SavageUnmapMem(pScrn, 0);
4010    }
4011
4012    if (psav->pVbe)
4013      vbeFree(psav->pVbe);
4014    psav->pVbe = NULL;
4015
4016    pScrn->vtSema = FALSE;
4017    pScreen->CloseScreen = psav->CloseScreen;
4018
4019    return (*pScreen->CloseScreen)(CLOSE_SCREEN_ARGS);
4020}
4021
4022
4023static Bool SavageSaveScreen(ScreenPtr pScreen, int mode)
4024{
4025    ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
4026
4027    TRACE(("SavageSaveScreen(0x%x)\n", mode));
4028
4029    if( pScrn->vtSema && SAVPTR(pScrn)->hwcursor && SAVPTR(pScrn)->hwc_on )
4030    {
4031	if( xf86IsUnblank(mode) )
4032	    SavageShowCursor( pScrn );
4033	else
4034	    SavageHideCursor( pScrn );
4035	SAVPTR(pScrn)->hwc_on = TRUE; /*restore */
4036    }
4037
4038    return vgaHWSaveScreen(pScreen, mode);
4039}
4040
4041void SavageAdjustFrame(ADJUST_FRAME_ARGS_DECL)
4042{
4043    SCRN_INFO_PTR(arg);
4044    SavagePtr psav = SAVPTR(pScrn);
4045
4046    if (psav->IsSecondary) {
4047	SavageDoAdjustFrame(pScrn, x, y, TRUE);
4048    } else {
4049	SavageDoAdjustFrame(pScrn, x, y, FALSE);
4050    }
4051
4052}
4053
4054void
4055SavageDoAdjustFrame(ScrnInfoPtr pScrn, int x, int y, int crtc2)
4056{
4057    SavagePtr psav = SAVPTR(pScrn);
4058    int address=0,top=0,left=0,tile_height,tile_size;
4059
4060    TRACE(("SavageDoAdjustFrame(%d,%d,%d)\n", x, y, crtc2));
4061
4062    if (psav->Chipset == S3_SAVAGE2000) {
4063        tile_height = TILEHEIGHT_2000; /* 32 */
4064        tile_size = TILE_SIZE_BYTE_2000; /* 4096 */
4065    } else {
4066        tile_height = TILEHEIGHT; /* 16 */
4067        tile_size = TILE_SIZE_BYTE; /* 2048 */
4068    }
4069
4070    if (!psav->bTiled) {
4071        left = x - x % 64;
4072        top = y;
4073        address = (top * psav->lDelta) + left * (pScrn->bitsPerPixel >> 3);
4074        address = (address >> 5) << 5;
4075    } else {
4076        top = y - y % tile_height;
4077        if (pScrn->bitsPerPixel == 16) {
4078            left = x - x % TILEWIDTH_16BPP;
4079            address = top * psav->lDelta + left * tile_size / TILEWIDTH_16BPP;
4080        } else if (pScrn->bitsPerPixel == 32) {
4081            left = x - x % TILEWIDTH_32BPP;
4082            address = top * psav->lDelta + left * tile_size / TILEWIDTH_32BPP;
4083        }
4084    }
4085
4086    address += pScrn->fbOffset;
4087
4088    if (psav->Chipset == S3_SAVAGE_MX) {
4089	if (!crtc2) {
4090            OUTREG32(PRI_STREAM_FBUF_ADDR0, address & 0xFFFFFFFC);
4091            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFFC);/* IGA1 */
4092        } else {
4093            OUTREG32(PRI_STREAM2_FBUF_ADDR0, address & 0xFFFFFFFC);/* IGA2 */
4094            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFFC);
4095	}
4096    } else if (psav->Chipset == S3_SUPERSAVAGE) {
4097	if (!crtc2) {
4098            /* IGA1 */
4099            OUTREG32(PRI_STREAM_FBUF_ADDR0, 0x80000000);
4100            OUTREG32(PRI_STREAM_FBUF_ADDR1, address & 0xFFFFFFF8);
4101        } else {
4102            /* IGA2 */
4103            OUTREG32(PRI_STREAM2_FBUF_ADDR0, ((address & 0xFFFFFFF8) | 0x80000000));
4104            OUTREG32(PRI_STREAM2_FBUF_ADDR1, address & 0xFFFFFFF8);
4105	}
4106    } else if (psav->Chipset == S3_SAVAGE2000) {
4107        /*  certain Y values seems to cause havoc, not sure why */
4108        OUTREG32(PRI_STREAM_FBUF_ADDR0, (address & 0xFFFFFFF8));
4109        OUTREG32(PRI_STREAM2_FBUF_ADDR0, (address & 0xFFFFFFF8));
4110    } else {
4111        OUTREG32(PRI_STREAM_FBUF_ADDR0,address |  0xFFFFFFFC);
4112        OUTREG32(PRI_STREAM_FBUF_ADDR1,address |  0x80000000);
4113    }
4114
4115    return;
4116}
4117
4118Bool SavageSwitchMode(SWITCH_MODE_ARGS_DECL)
4119{
4120    SCRN_INFO_PTR(arg);
4121    SavagePtr psav = SAVPTR(pScrn);
4122    Bool success;
4123
4124    TRACE(("SavageSwitchMode\n"));
4125
4126    if (psav->FBStart2nd || (psav->videoFlags & VF_STREAMS_ON))
4127        SavageStreamsOff(pScrn);
4128
4129    success = SavageModeInit(pScrn, mode);
4130
4131    /* switching mode on primary will reset secondary.  it needs to be reset as well*/
4132    if (psav->IsPrimary) {
4133        DevUnion* pPriv;
4134        SavageEntPtr pSavEnt;
4135        pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
4136              gSavageEntityIndex);
4137        pSavEnt = pPriv->ptr;
4138        SavageModeInit(pSavEnt->pSecondaryScrn, pSavEnt->pSecondaryScrn->currentMode);
4139    }
4140    SavagePanningCheck(pScrn, mode);
4141
4142    return success;
4143}
4144
4145
4146void SavageEnableMMIO(ScrnInfoPtr pScrn)
4147{
4148    vgaHWPtr hwp = VGAHWPTR(pScrn);
4149    SavagePtr psav = SAVPTR(pScrn);
4150    int vgaCRIndex, vgaCRReg;
4151    unsigned char val;
4152
4153    TRACE(("SavageEnableMMIO\n"));
4154
4155    vgaHWSetStdFuncs(hwp);
4156    vgaHWSetMmioFuncs(hwp, psav->MapBase, 0x8000);
4157    val = VGAIN8(0x3c3);
4158    VGAOUT8(0x3c3, val | 0x01);
4159    val = VGAIN8(VGA_MISC_OUT_R);
4160    VGAOUT8(VGA_MISC_OUT_W, val | 0x01);
4161    vgaCRIndex = psav->vgaIOBase + 4;
4162    vgaCRReg = psav->vgaIOBase + 5;
4163
4164    if( psav->Chipset >= S3_SAVAGE4 )
4165    {
4166	VGAOUT8(vgaCRIndex, 0x40);
4167	val = VGAIN8(vgaCRReg);
4168	VGAOUT8(vgaCRReg, val | 1);
4169    }
4170
4171    return;
4172}
4173
4174
4175void SavageDisableMMIO(ScrnInfoPtr pScrn)
4176{
4177    vgaHWPtr hwp = VGAHWPTR(pScrn);
4178    SavagePtr psav = SAVPTR(pScrn);
4179    int vgaCRIndex, vgaCRReg;
4180    unsigned char val;
4181
4182    TRACE(("SavageDisableMMIO\n"));
4183
4184    vgaCRIndex = psav->vgaIOBase + 4;
4185    vgaCRReg = psav->vgaIOBase + 5;
4186
4187    if( psav->Chipset >= S3_SAVAGE4 )
4188    {
4189	VGAOUT8(vgaCRIndex, 0x40);
4190	val = VGAIN8(vgaCRReg);
4191	VGAOUT8(vgaCRReg, val | 1);
4192    }
4193
4194    vgaHWSetStdFuncs(hwp);
4195
4196    return;
4197}
4198
4199void SavageLoadPalette(ScrnInfoPtr pScrn, int numColors, int *indicies,
4200		       LOCO *colors, VisualPtr pVisual)
4201{
4202    SavagePtr psav = SAVPTR(pScrn);
4203    int i, index;
4204    int updateKey = -1;
4205    unsigned char byte = 0;
4206
4207    /* choose CLUT */
4208    if (psav->IsPrimary) {
4209	/* enable CLUT 1 */
4210        VGAOUT8(0x3c4, 0x21);
4211        byte = VGAIN8(0x3c5);
4212        VGAOUT8(0x3c5, (byte & ~0x01));
4213	/* select CLUT 1 */
4214        VGAOUT8(0x3c4, 0x47);
4215        byte = VGAIN8(0x3c5);
4216        VGAOUT8(0x3c5, (byte & ~0x03) | 0x01); /* CLUT 1 */
4217    } else if (psav->IsSecondary) {
4218	/* enable CLUT 2 */
4219        VGAOUT8(0x3c4, 0x21);
4220        byte = VGAIN8(0x3c5);
4221        VGAOUT8(0x3c5, (byte & ~0x10));
4222	/* select CLUT 2 */
4223        VGAOUT8(0x3c4, 0x47);
4224        byte = VGAIN8(0x3c5);
4225        VGAOUT8(0x3c5, (byte & ~0x03) | 0x02); /* CLUT 2 */
4226    }
4227
4228    for (i=0; i<numColors; i++) {
4229	index = indicies[i];
4230	if (index == pScrn->colorKey) updateKey = index;
4231	VGAOUT8(0x3c8, index);
4232	VGAOUT8(0x3c9, colors[index].red);
4233	VGAOUT8(0x3c9, colors[index].green);
4234	VGAOUT8(0x3c9, colors[index].blue);
4235    }
4236
4237    /* restore saved CLUT index value */
4238    if (psav->IsPrimary || psav->IsSecondary) {
4239        VGAOUT8(0x3c4, 0x47);
4240        VGAOUT8(0x3c5, byte);
4241    }
4242
4243    if (updateKey != -1)
4244	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4245			colors[updateKey].blue);
4246}
4247
4248#define Shift(v,d)  ((d) < 0 ? ((v) >> (-d)) : ((v) << (d)))
4249
4250static void
4251SavageUpdateKey(ScrnInfoPtr pScrn, int r, int g, int b)
4252{
4253    ScreenPtr pScreen;
4254    SavagePtr psav = SAVPTR(pScrn);
4255    FbOverlayScrPrivPtr pScrOvlPriv;
4256    CARD32 key;
4257    int ul = 0, ol = 1;
4258
4259    if (pScrn->depth != 8) {
4260	ul = 1;
4261	ol = 0;
4262    }
4263    if (!(pScreen = pScrn->pScreen)
4264	|| !psav->FBStart2nd
4265	|| !(pScrOvlPriv = fbOverlayGetScrPriv(pScreen)))
4266	return;
4267    key = ((Shift(r,psav->overlay.redShift) & psav->overlay.redMask)
4268	   | (Shift(g,psav->overlay.greenShift) & psav->overlay.greenMask)
4269	   | (Shift(b,psav->overlay.blueShift) & psav->overlay.blueMask));
4270    if (pScrOvlPriv->layer[ol].key != key) {
4271	pScrOvlPriv->layer[ol].key = key;
4272	(*pScrOvlPriv->PaintKey) (&pScrOvlPriv->layer[ol].u.run.pixmap->drawable,
4273				  &pScrOvlPriv->layer[ul].u.run.region,
4274				  pScrOvlPriv->layer[ol].key, ol);
4275    }
4276}
4277
4278#if 0
4279#define inStatus1() (hwp->readST01( hwp ))
4280#endif
4281
4282void SavageLoadPaletteSavage4(ScrnInfoPtr pScrn, int numColors, int *indicies,
4283		       LOCO *colors, VisualPtr pVisual)
4284{
4285    SavagePtr psav = SAVPTR(pScrn);
4286    int i, index;
4287    int updateKey = -1;
4288
4289    VerticalRetraceWait();
4290
4291    for (i=0; i<numColors; i++) {
4292          if (!(inStatus1() & 0x08))
4293  	    VerticalRetraceWait();
4294	index = indicies[i];
4295	VGAOUT8(0x3c8, index);
4296	VGAOUT8(0x3c9, colors[index].red);
4297	VGAOUT8(0x3c9, colors[index].green);
4298	VGAOUT8(0x3c9, colors[index].blue);
4299	if (index == pScrn->colorKey) updateKey = index;
4300    }
4301    if (updateKey != -1)
4302	SavageUpdateKey(pScrn, colors[updateKey].red, colors[updateKey].green,
4303			colors[updateKey].blue);
4304}
4305
4306static void SavageCalcClock(long freq, int min_m, int min_n1, int max_n1,
4307			   int min_n2, int max_n2, long freq_min,
4308			   long freq_max, unsigned int *mdiv,
4309			   unsigned int *ndiv, unsigned int *r)
4310{
4311    double ffreq, ffreq_min, ffreq_max;
4312    double div, diff, best_diff;
4313    unsigned int m;
4314    unsigned char n1, n2, best_n1=16+2, best_n2=2, best_m=125+2;
4315
4316    ffreq = freq / 1000.0 / BASE_FREQ;
4317    ffreq_max = freq_max / 1000.0 / BASE_FREQ;
4318    ffreq_min = freq_min / 1000.0 / BASE_FREQ;
4319
4320    if (ffreq < ffreq_min / (1 << max_n2)) {
4321	    ErrorF("invalid frequency %1.3f Mhz\n",
4322		   ffreq*BASE_FREQ);
4323	    ffreq = ffreq_min / (1 << max_n2);
4324    }
4325    if (ffreq > ffreq_max / (1 << min_n2)) {
4326	    ErrorF("invalid frequency %1.3f Mhz\n",
4327		   ffreq*BASE_FREQ);
4328	    ffreq = ffreq_max / (1 << min_n2);
4329    }
4330
4331    /* work out suitable timings */
4332
4333    best_diff = ffreq;
4334
4335    for (n2=min_n2; n2<=max_n2; n2++) {
4336	for (n1=min_n1+2; n1<=max_n1+2; n1++) {
4337	    m = (int)(ffreq * n1 * (1 << n2) + 0.5);
4338	    if (m < min_m+2 || m > 127+2)
4339		continue;
4340	    div = (double)(m) / (double)(n1);
4341	    if ((div >= ffreq_min) &&
4342		(div <= ffreq_max)) {
4343		diff = ffreq - div / (1 << n2);
4344		if (diff < 0.0)
4345			diff = -diff;
4346		if (diff < best_diff) {
4347		    best_diff = diff;
4348		    best_m = m;
4349		    best_n1 = n1;
4350		    best_n2 = n2;
4351		}
4352	    }
4353	}
4354    }
4355
4356    *ndiv = best_n1 - 2;
4357    *r = best_n2;
4358    *mdiv = best_m - 2;
4359}
4360
4361
4362void SavageGEReset(ScrnInfoPtr pScrn, int from_timeout, int line, char *file)
4363{
4364    unsigned char cr66;
4365    int r, success = 0;
4366    CARD32 fifo_control = 0, miu_control = 0;
4367    CARD32 streams_timeout = 0, misc_timeout = 0;
4368    vgaHWPtr hwp = VGAHWPTR(pScrn);
4369    SavagePtr psav = SAVPTR(pScrn);
4370    int vgaCRIndex, vgaCRReg, vgaIOBase;
4371
4372    TRACE(("SavageGEReset(%d,%s)\n", line, file));
4373
4374    vgaIOBase = hwp->IOBase;
4375    vgaCRIndex = vgaIOBase + 4;
4376    vgaCRReg = vgaIOBase + 5;
4377
4378    if (from_timeout) {
4379	if (psav->GEResetCnt++ < 10 || xf86GetVerbosity() > 1)
4380	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4381		       "SavageGEReset called from %s line %d\n", file, line);
4382    } else
4383	psav->WaitIdleEmpty(psav);
4384
4385    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4386	fifo_control = INREG(FIFO_CONTROL_REG);
4387	miu_control = INREG(MIU_CONTROL_REG);
4388	streams_timeout = INREG(STREAMS_TIMEOUT_REG);
4389	misc_timeout = INREG(MISC_TIMEOUT_REG);
4390    }
4391
4392    VGAOUT8(vgaCRIndex, 0x66);
4393    cr66 = VGAIN8(vgaCRReg);
4394
4395    usleep(10000);
4396    for (r=1; r<10; r++) {
4397	VGAOUT8(vgaCRReg, cr66 | 0x02);
4398	usleep(10000);
4399	VGAOUT8(vgaCRReg, cr66 & ~0x02);
4400	usleep(10000);
4401
4402	if (!from_timeout)
4403	    psav->WaitIdleEmpty(psav);
4404	OUTREG(DEST_SRC_STR, psav->Bpl << 16 | psav->Bpl);
4405
4406	usleep(10000);
4407	switch(psav->Chipset) {
4408	    case S3_SAVAGE3D:
4409	    case S3_SAVAGE_MX:
4410	      success = (STATUS_WORD0 & 0x0008ffff) == 0x00080000;
4411	      break;
4412	    case S3_SAVAGE4:
4413	    case S3_PROSAVAGE:
4414	    case S3_PROSAVAGEDDR:
4415	    case S3_TWISTER:
4416	    case S3_SUPERSAVAGE:
4417	      success = (ALT_STATUS_WORD0 & 0x0081ffff) == 0x00800000;
4418	      break;
4419	    case S3_SAVAGE2000:
4420	      success = (ALT_STATUS_WORD0 & 0x008fffff) == 0;
4421	      break;
4422	}
4423	if(!success) {
4424	    usleep(10000);
4425	    xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4426		"restarting S3 graphics engine reset %2d ...\n", r);
4427	}
4428	else
4429	    break;
4430    }
4431
4432    /* At this point, the FIFO is empty and the engine is idle. */
4433
4434    if (from_timeout && !S3_SAVAGE_MOBILE_SERIES(psav->Chipset) ) {
4435	OUTREG(FIFO_CONTROL_REG, fifo_control);
4436	OUTREG(MIU_CONTROL_REG, miu_control);
4437	OUTREG(STREAMS_TIMEOUT_REG, streams_timeout);
4438	OUTREG(MISC_TIMEOUT_REG, misc_timeout);
4439    }
4440
4441    OUTREG(SRC_BASE, 0);
4442    OUTREG(DEST_BASE, 0);
4443    OUTREG(CLIP_L_R, ((0) << 16) | pScrn->displayWidth);
4444    OUTREG(CLIP_T_B, ((0) << 16) | psav->ScissB);
4445    OUTREG(MONO_PAT_0, ~0);
4446    OUTREG(MONO_PAT_1, ~0);
4447
4448    SavageSetGBD(pScrn);
4449
4450}
4451
4452
4453
4454/* This function is used to debug, it prints out the contents of s3 regs */
4455
4456void
4457SavagePrintRegs(ScrnInfoPtr pScrn)
4458{
4459    SavagePtr psav = SAVPTR(pScrn);
4460    unsigned char i;
4461    int vgaCRIndex = 0x3d4;
4462    int vgaCRReg = 0x3d5;
4463
4464    ErrorF( "SR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4465
4466    for( i = 0; i < 0x70; i++ ) {
4467	if( !(i % 16) )
4468	    ErrorF( "\nSR%xx ", i >> 4 );
4469	VGAOUT8( 0x3c4, i );
4470	ErrorF( " %02x", VGAIN8(0x3c5) );
4471    }
4472
4473    ErrorF( "\n\nCR    x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF" );
4474
4475    for( i = 0; i < 0xB7; i++ ) {
4476	if( !(i % 16) )
4477	    ErrorF( "\nCR%xx ", i >> 4 );
4478	VGAOUT8( vgaCRIndex, i );
4479	ErrorF( " %02x", VGAIN8(vgaCRReg) );
4480    }
4481
4482    ErrorF("\n\n");
4483}
4484
4485static void SavageDPMS(ScrnInfoPtr pScrn, int mode, int flags)
4486{
4487    SavagePtr psav = SAVPTR(pScrn);
4488    unsigned char sr8 = 0x00, srd = 0x00;
4489
4490    TRACE(("SavageDPMS(%d,%x)\n", mode, flags));
4491
4492    if (psav->DisplayType == MT_CRT) {
4493    	VGAOUT8(0x3c4, 0x08);
4494    	sr8 = VGAIN8(0x3c5);
4495    	sr8 |= 0x06;
4496    	VGAOUT8(0x3c5, sr8);
4497
4498    	VGAOUT8(0x3c4, 0x0d);
4499    	srd = VGAIN8(0x3c5);
4500
4501    	srd &= 0x03;
4502
4503    	switch (mode) {
4504	    case DPMSModeOn:
4505	    	break;
4506	    case DPMSModeStandby:
4507	    	srd |= 0x10;
4508	    	break;
4509	    case DPMSModeSuspend:
4510	    	srd |= 0x40;
4511	    	break;
4512	    case DPMSModeOff:
4513	    	srd |= 0x50;
4514	    	break;
4515	    default:
4516	    	xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4517	    	break;
4518    	}
4519
4520    	VGAOUT8(0x3c4, 0x0d);
4521    	VGAOUT8(0x3c5, srd);
4522    }
4523
4524    if (psav->DisplayType == MT_LCD || psav->DisplayType == MT_DFP) {
4525	if (S3_MOBILE_TWISTER_SERIES(psav->Chipset) && psav->UseBIOS) {
4526	    SavageSetPanelEnabled(psav, (mode == DPMSModeOn));
4527	} else {
4528    	    switch (mode) {
4529	        case DPMSModeOn:
4530		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4531		    VGAOUT8(0x3c5, VGAIN8(0x3c5) | 0x10);
4532	            break;
4533	        case DPMSModeStandby:
4534	        case DPMSModeSuspend:
4535	        case DPMSModeOff:
4536		    VGAOUT8(0x3c4, 0x31); /* SR31 bit 4 - FP enable */
4537		    VGAOUT8(0x3c5, VGAIN8(0x3c5) & ~0x10);
4538	            break;
4539	        default:
4540	            xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Invalid DPMS mode %d\n", mode);
4541	            break;
4542	    }
4543        }
4544    }
4545
4546    return;
4547}
4548
4549static void
4550SavageProbeDDC(ScrnInfoPtr pScrn, int index)
4551{
4552    vbeInfoPtr pVbe;
4553
4554    if (xf86LoadSubModule(pScrn, "vbe")) {
4555	pVbe = VBEInit(NULL, index);
4556	ConfiguredMonitor = vbeDoEDID(pVbe, NULL);
4557	vbeFree(pVbe);
4558    }
4559}
4560
4561static unsigned int
4562SavageDDC1Read(ScrnInfoPtr pScrn)
4563{
4564    register unsigned char tmp;
4565    SavagePtr psav = SAVPTR(pScrn);
4566
4567    UnLockExtRegs();
4568
4569    VerticalRetraceWait();
4570
4571    InI2CREG(tmp,psav->I2CPort);
4572
4573    return ((unsigned int) (tmp & 0x08));
4574}
4575
4576static Bool
4577SavageDDC1(ScrnInfoPtr pScrn)
4578{
4579    SavagePtr psav = SAVPTR(pScrn);
4580    unsigned char byte;
4581    xf86MonPtr pMon;
4582
4583    UnLockExtRegs();
4584
4585    /* initialize chipset */
4586    InI2CREG(byte,psav->I2CPort);
4587    OutI2CREG(byte | 0x12,psav->I2CPort);
4588
4589    pMon = xf86DoEDID_DDC1(XF86_SCRN_ARG(pScrn),vgaHWddc1SetSpeedWeak(),SavageDDC1Read);
4590    if (!pMon)
4591        return FALSE;
4592
4593    xf86PrintEDID(pMon);
4594
4595    if (!psav->IgnoreEDID)
4596        xf86SetDDCproperties(pScrn,pMon);
4597
4598    /* undo initialization */
4599    OutI2CREG(byte,psav->I2CPort);
4600
4601    return TRUE;
4602}
4603
4604static void
4605SavageGetTvMaxSize(SavagePtr psav)
4606{
4607    if( psav->PAL ) {
4608	psav->TVSizeX = 800;
4609	psav->TVSizeY = 600;
4610    }
4611    else {
4612	psav->TVSizeX = 640;
4613	psav->TVSizeY = 480;
4614    }
4615}
4616
4617
4618static Bool
4619SavagePanningCheck(ScrnInfoPtr pScrn, DisplayModePtr pMode)
4620{
4621    SavagePtr psav = SAVPTR(pScrn);
4622    psav->iResX = pMode->CrtcHDisplay;
4623    psav->iResY = pMode->CrtcVDisplay;
4624
4625    if ((psav->iResX < psav->PanelX || psav->iResY < psav->PanelY))
4626        psav->FPExpansion = TRUE;
4627    else
4628        psav->FPExpansion = FALSE;
4629
4630    if( psav->iResX < pScrn->virtualX || psav->iResY < pScrn->virtualY )
4631	return TRUE;
4632    else
4633	return FALSE;
4634}
4635
4636static void
4637SavageResetStreams(ScrnInfoPtr pScrn)
4638{
4639    SavagePtr psav = SAVPTR(pScrn);
4640    unsigned char cr67;
4641    unsigned char cr69;
4642
4643    /* disable streams */
4644    switch (psav->Chipset) {
4645        case S3_SAVAGE_MX:
4646        case S3_SUPERSAVAGE:
4647            OUTREG32(PRI_STREAM_STRIDE,0);
4648            OUTREG32(PRI_STREAM2_STRIDE, 0);
4649            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4650            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4651            OUTREG32(PRI_STREAM2_FBUF_ADDR0,0x00000000);
4652            OUTREG32(PRI_STREAM2_FBUF_ADDR1,0x00000000);
4653	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4654            cr67 = INREG8(CRT_DATA_REG);
4655	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4656	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4657	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4658            OUTREG8(CRT_DATA_REG, cr67);
4659            break;
4660	case S3_SAVAGE3D:
4661        case S3_SAVAGE4:
4662        case S3_TWISTER:
4663        case S3_PROSAVAGE:
4664        case S3_PROSAVAGEDDR:
4665            OUTREG32(PRI_STREAM_STRIDE,0);
4666            OUTREG32(PRI_STREAM_FBUF_ADDR0,0);
4667            OUTREG32(PRI_STREAM_FBUF_ADDR1,0);
4668	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4669            cr67 = INREG8(CRT_DATA_REG);
4670	    cr67 &= ~0x0c; /* CR67[2] = 1 : enable stream 1 */
4671            OUTREG8(CRT_DATA_REG, cr67);
4672	    OUTREG8(CRT_ADDRESS_REG, 0x69);
4673            cr69 = INREG8(CRT_DATA_REG);
4674	    cr69 &= ~0x80; /* CR69[0] = 1 : Mem-mapped regs */
4675            OUTREG8(CRT_DATA_REG, cr69);
4676            break;
4677        case S3_SAVAGE2000:
4678            OUTREG32(PRI_STREAM_STRIDE,0);
4679            OUTREG32(PRI_STREAM_FBUF_ADDR0,0x00000000);
4680            OUTREG32(PRI_STREAM_FBUF_ADDR1,0x00000000);
4681	    OUTREG8(CRT_ADDRESS_REG, 0x67);
4682            cr67 = INREG8(CRT_DATA_REG);
4683	    cr67 &= ~0x08; /* CR67[3] = 1 : Mem-mapped regs */
4684	    cr67 &= ~0x04; /* CR67[2] = 1 : enable stream 1 */
4685	    cr67 &= ~0x02; /* CR67[1] = 1 : enable stream 2 */
4686            OUTREG8(CRT_DATA_REG, cr67);
4687            break;
4688        default:
4689            break;
4690    }
4691
4692}
4693